1 /* 2 * Copyright (C) 2010 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; 18 19 import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY; 20 21 import android.accounts.Account; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.content.pm.PackageInfo; 25 import android.content.pm.PackageManager; 26 import android.content.pm.PackageManager.NameNotFoundException; 27 import android.content.pm.ProviderInfo; 28 import android.database.Cursor; 29 import android.database.MatrixCursor; 30 import android.net.Uri; 31 import android.os.Bundle; 32 import android.provider.ContactsContract; 33 import android.provider.ContactsContract.AggregationExceptions; 34 import android.provider.ContactsContract.Contacts; 35 import android.provider.ContactsContract.Directory; 36 import android.provider.ContactsContract.RawContacts; 37 import android.test.mock.MockContentProvider; 38 import android.test.suitebuilder.annotation.MediumTest; 39 import android.util.Log; 40 41 import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 42 43 import com.google.android.collect.Lists; 44 45 /** 46 * Unit tests for {@link ContactDirectoryManager}. Run the test like this: 47 * 48 adb shell am instrument -e class com.android.providers.contacts.ContactDirectoryManagerTest \ 49 -w com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 50 * 51 */ 52 @MediumTest 53 public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { 54 private static final String TAG = "ContactDirectoryManagerTest"; 55 56 private ContactsMockPackageManager mPackageManager; 57 58 private ContactsProvider2 mProvider; 59 60 private ContactDirectoryManager mDirectoryManager; 61 62 public static class MockContactDirectoryProvider extends MockContentProvider { 63 64 private String mAuthority; 65 66 private MatrixCursor mResponse; 67 68 @Override attachInfoForTesting(Context context, ProviderInfo info)69 public void attachInfoForTesting(Context context, ProviderInfo info) { 70 mAuthority = info.authority; 71 } 72 createResponseCursor()73 public MatrixCursor createResponseCursor() { 74 mResponse = new MatrixCursor( 75 new String[] { Directory.ACCOUNT_NAME, Directory.ACCOUNT_TYPE, 76 Directory.DISPLAY_NAME, Directory.TYPE_RESOURCE_ID, 77 Directory.EXPORT_SUPPORT, Directory.SHORTCUT_SUPPORT, 78 Directory.PHOTO_SUPPORT }); 79 80 return mResponse; 81 } 82 83 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)84 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 85 String sortOrder) { 86 87 if (uri.toString().equals("content://" + mAuthority + "/directories")) { 88 // Should tolerate multiple queries. 89 mResponse.moveToPosition(-1); 90 return mResponse; 91 } else if (uri.toString().startsWith("content://" + mAuthority + "/contacts")) { 92 MatrixCursor cursor = new MatrixCursor( 93 new String[] { "projection", "selection", "selectionArgs", "sortOrder", 94 "accountName", "accountType"}); 95 cursor.addRow(new Object[] { 96 Lists.newArrayList(projection).toString(), 97 selection, 98 Lists.newArrayList(selectionArgs).toString(), 99 sortOrder, 100 uri.getQueryParameter(RawContacts.ACCOUNT_NAME), 101 uri.getQueryParameter(RawContacts.ACCOUNT_TYPE), 102 }); 103 return cursor; 104 } else if (uri.toString().startsWith( 105 "content://" + mAuthority + "/aggregation_exceptions")) { 106 return new MatrixCursor(projection); 107 } 108 109 fail("Unexpected uri: " + uri); 110 return null; 111 } 112 } 113 114 @Override setUp()115 public void setUp() throws Exception { 116 super.setUp(); 117 118 mProvider = (ContactsProvider2) getProvider(); 119 mDirectoryManager = mProvider.getContactDirectoryManagerForTest(); 120 121 mPackageManager = (ContactsMockPackageManager) getProvider() 122 .getContext().getPackageManager(); 123 } 124 125 @Override getContextPackageName()126 protected String getContextPackageName() { 127 // In this test, we need to use the real package name, because that'll be recorded in the 128 // directory table, and if it's wrong, the tests would get confused. 129 return getContext().getPackageName(); 130 } 131 testIsDirectoryProvider()132 public void testIsDirectoryProvider() { 133 ProviderInfo provider = new ProviderInfo(); 134 135 // Null -- just return false. 136 assertFalse(ContactDirectoryManager.isDirectoryProvider(null)); 137 138 // No metadata 139 assertFalse(ContactDirectoryManager.isDirectoryProvider(provider)); 140 141 // No CONTACT_DIRECTORY_META_DATA 142 provider.metaData = new Bundle(); 143 assertFalse(ContactDirectoryManager.isDirectoryProvider(provider)); 144 145 // CONTACT_DIRECTORY_META_DATA is a string 146 provider.metaData.putString("android.content.ContactDirectory", ""); 147 assertFalse(ContactDirectoryManager.isDirectoryProvider(provider)); 148 149 // CONTACT_DIRECTORY_META_DATA is false 150 provider.metaData.putBoolean("android.content.ContactDirectory", false); 151 assertFalse(ContactDirectoryManager.isDirectoryProvider(provider)); 152 153 // CONTACT_DIRECTORY_META_DATA is true 154 provider.metaData.putBoolean("android.content.ContactDirectory", true); 155 assertTrue(ContactDirectoryManager.isDirectoryProvider(provider)); 156 } 157 testScanAllProviders()158 public void testScanAllProviders() throws Exception { 159 mPackageManager.setInstalledPackages( 160 Lists.newArrayList( 161 createProviderPackage("test.package1", "authority1"), 162 createProviderPackage("test.package2", "authority2"), 163 createPackage("test.packageX", "authorityX", false))); 164 165 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 166 MockContactDirectoryProvider.class, "authority1"); 167 168 MatrixCursor response1 = provider1.createResponseCursor(); 169 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 170 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 171 Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY); 172 addDirectoryRow(response1, "account-name2", "account-type2", "display-name2", 2, 173 Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY, 174 Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY); 175 176 MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider( 177 MockContactDirectoryProvider.class, "authority2"); 178 179 MatrixCursor response2 = provider2.createResponseCursor(); 180 addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3, 181 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, 182 Directory.PHOTO_SUPPORT_FULL); 183 184 assertEquals(3, mDirectoryManager.scanAllPackages(/* rescan=*/ false)); 185 186 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, 187 /* order by=*/ Directory.DIRECTORY_AUTHORITY + "," + Directory.ACCOUNT_NAME + 188 "," + Directory._ID ); 189 190 TestUtils.dumpCursor(cursor); 191 assertEquals(5, cursor.getCount()); 192 193 assertTrue(cursor.moveToPosition(0)); 194 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", 195 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 196 Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY); 197 198 assertTrue(cursor.moveToPosition(1)); 199 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name2", "account-type2", 200 "display-name2", 2, Directory.EXPORT_SUPPORT_ANY_ACCOUNT, 201 Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY, Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY); 202 203 assertTrue(cursor.moveToPosition(2)); 204 assertDirectoryRow(cursor, "test.package2", "authority2", "account-name3", "account-type3", 205 "display-name3", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, 206 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); 207 208 assertTrue(cursor.moveToPosition(3)); 209 assertDirectoryRow(cursor, getContext().getPackageName(), 210 "com.android.contacts", null, null, 211 null, -1 /* =any */, Directory.EXPORT_SUPPORT_NONE, 212 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); 213 214 assertTrue(cursor.moveToPosition(4)); 215 assertDirectoryRow(cursor, getContext().getPackageName(), 216 "com.android.contacts", null, null, 217 null, -1 /* =any */, Directory.EXPORT_SUPPORT_NONE, 218 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); 219 220 cursor.close(); 221 } 222 testScanAllProviders_scanCondition()223 public void testScanAllProviders_scanCondition() throws Exception { 224 testScanAllProviders(); 225 226 // Nothing has changed, so no scanning. 227 assertEquals(0, mDirectoryManager.scanAllPackages(/* rescan=*/ false)); 228 229 // rescan = true, so a full-scan should happen. 230 assertEquals(3, mDirectoryManager.scanAllPackages(/* rescan=*/ true)); 231 232 // Change GAL packages, a scan should happen. 233 mPackageManager.setInstalledPackages( 234 Lists.newArrayList( 235 createProviderPackage("test.package2", "authority2"), 236 createPackage("test.packageX", "authorityX", false))); 237 assertEquals(1, mDirectoryManager.scanAllPackages(/* rescan=*/ false)); 238 239 // Remove the non-GAL package, no scan should happen. 240 mPackageManager.setInstalledPackages( 241 Lists.newArrayList( 242 createProviderPackage("test.package2", "authority2"))); 243 assertEquals(0, mDirectoryManager.scanAllPackages(/* rescan=*/ false)); 244 245 // Remove GAL package 2 and add 1, a scan should happen. 246 mPackageManager.setInstalledPackages( 247 Lists.newArrayList( 248 createProviderPackage("test.package1", "authority1"), 249 createPackage("test.packageX", "authorityX", false))); 250 assertEquals(2, mDirectoryManager.scanAllPackages(/* rescan=*/ false)); 251 252 } 253 testPackageInstalled()254 public void testPackageInstalled() throws Exception { 255 mPackageManager.setInstalledPackages( 256 Lists.newArrayList(createProviderPackage("test.package1", "authority1"), 257 createPackage("test.packageX", "authorityX", false))); 258 259 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 260 MockContactDirectoryProvider.class, "authority1"); 261 262 MatrixCursor response1 = provider1.createResponseCursor(); 263 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 264 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 265 Directory.PHOTO_SUPPORT_FULL); 266 267 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 268 269 // At this point the manager has discovered a single directory (plus two 270 // standard ones). 271 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 272 assertEquals(3, cursor.getCount()); 273 cursor.close(); 274 275 // Pretend to install another package 276 MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider( 277 MockContactDirectoryProvider.class, "authority2"); 278 279 MatrixCursor response2 = provider2.createResponseCursor(); 280 addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3, 281 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, 282 Directory.PHOTO_SUPPORT_FULL); 283 284 mPackageManager.getInstalledPackages(0).add( 285 createProviderPackage("test.package2", "authority2")); 286 287 mProvider.onPackageChanged("test.package2"); 288 289 cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 290 assertEquals(4, cursor.getCount()); 291 292 cursor.moveToPosition(2); 293 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", 294 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 295 Directory.PHOTO_SUPPORT_FULL); 296 297 cursor.moveToNext(); 298 assertDirectoryRow(cursor, "test.package2", "authority2", "account-name3", "account-type3", 299 "display-name3", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, 300 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); 301 302 cursor.close(); 303 } 304 testPackageUninstalled()305 public void testPackageUninstalled() throws Exception { 306 mPackageManager.setInstalledPackages( 307 Lists.newArrayList( 308 createProviderPackage("test.package1", "authority1"), 309 createProviderPackage("test.package2", "authority2"), 310 createPackage("test.packageX", "authorityX", false))); 311 312 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 313 MockContactDirectoryProvider.class, "authority1"); 314 315 MatrixCursor response1 = provider1.createResponseCursor(); 316 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 317 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 318 Directory.PHOTO_SUPPORT_NONE); 319 320 MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider( 321 MockContactDirectoryProvider.class, "authority2"); 322 323 MatrixCursor response2 = provider2.createResponseCursor(); 324 addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3, 325 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, 326 Directory.PHOTO_SUPPORT_FULL); 327 328 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 329 330 // At this point the manager has discovered two custom directories. 331 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 332 assertEquals(4, cursor.getCount()); 333 cursor.close(); 334 335 // Pretend to uninstall one of the packages 336 mPackageManager.getInstalledPackages(0).remove(1); 337 338 mProvider.onPackageChanged("test.package2"); 339 340 cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 341 assertEquals(3, cursor.getCount()); 342 343 cursor.moveToPosition(2); 344 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", 345 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 346 Directory.PHOTO_SUPPORT_NONE); 347 348 cursor.close(); 349 } 350 testPackageReplaced()351 public void testPackageReplaced() throws Exception { 352 mPackageManager.setInstalledPackages( 353 Lists.newArrayList( 354 createProviderPackage("test.package1", "authority1"), 355 createProviderPackage("test.package2", "authority2"), 356 createPackage("test.packageX", "authorityX", false))); 357 358 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 359 MockContactDirectoryProvider.class, "authority1"); 360 361 MatrixCursor response1 = provider1.createResponseCursor(); 362 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 363 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 364 Directory.PHOTO_SUPPORT_NONE); 365 366 MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider( 367 MockContactDirectoryProvider.class, "authority2"); 368 369 MatrixCursor response2 = provider2.createResponseCursor(); 370 addDirectoryRow(response2, "account-name3", "account-type3", "display-name3", 3, 371 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, 372 Directory.PHOTO_SUPPORT_FULL); 373 374 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 375 376 // At this point the manager has discovered two custom directories. 377 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 378 assertEquals(4, cursor.getCount()); 379 cursor.close(); 380 381 // Pretend to replace the package with a different provider inside 382 MatrixCursor response3 = provider2.createResponseCursor(); 383 addDirectoryRow(response3, "account-name4", "account-type4", "display-name4", 4, 384 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 385 Directory.PHOTO_SUPPORT_NONE); 386 387 mProvider.onPackageChanged("test.package2"); 388 389 cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 390 assertEquals(4, cursor.getCount()); 391 392 cursor.moveToPosition(2); 393 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", 394 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 395 Directory.PHOTO_SUPPORT_NONE); 396 397 cursor.moveToNext(); 398 assertDirectoryRow(cursor, "test.package2", "authority2", "account-name4", "account-type4", 399 "display-name4", 4, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 400 Directory.PHOTO_SUPPORT_NONE); 401 402 cursor.close(); 403 } 404 405 /** 406 * Tests if the manager works correctly when the package name for a directory is changed 407 * (on system update). 408 */ testPackageRenamed()409 public void testPackageRenamed() throws Exception { 410 mPackageManager.setInstalledPackages( 411 Lists.newArrayList( 412 createProviderPackage("test.package1", "authority1"), 413 createProviderPackage("test.package2", "authority2"), 414 createPackage("test.packageX", "authorityX", false))); 415 416 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 417 MockContactDirectoryProvider.class, "authority1"); 418 419 MatrixCursor response1 = provider1.createResponseCursor(); 420 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 421 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 422 Directory.PHOTO_SUPPORT_NONE); 423 424 MockContactDirectoryProvider provider2 = (MockContactDirectoryProvider) addProvider( 425 MockContactDirectoryProvider.class, "authority2"); 426 427 MatrixCursor response2 = provider2.createResponseCursor(); 428 addDirectoryRow(response2, "account-name2", "account-type2", "display-name2", 2, 429 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, 430 Directory.PHOTO_SUPPORT_FULL); 431 432 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 433 434 // At this point the manager has discovered two custom directories. 435 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 436 assertEquals(4, cursor.getCount()); 437 cursor.close(); 438 439 // Pretend to rename the package name of a package on system update. 440 PackageInfo info = mPackageManager.getInstalledPackages(0).get(1); 441 info.packageName = "test.package3"; 442 info.providers[0].packageName = "test.package3"; 443 MatrixCursor response3 = provider2.createResponseCursor(); 444 // Change resource id. 445 addDirectoryRow(response3, "account-name2", "account-type2", "display-name2", 3, 446 Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, Directory.SHORTCUT_SUPPORT_FULL, 447 Directory.PHOTO_SUPPORT_FULL); 448 449 // When this happens on reboot, scanAllPackages() is called instead of onPackageChanged() 450 // (as part of ContactsProvider2 initialization). 451 // Accounts won't be affected so false should be passed here. 452 mDirectoryManager.scanAllPackages(false); 453 454 cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 455 // We should have columns for default, local_invisible, test.package1, and test.package3. 456 // The row for test.package2 should not remain. 457 assertEquals(4, cursor.getCount()); 458 459 cursor.moveToPosition(2); 460 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", 461 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 462 Directory.PHOTO_SUPPORT_NONE); 463 464 cursor.moveToNext(); 465 assertDirectoryRow(cursor, "test.package3", "authority2", "account-name2", "account-type2", 466 "display-name2", 3, Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY, 467 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); 468 469 cursor.close(); 470 } 471 testAccountRemoval()472 public void testAccountRemoval() throws Exception { 473 mPackageManager.setInstalledPackages( 474 Lists.newArrayList( 475 createProviderPackage("test.package1", "authority1"), 476 createProviderPackage("test.package2", "authority2"), 477 createPackage("test.packageX", "authorityX", false))); 478 479 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 480 MockContactDirectoryProvider.class, "authority1"); 481 482 Account[] accounts = new Account[]{ 483 new Account("account-name1", "account-type1"), 484 new Account("account-name2", "account-type2")}; 485 mActor.setAccounts(accounts); 486 ((ContactsProvider2)getProvider()).onAccountsUpdated(accounts); 487 488 MatrixCursor response1 = provider1.createResponseCursor(); 489 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 490 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 491 Directory.PHOTO_SUPPORT_NONE); 492 addDirectoryRow(response1, "account-name2", "account-type2", "display-name2", 2, 493 Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_DATA_ITEMS_ONLY, 494 Directory.PHOTO_SUPPORT_FULL_SIZE_ONLY); 495 496 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 497 498 accounts = new Account[]{new Account("account-name1", "account-type1")}; 499 mActor.setAccounts(accounts); 500 ((ContactsProvider2)getProvider()).onAccountsUpdated(accounts); 501 502 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 503 assertEquals(3, cursor.getCount()); 504 505 cursor.moveToPosition(2); 506 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name1", "account-type1", 507 "display-name1", 1, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 508 Directory.PHOTO_SUPPORT_NONE); 509 510 cursor.close(); 511 } 512 testNotifyDirectoryChange()513 public void testNotifyDirectoryChange() throws Exception { 514 mPackageManager.setInstalledPackages( 515 Lists.newArrayList(createProviderPackage("test.package1", "authority1"), 516 createPackage("test.packageX", "authorityX", false))); 517 518 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 519 MockContactDirectoryProvider.class, "authority1"); 520 521 MatrixCursor response1 = provider1.createResponseCursor(); 522 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 523 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 524 Directory.PHOTO_SUPPORT_NONE); 525 526 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 527 528 // Pretend to replace the package with a different provider inside 529 MatrixCursor response2 = provider1.createResponseCursor(); 530 addDirectoryRow(response2, "account-name2", "account-type2", "display-name2", 2, 531 Directory.EXPORT_SUPPORT_ANY_ACCOUNT, Directory.SHORTCUT_SUPPORT_FULL, 532 Directory.PHOTO_SUPPORT_FULL); 533 534 ContactsContract.Directory.notifyDirectoryChange(mResolver); 535 536 Cursor cursor = mResolver.query(Directory.CONTENT_URI, null, null, null, null); 537 assertEquals(3, cursor.getCount()); 538 539 cursor.moveToPosition(2); 540 assertDirectoryRow(cursor, "test.package1", "authority1", "account-name2", "account-type2", 541 "display-name2", 2, Directory.EXPORT_SUPPORT_ANY_ACCOUNT, 542 Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); 543 544 cursor.close(); 545 } 546 testForwardingToDirectoryProvider()547 public void testForwardingToDirectoryProvider() throws Exception { 548 mPackageManager.setInstalledPackages( 549 Lists.newArrayList(createProviderPackage("test.package1", "authority1"), 550 createPackage("test.packageX", "authorityX", false))); 551 552 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 553 MockContactDirectoryProvider.class, "authority1"); 554 555 MatrixCursor response1 = provider1.createResponseCursor(); 556 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 557 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 558 Directory.PHOTO_SUPPORT_NONE); 559 560 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 561 562 Cursor cursor = mResolver.query( 563 Directory.CONTENT_URI, new String[] { Directory._ID }, null, null, null); 564 cursor.moveToPosition(2); 565 long directoryId = cursor.getLong(0); 566 cursor.close(); 567 568 Uri contentUri = Contacts.CONTENT_URI.buildUpon().appendQueryParameter( 569 ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build(); 570 571 // The request should be forwarded to TestProvider, which will simply 572 // package arguments and return them to us for verification 573 cursor = mResolver.query(contentUri, 574 new String[]{"f1", "f2"}, "query", new String[]{"s1", "s2"}, "so"); 575 assertNotNull(cursor); 576 assertEquals(1, cursor.getCount()); 577 cursor.moveToFirst(); 578 assertEquals("[f1, f2]", cursor.getString(cursor.getColumnIndex("projection"))); 579 assertEquals("query", cursor.getString(cursor.getColumnIndex("selection"))); 580 assertEquals("[s1, s2]", cursor.getString(cursor.getColumnIndex("selectionArgs"))); 581 assertEquals("so", cursor.getString(cursor.getColumnIndex("sortOrder"))); 582 assertEquals("account-name1", cursor.getString(cursor.getColumnIndex("accountName"))); 583 assertEquals("account-type1", cursor.getString(cursor.getColumnIndex("accountType"))); 584 cursor.close(); 585 } 586 testProjectionPopulated()587 public void testProjectionPopulated() throws Exception { 588 mPackageManager.setInstalledPackages( 589 Lists.newArrayList(createProviderPackage("test.package1", "authority1"), 590 createPackage("test.packageX", "authorityX", false))); 591 592 MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( 593 MockContactDirectoryProvider.class, "authority1"); 594 595 MatrixCursor response1 = provider1.createResponseCursor(); 596 addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, 597 Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, 598 Directory.PHOTO_SUPPORT_NONE); 599 600 mDirectoryManager.scanAllPackages(/* rescan=*/ false); 601 602 Cursor cursor = mResolver.query( 603 Directory.CONTENT_URI, new String[] { Directory._ID }, null, null, null); 604 cursor.moveToPosition(2); 605 long directoryId = cursor.getLong(0); 606 cursor.close(); 607 608 Uri contentUri = AggregationExceptions.CONTENT_URI.buildUpon().appendQueryParameter( 609 ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build(); 610 611 // The request should be forwarded to TestProvider, which will return an empty cursor 612 // but the projection should be correctly populated by ContactProvider 613 assertProjection(contentUri, new String[]{ 614 AggregationExceptionColumns._ID, 615 AggregationExceptions.TYPE, 616 AggregationExceptions.RAW_CONTACT_ID1, 617 AggregationExceptions.RAW_CONTACT_ID2, 618 }); 619 } 620 621 /** 622 * Test {@link ContactDirectoryManager#getDirectoryProviderPackages} with the actual 623 * package manager, and see if it returns the google sync package. 624 */ testGetDirectoryProviderPackages()625 public void testGetDirectoryProviderPackages() { 626 final PackageManager pm = getContext().getPackageManager(); 627 final String googleSync = "com.google.android.syncadapters.contacts"; 628 629 // Skip if the package is not installed. 630 try { 631 pm.getPackageInfo(googleSync, 0); 632 } catch (NameNotFoundException e) { 633 Log.w(TAG, googleSync + " not installed. Skipping..."); 634 return; 635 } 636 637 // If installed, getDirectoryProviderPackages() should return it. 638 assertTrue(ContactDirectoryManager.getDirectoryProviderPackages(pm).contains(googleSync)); 639 } 640 createProviderPackage(String packageName, String authority)641 protected PackageInfo createProviderPackage(String packageName, String authority) { 642 return createPackage(packageName, authority, true); 643 } 644 createPackage(String packageName, String authority, boolean isDirectoryProvider)645 protected PackageInfo createPackage(String packageName, String authority, 646 boolean isDirectoryProvider) { 647 PackageInfo providerPackage = new PackageInfo(); 648 providerPackage.packageName = packageName; 649 ProviderInfo providerInfo = new ProviderInfo(); 650 providerInfo.packageName = providerPackage.packageName; 651 providerInfo.authority = authority; 652 if (isDirectoryProvider) { 653 providerInfo.metaData = new Bundle(); 654 providerInfo.metaData.putBoolean("android.content.ContactDirectory", true); 655 } 656 providerPackage.providers = new ProviderInfo[] { providerInfo }; 657 return providerPackage; 658 } 659 addDirectoryRow(MatrixCursor cursor, String accountName, String accountType, String displayName, int typeResourceId, int exportSupport, int shortcutSupport, int photoSupport)660 protected void addDirectoryRow(MatrixCursor cursor, String accountName, String accountType, 661 String displayName, int typeResourceId, int exportSupport, int shortcutSupport, 662 int photoSupport) { 663 Object[] row = new Object[cursor.getColumnCount()]; 664 row[cursor.getColumnIndex(Directory.ACCOUNT_NAME)] = accountName; 665 row[cursor.getColumnIndex(Directory.ACCOUNT_TYPE)] = accountType; 666 row[cursor.getColumnIndex(Directory.DISPLAY_NAME)] = displayName; 667 row[cursor.getColumnIndex(Directory.TYPE_RESOURCE_ID)] = typeResourceId; 668 row[cursor.getColumnIndex(Directory.EXPORT_SUPPORT)] = exportSupport; 669 row[cursor.getColumnIndex(Directory.SHORTCUT_SUPPORT)] = shortcutSupport; 670 row[cursor.getColumnIndex(Directory.PHOTO_SUPPORT)] = photoSupport; 671 cursor.addRow(row); 672 } 673 assertDirectoryRow(Cursor cursor, String packageName, String authority, String accountName, String accountType, String displayName, int typeResourceId, int exportSupport, int shortcutSupport, int photoSupport)674 protected void assertDirectoryRow(Cursor cursor, String packageName, String authority, 675 String accountName, String accountType, String displayName, int typeResourceId, 676 int exportSupport, int shortcutSupport, int photoSupport) { 677 ContentValues values = new ContentValues(); 678 values.put(Directory.PACKAGE_NAME, packageName); 679 values.put(Directory.DIRECTORY_AUTHORITY, authority); 680 values.put(Directory.ACCOUNT_NAME, accountName); 681 values.put(Directory.ACCOUNT_TYPE, accountType); 682 values.put(Directory.DISPLAY_NAME, displayName); 683 if (typeResourceId >= 0) { 684 values.put(Directory.TYPE_RESOURCE_ID, typeResourceId); 685 } 686 values.put(Directory.EXPORT_SUPPORT, exportSupport); 687 values.put(Directory.SHORTCUT_SUPPORT, shortcutSupport); 688 values.put(Directory.PHOTO_SUPPORT, photoSupport); 689 690 assertCursorValues(cursor, values); 691 } 692 } 693