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 testReaggregationWhenBecomesInvisible() { 609 Account account = new Account("accountName", "accountType"); 610 createAutoAddGroup(account); 611 612 long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); 613 DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); 614 615 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 616 DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder"); 617 618 long rawContactId3 = RawContactUtil.createRawContact(mResolver, account); 619 DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); 620 621 assertNotAggregated(rawContactId1, rawContactId3); 622 assertNotAggregated(rawContactId2, rawContactId3); 623 assertNotAggregated(rawContactId1, rawContactId2); 624 625 // Hide by removing from all groups 626 removeGroupMemberships(rawContactId3); 627 628 assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder"); 629 assertNotAggregated(rawContactId1, rawContactId3); 630 assertNotAggregated(rawContactId2, rawContactId3); 631 } 632 633 public void testReaggregationWhenBecomesInvisibleSecondaryDataMatch() { 634 Account account = new Account("accountName", "accountType"); 635 createAutoAddGroup(account); 636 637 long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); 638 DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); 639 insertPhoneNumber(rawContactId1, "1234567890"); 640 641 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 642 insertPhoneNumber(rawContactId2, "1234567890"); 643 644 long rawContactId3 = RawContactUtil.createRawContact(mResolver, account); 645 DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); 646 647 assertNotAggregated(rawContactId1, rawContactId3); 648 assertNotAggregated(rawContactId2, rawContactId3); 649 assertNotAggregated(rawContactId1, rawContactId2); 650 651 // Hide by removing from all groups 652 removeGroupMemberships(rawContactId3); 653 654 assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder"); 655 assertNotAggregated(rawContactId1, rawContactId3); 656 assertNotAggregated(rawContactId2, rawContactId3); 657 } 658 659 public void testReaggregationWhenBecomesVisible() { 660 Account account = new Account("accountName", "accountType"); 661 long groupId = createAutoAddGroup(account); 662 663 long rawContactId1 = RawContactUtil.createRawContact(mResolver, account); 664 DataUtil.insertStructuredName(mResolver, rawContactId1, "Flynn", "Ryder"); 665 666 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 667 DataUtil.insertStructuredName(mResolver, rawContactId2, "Flynn", "Ryder"); 668 669 long rawContactId3 = RawContactUtil.createRawContact(mResolver, account); 670 removeGroupMemberships(rawContactId3); 671 DataUtil.insertStructuredName(mResolver, rawContactId3, "Flynn", "Ryder"); 672 673 assertAggregated(rawContactId1, rawContactId2, "Flynn Ryder"); 674 assertNotAggregated(rawContactId1, rawContactId3); 675 assertNotAggregated(rawContactId2, rawContactId3); 676 677 insertGroupMembership(rawContactId3, groupId); 678 679 assertNotAggregated(rawContactId1, rawContactId3); 680 assertNotAggregated(rawContactId2, rawContactId3); 681 assertNotAggregated(rawContactId1, rawContactId2); 682 } 683 684 public void testNonSplitBecauseOfMultipleAffinitiesWhenOverridden() { 685 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 686 ACCOUNT_1); 687 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 688 ACCOUNT_2); 689 long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 690 ACCOUNT_3); 691 assertAggregated(rawContactId1, rawContactId2); 692 assertAggregated(rawContactId1, rawContactId3); 693 setAggregationException( 694 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 695 assertAggregated(rawContactId1, rawContactId2); 696 assertAggregated(rawContactId1, rawContactId3); 697 698 // The aggregate this raw contact could join has a raw contact from the same account, 699 // let's not aggregate and break up the existing aggregate because of the ambiguity 700 long rawContactId4 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 701 ACCOUNT_1); 702 assertAggregated(rawContactId1, rawContactId2); // Aggregation exception 703 assertNotAggregated(rawContactId1, rawContactId3); 704 assertNotAggregated(rawContactId1, rawContactId4); 705 assertNotAggregated(rawContactId3, rawContactId4); 706 } 707 708 public void testNonAggregationFromSameAccount() { 709 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 710 ACCOUNT_1); 711 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 712 ACCOUNT_1); 713 assertNotAggregated(rawContactId1, rawContactId2); 714 } 715 716 public void testNonAggregationFromSameAccountNoCommonData() { 717 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 718 ACCOUNT_1); 719 insertEmail(rawContactId1, "lightning1 (at) android.com"); 720 insertPhoneNumber(rawContactId1, "111-222-3333"); 721 insertIdentity(rawContactId1, "iden1", "namespace"); 722 723 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 724 ACCOUNT_1); 725 insertEmail(rawContactId2, "lightning2 (at) android.com"); 726 insertPhoneNumber(rawContactId2, "555-666-7777"); 727 insertIdentity(rawContactId1, "iden2", "namespace"); 728 729 assertNotAggregated(rawContactId1, rawContactId2); 730 } 731 732 public void testAggregationFromSameAccountEmailSame() { 733 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 734 ACCOUNT_1); 735 insertEmail(rawContactId1, "lightning (at) android.com"); 736 737 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 738 ACCOUNT_1); 739 insertEmail(rawContactId2, "lightning (at) android.com"); 740 741 assertAggregated(rawContactId1, rawContactId2); 742 } 743 744 public void testNonAggregationFromSameAccountEmailDifferent() { 745 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 746 ACCOUNT_1); 747 insertEmail(rawContactId1, "lightning1 (at) android.com"); 748 749 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 750 ACCOUNT_1); 751 insertEmail(rawContactId2, "lightning2 (at) android.com"); 752 insertEmail(rawContactId2, "lightning3 (at) android.com"); 753 754 assertNotAggregated(rawContactId1, rawContactId2); 755 } 756 757 public void testAggregationFromSameAccountIdentitySame() { 758 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 759 ACCOUNT_1); 760 insertIdentity(rawContactId1, "iden", "namespace"); 761 762 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 763 ACCOUNT_1); 764 insertIdentity(rawContactId2, "iden", "namespace"); 765 766 assertAggregated(rawContactId1, rawContactId2); 767 } 768 769 public void testNonAggregationFromSameAccountIdentityDifferent() { 770 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 771 ACCOUNT_1); 772 insertIdentity(rawContactId1, "iden1", "namespace1"); 773 insertIdentity(rawContactId1, "iden2", "namespace2"); 774 775 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 776 ACCOUNT_1); 777 insertIdentity(rawContactId2, "iden2", "namespace1"); 778 insertIdentity(rawContactId2, "iden1", "namespace2"); 779 780 assertNotAggregated(rawContactId1, rawContactId2); 781 } 782 783 public void testAggregationFromSameAccountPhoneNumberSame() { 784 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 785 ACCOUNT_1); 786 insertPhoneNumber(rawContactId1, "111-222-3333"); 787 788 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 789 ACCOUNT_1); 790 insertPhoneNumber(rawContactId2, "111-222-3333"); 791 792 assertAggregated(rawContactId1, rawContactId2); 793 } 794 795 public void testAggregationFromSameAccountPhoneNumberNormalizedSame() { 796 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 797 ACCOUNT_1); 798 insertPhoneNumber(rawContactId1, "111-222-3333"); 799 800 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 801 ACCOUNT_1); 802 insertPhoneNumber(rawContactId2, "+1-111-222-3333"); 803 804 assertAggregated(rawContactId1, rawContactId2); 805 } 806 807 public void testNonAggregationFromSameAccountPhoneNumberDifferent() { 808 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 809 ACCOUNT_1); 810 insertPhoneNumber(rawContactId1, "111-222-3333"); 811 812 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe", 813 ACCOUNT_1); 814 insertPhoneNumber(rawContactId2, "111-222-3334"); 815 816 assertNotAggregated(rawContactId1, rawContactId2); 817 } 818 819 public void testAggregationSuggestionsBasedOnName() { 820 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 821 DataUtil.insertStructuredName(mResolver, rawContactId1, "Duane", null); 822 823 // Exact name match 824 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 825 DataUtil.insertStructuredName(mResolver, rawContactId2, "Duane", null); 826 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 827 rawContactId1, rawContactId2); 828 829 // Edit distance == 0.84 830 long rawContactId3 = RawContactUtil.createRawContact(mResolver); 831 DataUtil.insertStructuredName(mResolver, rawContactId3, "Dwayne", null); 832 833 // Edit distance == 0.6 834 long rawContactId4 = RawContactUtil.createRawContact(mResolver); 835 DataUtil.insertStructuredName(mResolver, rawContactId4, "Donny", null); 836 837 long contactId1 = queryContactId(rawContactId1); 838 long contactId2 = queryContactId(rawContactId2); 839 long contactId3 = queryContactId(rawContactId3); 840 841 assertSuggestions(contactId1, contactId2, contactId3); 842 } 843 844 public void testAggregationSuggestionsBasedOnPhoneNumber() { 845 846 // Create two contacts that would not be aggregated because of name mismatch 847 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 848 DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad"); 849 insertPhoneNumber(rawContactId1, "(888)555-1236"); 850 851 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 852 DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey"); 853 insertPhoneNumber(rawContactId2, "1(888)555-1236"); 854 855 long contactId1 = queryContactId(rawContactId1); 856 long contactId2 = queryContactId(rawContactId2); 857 assertTrue(contactId1 != contactId2); 858 859 assertSuggestions(contactId1, contactId2); 860 } 861 862 public void testAggregationSuggestionsBasedOnEmailAddress() { 863 864 // Create two contacts that would not be aggregated because of name mismatch 865 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 866 DataUtil.insertStructuredName(mResolver, rawContactId1, "Carl", "Fredricksen"); 867 insertEmail(rawContactId1, "up (at) android.com"); 868 869 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 870 DataUtil.insertStructuredName(mResolver, rawContactId2, "Charles", "Muntz"); 871 insertEmail(rawContactId2, "up (at) android.com"); 872 873 long contactId1 = queryContactId(rawContactId1); 874 long contactId2 = queryContactId(rawContactId2); 875 assertTrue(contactId1 != contactId2); 876 877 assertSuggestions(contactId1, contactId2); 878 } 879 880 public void testAggregationSuggestionsBasedOnEmailAddressApproximateMatch() { 881 882 // Create two contacts that would not be aggregated because of name mismatch 883 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 884 DataUtil.insertStructuredName(mResolver, rawContactId1, "Bob", null); 885 insertEmail(rawContactId1, "incredible (at) android.com"); 886 887 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 888 DataUtil.insertStructuredName(mResolver, rawContactId2, "Lucius", "Best"); 889 insertEmail(rawContactId2, "incrediball (at) android.com"); 890 891 long contactId1 = queryContactId(rawContactId1); 892 long contactId2 = queryContactId(rawContactId2); 893 assertTrue(contactId1 != contactId2); 894 895 assertSuggestions(contactId1, contactId2); 896 } 897 898 public void testAggregationSuggestionsBasedOnNickname() { 899 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 900 DataUtil.insertStructuredName(mResolver, rawContactId1, "Peter", "Parker"); 901 insertNickname(rawContactId1, "Spider-Man"); 902 903 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 904 DataUtil.insertStructuredName(mResolver, rawContactId2, "Manny", "Spider"); 905 906 long contactId1 = queryContactId(rawContactId1); 907 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 908 rawContactId1, rawContactId2); 909 910 long contactId2 = queryContactId(rawContactId2); 911 assertSuggestions(contactId1, contactId2); 912 } 913 914 public void testAggregationSuggestionsBasedOnNicknameMatchingName() { 915 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 916 DataUtil.insertStructuredName(mResolver, rawContactId1, "Clark", "Kent"); 917 insertNickname(rawContactId1, "Superman"); 918 919 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 920 DataUtil.insertStructuredName(mResolver, rawContactId2, "Roy", "Williams"); 921 insertNickname(rawContactId2, "superman"); 922 923 long contactId1 = queryContactId(rawContactId1); 924 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 925 rawContactId1, rawContactId2); 926 927 long contactId2 = queryContactId(rawContactId2); 928 assertSuggestions(contactId1, contactId2); 929 } 930 931 public void testAggregationSuggestionsBasedOnCommonNickname() { 932 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 933 DataUtil.insertStructuredName(mResolver, rawContactId1, "Dick", "Cherry"); 934 935 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 936 DataUtil.insertStructuredName(mResolver, rawContactId2, "Richard", "Cherry"); 937 938 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 939 rawContactId1, rawContactId2); 940 941 long contactId1 = queryContactId(rawContactId1); 942 long contactId2 = queryContactId(rawContactId2); 943 assertSuggestions(contactId1, contactId2); 944 } 945 946 public void testAggregationSuggestionsBasedOnPhoneNumberWithFilter() { 947 948 // Create two contacts that would not be aggregated because of name mismatch 949 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 950 DataUtil.insertStructuredName(mResolver, rawContactId1, "Lord", "Farquaad"); 951 insertPhoneNumber(rawContactId1, "(888)555-1236"); 952 953 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 954 DataUtil.insertStructuredName(mResolver, rawContactId2, "Talking", "Donkey"); 955 insertPhoneNumber(rawContactId2, "1(888)555-1236"); 956 957 long contactId1 = queryContactId(rawContactId1); 958 long contactId2 = queryContactId(rawContactId2); 959 assertTrue(contactId1 != contactId2); 960 961 assertSuggestions(contactId1, "talk", contactId2); 962 assertSuggestions(contactId1, "don", contactId2); 963 assertSuggestions(contactId1, "", contactId2); 964 assertSuggestions(contactId1, "eddie"); 965 } 966 967 public void testAggregationSuggestionsDontSuggestInvisible() { 968 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first", "last", 969 ACCOUNT_1); 970 insertPhoneNumber(rawContactId1, "111-222-3333"); 971 insertNickname(rawContactId1, "Superman"); 972 insertEmail(rawContactId1, "incredible (at) android.com"); 973 974 // Create another with the exact same name, phone number, nickname and email. 975 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first", "last", 976 ACCOUNT_2); 977 insertPhoneNumber(rawContactId2, "111-222-3333"); 978 insertNickname(rawContactId2, "Superman"); 979 insertEmail(rawContactId2, "incredible (at) android.com"); 980 981 // The aggregator should have joined them. Split them up. 982 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 983 rawContactId1, rawContactId2); 984 985 long contactId1 = queryContactId(rawContactId1); 986 long contactId2 = queryContactId(rawContactId2); 987 988 // Make sure they're different contacts. 989 MoreAsserts.assertNotEqual(contactId1, contactId2); 990 991 // Contact 2 should be suggested. 992 assertSuggestions(contactId1, contactId2); 993 994 // Make contact 2 invisible. 995 markInvisible(contactId2); 996 997 // Now contact 2 shuldn't be suggested. 998 assertSuggestions(contactId1, new long[0]); 999 } 1000 1001 public void testChoosePhotoSetBeforeAggregation() { 1002 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1003 setContactAccount(rawContactId1, "donut", "donut_act"); 1004 insertPhoto(rawContactId1); 1005 1006 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1007 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1008 long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2)); 1009 1010 long rawContactId3 = RawContactUtil.createRawContact(mResolver); 1011 setContactAccount(rawContactId3, "froyo", "froyo_act"); 1012 insertPhoto(rawContactId3); 1013 1014 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1015 rawContactId1, rawContactId2); 1016 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1017 rawContactId1, rawContactId3); 1018 assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2))); 1019 } 1020 1021 public void testChoosePhotoSetAfterAggregation() { 1022 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1023 setContactAccount(rawContactId1, "donut", "donut_act"); 1024 insertPhoto(rawContactId1); 1025 1026 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1027 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1028 rawContactId1, rawContactId2); 1029 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1030 long cupcakeId = ContentUris.parseId(insertPhoto(rawContactId2)); 1031 1032 long rawContactId3 = RawContactUtil.createRawContact(mResolver); 1033 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1034 rawContactId1, rawContactId3); 1035 setContactAccount(rawContactId3, "froyo", "froyo_act"); 1036 insertPhoto(rawContactId3); 1037 1038 assertEquals(cupcakeId, queryPhotoId(queryContactId(rawContactId2))); 1039 } 1040 1041 // Note that for the following tests of photo aggregation, the accounts are being used to 1042 // set the typical photo priority that each raw contact would have, based on 1043 // SynchronousContactsProvider2.createPhotoPriorityResolver. The relative priorities 1044 // specified there are: 1045 // cupcake: 3 1046 // donut: 2 1047 // froyo: 1 1048 // <other>: 0 1049 1050 public void testChooseLargerPhotoByDimensions() { 1051 // Donut photo is 256x256. 1052 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1053 setContactAccount(rawContactId1, "donut", "donut_act"); 1054 long normalEarthDataId = ContentUris.parseId( 1055 insertPhoto(rawContactId1, R.drawable.earth_normal)); 1056 long normalEarthPhotoFileId = getStoredLongValue( 1057 ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId), 1058 Photo.PHOTO_FILE_ID); 1059 1060 // Cupcake would normally have priority, but its photo is 200x200. 1061 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1062 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1063 insertPhoto(rawContactId2, R.drawable.earth_200); 1064 1065 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1066 rawContactId1, rawContactId2); 1067 1068 // Larger photo (by dimensions) wins. 1069 assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1070 } 1071 1072 public void testChooseLargerPhotoByFileSize() { 1073 // Donut photo is a 256x256 photo of a nebula. 1074 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1075 setContactAccount(rawContactId1, "donut", "donut_act"); 1076 long nebulaDataId = ContentUris.parseId( 1077 insertPhoto(rawContactId1, R.drawable.nebula)); 1078 long nebulaPhotoFileId = getStoredLongValue( 1079 ContentUris.withAppendedId(Data.CONTENT_URI, nebulaDataId), 1080 Photo.PHOTO_FILE_ID); 1081 1082 // Cupcake would normally have priority, but its photo (of a galaxy) has the same dimensions 1083 // as Donut's, but a smaller filesize. 1084 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1085 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1086 insertPhoto(rawContactId2, R.drawable.galaxy); 1087 1088 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1089 rawContactId1, rawContactId2); 1090 1091 // Larger photo (by filesize) wins. 1092 assertEquals(nebulaPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1093 } 1094 1095 public void testChooseFilePhotoOverThumbnail() { 1096 // Donut photo is a 256x256 photo of Earth. 1097 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1098 setContactAccount(rawContactId1, "donut", "donut_act"); 1099 long normalEarthDataId = ContentUris.parseId( 1100 insertPhoto(rawContactId1, R.drawable.earth_normal)); 1101 long normalEarthPhotoFileId = getStoredLongValue( 1102 ContentUris.withAppendedId(Data.CONTENT_URI, normalEarthDataId), 1103 Photo.PHOTO_FILE_ID); 1104 1105 // Cupcake would normally have priority, but its photo of Earth is thumbnail-sized. 1106 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1107 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1108 insertPhoto(rawContactId2, R.drawable.earth_small); 1109 1110 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1111 rawContactId1, rawContactId2); 1112 1113 // Larger photo (by filesize) wins. 1114 assertEquals(normalEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1115 } 1116 1117 public void testFallbackToAccountPriorityForSamePhoto() { 1118 // Donut photo is a 256x256 photo of Earth. 1119 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1120 setContactAccount(rawContactId1, "donut", "donut_act"); 1121 insertPhoto(rawContactId1, R.drawable.earth_normal); 1122 1123 // Cupcake has the same 256x256 photo of Earth. 1124 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1125 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1126 long cupcakeEarthDataId = ContentUris.parseId( 1127 insertPhoto(rawContactId2, R.drawable.earth_normal)); 1128 long cupcakeEarthPhotoFileId = getStoredLongValue( 1129 ContentUris.withAppendedId(Data.CONTENT_URI, cupcakeEarthDataId), 1130 Photo.PHOTO_FILE_ID); 1131 1132 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1133 rawContactId1, rawContactId2); 1134 1135 // Cupcake's version of the photo wins, falling back to account priority. 1136 assertEquals(cupcakeEarthPhotoFileId, queryPhotoFileId(queryContactId(rawContactId1))); 1137 } 1138 1139 public void testFallbackToAccountPriorityForDifferingThumbnails() { 1140 // Donut photo is a 96x96 thumbnail of Earth. 1141 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1142 setContactAccount(rawContactId1, "donut", "donut_act"); 1143 insertPhoto(rawContactId1, R.drawable.earth_small); 1144 1145 // Cupcake photo is the 96x96 "no contact" placeholder (smaller filesize than the Earth 1146 // picture, but thumbnail filesizes are ignored in the aggregator). 1147 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1148 setContactAccount(rawContactId2, "cupcake", "cupcake_act"); 1149 long cupcakeDataId = ContentUris.parseId( 1150 insertPhoto(rawContactId2, R.drawable.ic_contact_picture)); 1151 1152 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1153 rawContactId1, rawContactId2); 1154 1155 // The Cupcake thumbnail wins, by account priority.. 1156 assertEquals(cupcakeDataId, queryPhotoId(queryContactId(rawContactId1))); 1157 } 1158 1159 public void testDisplayNameSources() { 1160 long rawContactId = RawContactUtil.createRawContact(mResolver); 1161 long contactId = queryContactId(rawContactId); 1162 1163 assertNull(queryDisplayName(contactId)); 1164 1165 insertEmail(rawContactId, "eclair (at) android.com"); 1166 assertEquals("eclair (at) android.com", queryDisplayName(contactId)); 1167 1168 insertPhoneNumber(rawContactId, "800-555-5555"); 1169 assertEquals("800-555-5555", queryDisplayName(contactId)); 1170 1171 ContentValues values = new ContentValues(); 1172 values.put(Organization.COMPANY, "Android"); 1173 insertOrganization(rawContactId, values); 1174 assertEquals("Android", queryDisplayName(contactId)); 1175 1176 insertNickname(rawContactId, "Dro"); 1177 assertEquals("Dro", queryDisplayName(contactId)); 1178 1179 values.clear(); 1180 values.put(StructuredName.GIVEN_NAME, "Eclair"); 1181 values.put(StructuredName.FAMILY_NAME, "Android"); 1182 DataUtil.insertStructuredName(mResolver, rawContactId, values); 1183 assertEquals("Eclair Android", queryDisplayName(contactId)); 1184 } 1185 1186 public void testVerifiedName() { 1187 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "test1", "TEST1", 1188 ACCOUNT_1); 1189 storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, "1"); 1190 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "test2", "TEST2", 1191 ACCOUNT_2); 1192 long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "test3", 1193 "TEST3 LONG", ACCOUNT_3); 1194 1195 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, 1196 rawContactId2); 1197 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, 1198 rawContactId3); 1199 1200 long contactId = queryContactId(rawContactId1); 1201 1202 // Should be the verified name 1203 assertEquals("test1 TEST1", queryDisplayName(contactId)); 1204 1205 // Mark a different name as verified - this should reset the NAME_VERIFIED field 1206 // for the other rawContacts 1207 storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "1"); 1208 assertStoredValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.NAME_VERIFIED, 0); 1209 assertEquals("test2 TEST2", queryDisplayName(contactId)); 1210 1211 // Reset the NAME_VERIFIED flag - now the most complex of the three names should win 1212 storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.NAME_VERIFIED, "0"); 1213 assertEquals("test3 TEST3 LONG", queryDisplayName(contactId)); 1214 } 1215 1216 public void testAggregationModeSuspendedSeparateTransactions() { 1217 1218 // Setting aggregation mode to SUSPENDED should prevent aggregation from happening 1219 long rawContactId1 = RawContactUtil.createRawContact(mResolver, ACCOUNT_1); 1220 storeValue(RawContacts.CONTENT_URI, rawContactId1, 1221 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); 1222 Uri name1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "THE", "SAME"); 1223 1224 long rawContactId2 = RawContactUtil.createRawContact(mResolver, ACCOUNT_2); 1225 storeValue(RawContacts.CONTENT_URI, rawContactId2, 1226 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED); 1227 DataUtil.insertStructuredName(mResolver, rawContactId2, "THE", "SAME"); 1228 1229 assertNotAggregated(rawContactId1, rawContactId2); 1230 1231 // Changing aggregation mode to DEFAULT should change nothing 1232 storeValue(RawContacts.CONTENT_URI, rawContactId1, 1233 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); 1234 storeValue(RawContacts.CONTENT_URI, rawContactId2, 1235 RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT); 1236 assertNotAggregated(rawContactId1, rawContactId2); 1237 1238 // Changing the name should trigger aggregation 1239 storeValue(name1, StructuredName.GIVEN_NAME, "the"); 1240 assertAggregated(rawContactId1, rawContactId2); 1241 } 1242 1243 public void testAggregationModeInitializedAsSuspended() throws Exception { 1244 1245 // Setting aggregation mode to SUSPENDED should prevent aggregation from happening 1246 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1247 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1248 .build(); 1249 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1250 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1251 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1252 .withValue(StructuredName.GIVEN_NAME, "John") 1253 .withValue(StructuredName.FAMILY_NAME, "Doe") 1254 .build(); 1255 ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1256 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1257 .build(); 1258 ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1259 .withValueBackReference(Data.RAW_CONTACT_ID, 2) 1260 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1261 .withValue(StructuredName.GIVEN_NAME, "John") 1262 .withValue(StructuredName.FAMILY_NAME, "Doe") 1263 .build(); 1264 ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1265 .withSelection(RawContacts._ID + "=?", new String[1]) 1266 .withSelectionBackReference(0, 0) 1267 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT) 1268 .build(); 1269 ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1270 .withSelection(RawContacts._ID + "=?", new String[1]) 1271 .withSelectionBackReference(0, 2) 1272 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DEFAULT) 1273 .build(); 1274 1275 ContentProviderResult[] results = 1276 mResolver.applyBatch(ContactsContract.AUTHORITY, 1277 Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6)); 1278 1279 long rawContactId1 = ContentUris.parseId(results[0].uri); 1280 long rawContactId2 = ContentUris.parseId(results[2].uri); 1281 1282 assertNotAggregated(rawContactId1, rawContactId2); 1283 } 1284 1285 public void testAggregationModeUpdatedToSuspended() throws Exception { 1286 1287 // Setting aggregation mode to SUSPENDED should prevent aggregation from happening 1288 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1289 .withValues(new ContentValues()) 1290 .build(); 1291 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1292 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1293 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1294 .withValue(StructuredName.GIVEN_NAME, "John") 1295 .withValue(StructuredName.FAMILY_NAME, "Doe") 1296 .build(); 1297 ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1298 .withValues(new ContentValues()) 1299 .build(); 1300 ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1301 .withValueBackReference(Data.RAW_CONTACT_ID, 2) 1302 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1303 .withValue(StructuredName.GIVEN_NAME, "John") 1304 .withValue(StructuredName.FAMILY_NAME, "Doe") 1305 .build(); 1306 ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1307 .withSelection(RawContacts._ID + "=?", new String[1]) 1308 .withSelectionBackReference(0, 0) 1309 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1310 .build(); 1311 ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1312 .withSelection(RawContacts._ID + "=?", new String[1]) 1313 .withSelectionBackReference(0, 2) 1314 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1315 .build(); 1316 1317 ContentProviderResult[] results = 1318 mResolver.applyBatch(ContactsContract.AUTHORITY, 1319 Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6)); 1320 1321 long rawContactId1 = ContentUris.parseId(results[0].uri); 1322 long rawContactId2 = ContentUris.parseId(results[2].uri); 1323 1324 assertNotAggregated(rawContactId1, rawContactId2); 1325 } 1326 1327 public void testAggregationModeSuspendedOverriddenByAggException() throws Exception { 1328 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1329 .withValue(RawContacts.ACCOUNT_NAME, "a") 1330 .withValue(RawContacts.ACCOUNT_TYPE, "b") 1331 .build(); 1332 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1333 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1334 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1335 .withValue(StructuredName.GIVEN_NAME, "John") 1336 .withValue(StructuredName.FAMILY_NAME, "Doe") 1337 .build(); 1338 ContentProviderOperation cpo3 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1339 .withValue(RawContacts.ACCOUNT_NAME, "c") 1340 .withValue(RawContacts.ACCOUNT_TYPE, "d") 1341 .build(); 1342 ContentProviderOperation cpo4 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1343 .withValueBackReference(Data.RAW_CONTACT_ID, 2) 1344 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1345 .withValue(StructuredName.GIVEN_NAME, "John") 1346 .withValue(StructuredName.FAMILY_NAME, "Doe") 1347 .build(); 1348 ContentProviderOperation cpo5 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1349 .withSelection(RawContacts._ID + "=?", new String[1]) 1350 .withSelectionBackReference(0, 0) 1351 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1352 .build(); 1353 ContentProviderOperation cpo6 = ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI) 1354 .withSelection(RawContacts._ID + "=?", new String[1]) 1355 .withSelectionBackReference(0, 2) 1356 .withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED) 1357 .build(); 1358 1359 // Checking that aggregation mode SUSPENDED should be overridden by inserting 1360 // an explicit aggregation exception 1361 ContentProviderOperation cpo7 = 1362 ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI) 1363 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, 0) 1364 .withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, 2) 1365 .withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER) 1366 .build(); 1367 1368 ContentProviderResult[] results = 1369 mResolver.applyBatch(ContactsContract.AUTHORITY, 1370 Lists.newArrayList(cpo1, cpo2, cpo3, cpo4, cpo5, cpo6, cpo7)); 1371 1372 long rawContactId1 = ContentUris.parseId(results[0].uri); 1373 long rawContactId2 = ContentUris.parseId(results[2].uri); 1374 1375 assertAggregated(rawContactId1, rawContactId2); 1376 } 1377 1378 public void testAggregationSuggestionsQueryBuilderWithContactId() throws Exception { 1379 Uri uri = AggregationSuggestions.builder().setContactId(12).setLimit(7).build(); 1380 assertEquals("content://com.android.contacts/contacts/12/suggestions?limit=7", 1381 uri.toString()); 1382 } 1383 1384 public void testAggregationSuggestionsQueryBuilderWithValues() throws Exception { 1385 Uri uri = AggregationSuggestions.builder() 1386 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name1") 1387 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "name2") 1388 .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email1") 1389 .addParameter(AggregationSuggestions.PARAMETER_MATCH_EMAIL, "email2") 1390 .addParameter(AggregationSuggestions.PARAMETER_MATCH_PHONE, "phone1") 1391 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NICKNAME, "nickname1") 1392 .setLimit(7) 1393 .build(); 1394 assertEquals("content://com.android.contacts/contacts/0/suggestions?" 1395 + "limit=7" 1396 + "&query=name%3Aname1" 1397 + "&query=name%3Aname2" 1398 + "&query=email%3Aemail1" 1399 + "&query=email%3Aemail2" 1400 + "&query=phone%3Aphone1" 1401 + "&query=nickname%3Anickname1", uri.toString()); 1402 } 1403 1404 public void testAggregatedStatusUpdate() { 1405 long rawContactId1 = RawContactUtil.createRawContact(mResolver); 1406 Uri dataUri1 = DataUtil.insertStructuredName(mResolver, rawContactId1, "john", "doe"); 1407 insertStatusUpdate(ContentUris.parseId(dataUri1), StatusUpdates.AWAY, "Green", 100, 1408 StatusUpdates.CAPABILITY_HAS_CAMERA); 1409 long rawContactId2 = RawContactUtil.createRawContact(mResolver); 1410 Uri dataUri2 = DataUtil.insertStructuredName(mResolver, rawContactId2, "john", "doe"); 1411 insertStatusUpdate(ContentUris.parseId(dataUri2), StatusUpdates.AVAILABLE, "Red", 50, 1412 StatusUpdates.CAPABILITY_HAS_CAMERA); 1413 setAggregationException( 1414 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 1415 1416 assertStoredValue(getContactUriForRawContact(rawContactId1), 1417 Contacts.CONTACT_STATUS, "Green"); 1418 1419 // When we split these two raw contacts, their respective statuses should be restored 1420 setAggregationException( 1421 AggregationExceptions.TYPE_KEEP_SEPARATE, rawContactId1, rawContactId2); 1422 1423 assertStoredValue(getContactUriForRawContact(rawContactId1), 1424 Contacts.CONTACT_STATUS, "Green"); 1425 1426 assertStoredValue(getContactUriForRawContact(rawContactId2), 1427 Contacts.CONTACT_STATUS, "Red"); 1428 } 1429 1430 public void testAggregationSuggestionsByName() throws Exception { 1431 long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "first1", "last1"); 1432 long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "first2", "last2"); 1433 1434 Uri uri = AggregationSuggestions.builder() 1435 .addParameter(AggregationSuggestions.PARAMETER_MATCH_NAME, "last1 first1") 1436 .build(); 1437 1438 Cursor cursor = mResolver.query( 1439 uri, new String[] { Contacts._ID, Contacts.DISPLAY_NAME }, null, null, null); 1440 1441 assertEquals(1, cursor.getCount()); 1442 1443 cursor.moveToFirst(); 1444 1445 ContentValues values = new ContentValues(); 1446 values.put(Contacts._ID, queryContactId(rawContactId1)); 1447 values.put(Contacts.DISPLAY_NAME, "first1 last1"); 1448 assertCursorValues(cursor, values); 1449 cursor.close(); 1450 } 1451 1452 private void assertSuggestions(long contactId, long... suggestions) { 1453 final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1454 Uri uri = Uri.withAppendedPath(aggregateUri, 1455 Contacts.AggregationSuggestions.CONTENT_DIRECTORY); 1456 assertSuggestions(uri, suggestions); 1457 } 1458 1459 private void assertSuggestions(long contactId, String filter, long... suggestions) { 1460 final Uri aggregateUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1461 Uri uri = Uri.withAppendedPath(Uri.withAppendedPath(aggregateUri, 1462 Contacts.AggregationSuggestions.CONTENT_DIRECTORY), Uri.encode(filter)); 1463 assertSuggestions(uri, suggestions); 1464 } 1465 1466 private void assertSuggestions(Uri uri, long... suggestions) { 1467 final Cursor cursor = mResolver.query(uri, 1468 new String[] { Contacts._ID, Contacts.CONTACT_PRESENCE }, 1469 null, null, null); 1470 1471 try { 1472 assertEquals(suggestions.length, cursor.getCount()); 1473 1474 for (int i = 0; i < suggestions.length; i++) { 1475 cursor.moveToNext(); 1476 assertEquals(suggestions[i], cursor.getLong(0)); 1477 } 1478 } finally { 1479 TestUtils.dumpCursor(cursor); 1480 } 1481 1482 cursor.close(); 1483 } 1484 1485 private void assertDisplayNameEquals(long contactId, long rawContactId) { 1486 1487 String contactDisplayName = queryDisplayName(contactId); 1488 1489 Cursor c = queryRawContact(rawContactId); 1490 assertTrue(c.moveToFirst()); 1491 String rawDisplayName = c.getString(c.getColumnIndex(RawContacts.DISPLAY_NAME_PRIMARY)); 1492 c.close(); 1493 1494 assertTrue(contactDisplayName != null); 1495 assertTrue(rawDisplayName != null); 1496 assertEquals(rawDisplayName, contactDisplayName); 1497 } 1498 } 1499