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