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