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 android.accounts.cts; 18 19 import android.accounts.Account; 20 import android.accounts.AccountManager; 21 import android.accounts.AccountManagerCallback; 22 import android.accounts.AccountManagerFuture; 23 import android.accounts.AuthenticatorDescription; 24 import android.accounts.AuthenticatorException; 25 import android.accounts.OnAccountsUpdateListener; 26 import android.accounts.OperationCanceledException; 27 import android.app.Activity; 28 import android.content.Context; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.os.StrictMode; 32 import android.test.AndroidTestCase; 33 34 import java.io.IOException; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.concurrent.TimeUnit; 37 38 /** 39 * You can run those unit tests with the following command line: 40 * 41 * adb shell am instrument 42 * -e debug false -w 43 * -e class android.accounts.cts.AccountManagerTest 44 * android.accounts.cts/android.test.InstrumentationTestRunner 45 */ 46 public class AccountManagerTest extends AndroidTestCase { 47 48 public static final String ACCOUNT_NAME = "android.accounts.cts.account.name"; 49 public static final String ACCOUNT_NAME_OTHER = "android.accounts.cts.account.name.other"; 50 51 public static final String ACCOUNT_TYPE = "android.accounts.cts.account.type"; 52 public static final String ACCOUNT_TYPE_OTHER = "android.accounts.cts.account.type.other"; 53 54 public static final String ACCOUNT_PASSWORD = "android.accounts.cts.account.password"; 55 56 public static final String AUTH_TOKEN = "mockAuthToken"; 57 public static final String AUTH_TOKEN_TYPE = "mockAuthTokenType"; 58 public static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel"; 59 60 public static final String FEATURE_1 = "feature.1"; 61 public static final String FEATURE_2 = "feature.2"; 62 public static final String NON_EXISTING_FEATURE = "feature.3"; 63 64 public static final String OPTION_NAME_1 = "option.name.1"; 65 public static final String OPTION_VALUE_1 = "option.value.1"; 66 67 public static final String OPTION_NAME_2 = "option.name.2"; 68 public static final String OPTION_VALUE_2 = "option.value.2"; 69 70 public static final String[] REQUIRED_FEATURES = new String[] { FEATURE_1, FEATURE_2 }; 71 72 public static final Activity ACTIVITY = new Activity(); 73 public static final Bundle OPTIONS_BUNDLE = new Bundle(); 74 75 public static final Bundle USERDATA_BUNDLE = new Bundle(); 76 77 public static final String USERDATA_NAME_1 = "user.data.name.1"; 78 public static final String USERDATA_NAME_2 = "user.data.name.2"; 79 public static final String USERDATA_VALUE_1 = "user.data.value.1"; 80 public static final String USERDATA_VALUE_2 = "user.data.value.2"; 81 82 public static final Account ACCOUNT = new Account(ACCOUNT_NAME, ACCOUNT_TYPE); 83 public static final Account ACCOUNT_SAME_TYPE = new Account(ACCOUNT_NAME_OTHER, ACCOUNT_TYPE); 84 85 private static MockAccountAuthenticator mockAuthenticator; 86 private static final int LATCH_TIMEOUT_MS = 500; 87 private static AccountManager am; 88 89 public synchronized static MockAccountAuthenticator getMockAuthenticator(Context context) { 90 if (null == mockAuthenticator) { 91 mockAuthenticator = new MockAccountAuthenticator(context); 92 } 93 return mockAuthenticator; 94 } 95 96 @Override 97 public void setUp() throws Exception { 98 super.setUp(); 99 100 OPTIONS_BUNDLE.putString(OPTION_NAME_1, OPTION_VALUE_1); 101 OPTIONS_BUNDLE.putString(OPTION_NAME_2, OPTION_VALUE_2); 102 103 USERDATA_BUNDLE.putString(USERDATA_NAME_1, USERDATA_VALUE_1); 104 105 getMockAuthenticator(getContext()); 106 107 am = AccountManager.get(getContext()); 108 } 109 110 @Override 111 public void tearDown() throws Exception, AuthenticatorException, OperationCanceledException { 112 mockAuthenticator.clearData(); 113 114 // Need to clean up created account 115 assertTrue(removeAccount(am, ACCOUNT, null /* callback */)); 116 assertTrue(removeAccount(am, ACCOUNT_SAME_TYPE, null /* callback */)); 117 118 // need to clean up the authenticator cached data 119 mockAuthenticator.clearData(); 120 121 super.tearDown(); 122 } 123 124 private void validateAccountAndAuthTokenResult(Bundle result) { 125 assertEquals(ACCOUNT_NAME, result.get(AccountManager.KEY_ACCOUNT_NAME)); 126 assertEquals(ACCOUNT_TYPE, result.get(AccountManager.KEY_ACCOUNT_TYPE)); 127 assertEquals(AUTH_TOKEN, result.get(AccountManager.KEY_AUTHTOKEN)); 128 } 129 130 private void validateAccountAndNoAuthTokenResult(Bundle result) { 131 assertEquals(ACCOUNT_NAME, result.get(AccountManager.KEY_ACCOUNT_NAME)); 132 assertEquals(ACCOUNT_TYPE, result.get(AccountManager.KEY_ACCOUNT_TYPE)); 133 assertNull(result.get(AccountManager.KEY_AUTHTOKEN)); 134 } 135 136 private void validateNullResult(Bundle resultBundle) { 137 assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME)); 138 assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE)); 139 assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN)); 140 } 141 142 private void validateAccountAndAuthTokenType() { 143 assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType()); 144 assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType()); 145 } 146 147 private void validateFeatures() { 148 assertEquals(REQUIRED_FEATURES[0], mockAuthenticator.getRequiredFeatures()[0]); 149 assertEquals(REQUIRED_FEATURES[1], mockAuthenticator.getRequiredFeatures()[1]); 150 } 151 152 private void validateOptions(Bundle expectedOptions, Bundle actualOptions) { 153 // In ICS AccountManager may add options to indicate the caller id. 154 // We only validate that the passed in options are present in the actual ones 155 if (expectedOptions != null) { 156 assertNotNull(actualOptions); 157 assertEquals(expectedOptions.get(OPTION_NAME_1), actualOptions.get(OPTION_NAME_1)); 158 assertEquals(expectedOptions.get(OPTION_NAME_2), actualOptions.get(OPTION_NAME_2)); 159 } 160 } 161 162 private void validateSystemOptions(Bundle options) { 163 assertNotNull(options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME)); 164 assertTrue(options.containsKey(AccountManager.KEY_CALLER_UID)); 165 assertTrue(options.containsKey(AccountManager.KEY_CALLER_PID)); 166 } 167 168 private void validateCredentials() { 169 assertEquals(ACCOUNT, mockAuthenticator.getAccount()); 170 } 171 172 private int getAccountsCount() { 173 Account[] accounts = am.getAccounts(); 174 assertNotNull(accounts); 175 return accounts.length; 176 } 177 178 private Bundle addAccount(AccountManager am, String accountType, String authTokenType, 179 String[] requiredFeatures, Bundle options, Activity activity, 180 AccountManagerCallback<Bundle> callback, Handler handler) throws 181 IOException, AuthenticatorException, OperationCanceledException { 182 183 AccountManagerFuture<Bundle> futureBundle = am.addAccount( 184 accountType, 185 authTokenType, 186 requiredFeatures, 187 options, 188 activity, 189 callback, 190 handler); 191 192 Bundle resultBundle = futureBundle.getResult(); 193 assertTrue(futureBundle.isDone()); 194 assertNotNull(resultBundle); 195 196 return resultBundle; 197 } 198 199 private boolean removeAccount(AccountManager am, Account account, 200 AccountManagerCallback<Boolean> callback) throws IOException, AuthenticatorException, 201 OperationCanceledException { 202 203 AccountManagerFuture<Boolean> futureBoolean = am.removeAccount(account, 204 callback, 205 null /* handler */); 206 Boolean resultBoolean = futureBoolean.getResult(); 207 assertTrue(futureBoolean.isDone()); 208 209 return resultBoolean; 210 } 211 212 private void addAccountExplicitly(Account account, String password, Bundle userdata) { 213 assertTrue(am.addAccountExplicitly(account, password, userdata)); 214 } 215 216 private Bundle getAuthTokenByFeature(String[] features, Activity activity) 217 throws IOException, AuthenticatorException, OperationCanceledException { 218 219 AccountManagerFuture<Bundle> futureBundle = am.getAuthTokenByFeatures(ACCOUNT_TYPE, 220 AUTH_TOKEN_TYPE, 221 features, 222 activity, 223 OPTIONS_BUNDLE, 224 OPTIONS_BUNDLE, 225 null /* no callback */, 226 null /* no handler */ 227 ); 228 229 Bundle resultBundle = futureBundle.getResult(); 230 231 assertTrue(futureBundle.isDone()); 232 assertNotNull(resultBundle); 233 234 return resultBundle; 235 } 236 237 private boolean isAccountPresent(Account[] accounts, Account accountToCheck) { 238 if (null == accounts || null == accountToCheck) { 239 return false; 240 } 241 boolean result = false; 242 int length = accounts.length; 243 for (int n=0; n<length; n++) { 244 if(accountToCheck.equals(accounts[n])) { 245 result = true; 246 break; 247 } 248 } 249 return result; 250 } 251 252 /** 253 * Test singleton 254 */ 255 public void testGet() { 256 assertNotNull(AccountManager.get(getContext())); 257 } 258 259 /** 260 * Test a basic addAccount() 261 */ 262 public void testAddAccount() throws IOException, AuthenticatorException, 263 OperationCanceledException { 264 265 Bundle resultBundle = addAccount(am, 266 ACCOUNT_TYPE, 267 AUTH_TOKEN_TYPE, 268 REQUIRED_FEATURES, 269 OPTIONS_BUNDLE, 270 ACTIVITY, 271 null /* callback */, 272 null /* handler */); 273 274 // Assert parameters has been passed correctly 275 validateAccountAndAuthTokenType(); 276 validateFeatures(); 277 validateOptions(OPTIONS_BUNDLE, mockAuthenticator.mOptionsAddAccount); 278 validateSystemOptions(mockAuthenticator.mOptionsAddAccount); 279 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 280 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 281 validateOptions(null, mockAuthenticator.mOptionsGetAuthToken); 282 283 // Assert returned result 284 validateAccountAndNoAuthTokenResult(resultBundle); 285 } 286 287 /** 288 * Test addAccount() with callback and handler 289 */ 290 public void testAddAccountWithCallbackAndHandler() throws IOException, 291 AuthenticatorException, OperationCanceledException { 292 293 testAddAccountWithCallbackAndHandler(null /* handler */); 294 testAddAccountWithCallbackAndHandler(new Handler()); 295 } 296 297 private void testAddAccountWithCallbackAndHandler(Handler handler) throws IOException, 298 AuthenticatorException, OperationCanceledException { 299 300 final CountDownLatch latch = new CountDownLatch(1); 301 302 AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { 303 public void run(AccountManagerFuture<Bundle> bundleFuture) { 304 Bundle resultBundle = null; 305 try { 306 resultBundle = bundleFuture.getResult(); 307 } catch (OperationCanceledException e) { 308 fail("should not throw an OperationCanceledException"); 309 } catch (IOException e) { 310 fail("should not throw an IOException"); 311 } catch (AuthenticatorException e) { 312 fail("should not throw an AuthenticatorException"); 313 } 314 315 // Assert parameters has been passed correctly 316 validateAccountAndAuthTokenType(); 317 validateFeatures(); 318 validateOptions(OPTIONS_BUNDLE, mockAuthenticator.mOptionsAddAccount); 319 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 320 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 321 validateOptions(null, mockAuthenticator.mOptionsGetAuthToken); 322 323 // Assert return result 324 validateAccountAndNoAuthTokenResult(resultBundle); 325 326 latch.countDown(); 327 } 328 }; 329 330 addAccount(am, 331 ACCOUNT_TYPE, 332 AUTH_TOKEN_TYPE, 333 REQUIRED_FEATURES, 334 OPTIONS_BUNDLE, 335 ACTIVITY, 336 callback, 337 handler); 338 339 // Wait with timeout for the callback to do its work 340 try { 341 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 342 } catch (InterruptedException e) { 343 fail("should not throw an InterruptedException"); 344 } 345 } 346 347 /** 348 * Test addAccountExplicitly() and removeAccount() 349 */ 350 public void testAddAccountExplicitlyAndRemoveAccount() throws IOException, 351 AuthenticatorException, OperationCanceledException { 352 353 final int accountsCount = getAccountsCount(); 354 355 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 356 357 // Assert that we have one more account 358 Account[] accounts = am.getAccounts(); 359 assertNotNull(accounts); 360 assertEquals(1 + accountsCount, accounts.length); 361 assertTrue(isAccountPresent(am.getAccounts(), ACCOUNT)); 362 363 // Need to clean up 364 assertTrue(removeAccount(am, ACCOUNT, null /* callback */)); 365 366 // and verify that we go back to the initial state 367 accounts = am.getAccounts(); 368 assertNotNull(accounts); 369 assertEquals(accountsCount, accounts.length); 370 } 371 372 /** 373 * Test getAccounts() and getAccountsByType() 374 */ 375 public void testGetAccountsAndGetAccountsByType() throws IOException, AuthenticatorException, 376 OperationCanceledException { 377 378 assertEquals(false, isAccountPresent(am.getAccounts(), ACCOUNT)); 379 assertEquals(false, isAccountPresent(am.getAccounts(), ACCOUNT_SAME_TYPE)); 380 381 final int accountsCount = getAccountsCount(); 382 383 // Add a first account 384 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 385 386 // Check that we have the new account 387 Account[] accounts = am.getAccounts(); 388 assertEquals(1 + accountsCount, accounts.length); 389 assertEquals(true, isAccountPresent(accounts, ACCOUNT)); 390 391 // Add another account 392 addAccountExplicitly(ACCOUNT_SAME_TYPE, ACCOUNT_PASSWORD, null /* userData */); 393 394 // Check that we have one more account again 395 accounts = am.getAccounts(); 396 assertEquals(2 + accountsCount, accounts.length); 397 assertEquals(true, isAccountPresent(accounts, ACCOUNT_SAME_TYPE)); 398 399 // Check if we have one from first type 400 accounts = am.getAccountsByType(ACCOUNT_TYPE); 401 assertEquals(2, accounts.length); 402 403 // Check if we dont have any account from the other type 404 accounts = am.getAccountsByType(ACCOUNT_TYPE_OTHER); 405 assertEquals(0, accounts.length); 406 } 407 408 /** 409 * Test getAuthenticatorTypes() 410 */ 411 public void testGetAuthenticatorTypes() { 412 AuthenticatorDescription[] types = am.getAuthenticatorTypes(); 413 for(AuthenticatorDescription description: types) { 414 if (description.type.equals(ACCOUNT_TYPE)) { 415 return; 416 } 417 } 418 fail("should have found Authenticator type: " + ACCOUNT_TYPE); 419 } 420 421 /** 422 * Test setPassword() and getPassword() 423 */ 424 public void testSetAndGetAndClearPassword() { 425 // Add a first account 426 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 427 428 // Check that the password is the one we defined 429 assertEquals(ACCOUNT_PASSWORD, am.getPassword(ACCOUNT)); 430 431 // Clear the password and check that it is cleared 432 am.clearPassword(ACCOUNT); 433 assertNull(am.getPassword(ACCOUNT)); 434 435 // Reset the password 436 am.setPassword(ACCOUNT, ACCOUNT_PASSWORD); 437 438 // Check that the password is the one we defined 439 assertEquals(ACCOUNT_PASSWORD, am.getPassword(ACCOUNT)); 440 } 441 442 /** 443 * Test setUserData() and getUserData() 444 */ 445 public void testSetAndGetUserData() { 446 // Add a first account 447 boolean result = am.addAccountExplicitly(ACCOUNT, 448 ACCOUNT_PASSWORD, 449 USERDATA_BUNDLE); 450 451 assertTrue(result); 452 453 // Check that the UserData is the one we defined 454 assertEquals(USERDATA_VALUE_1, am.getUserData(ACCOUNT, USERDATA_NAME_1)); 455 456 am.setUserData(ACCOUNT, USERDATA_NAME_2, USERDATA_VALUE_2); 457 458 // Check that the UserData is the one we defined 459 assertEquals(USERDATA_VALUE_2, am.getUserData(ACCOUNT, USERDATA_NAME_2)); 460 } 461 462 /** 463 * Test getAccountsByTypeAndFeatures() 464 */ 465 public void testGetAccountsByTypeAndFeatures() throws IOException, 466 AuthenticatorException, OperationCanceledException { 467 468 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 469 470 AccountManagerFuture<Account[]> futureAccounts = am.getAccountsByTypeAndFeatures( 471 ACCOUNT_TYPE, REQUIRED_FEATURES, null, null); 472 473 Account[] accounts = futureAccounts.getResult(); 474 475 assertNotNull(accounts); 476 assertEquals(1, accounts.length); 477 assertEquals(true, isAccountPresent(accounts, ACCOUNT)); 478 479 futureAccounts = am.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, 480 new String[] { NON_EXISTING_FEATURE }, 481 null /* callback*/, 482 null /* handler */); 483 accounts = futureAccounts.getResult(); 484 485 assertNotNull(accounts); 486 assertEquals(0, accounts.length); 487 } 488 489 /** 490 * Test getAccountsByTypeAndFeatures() with callback and handler 491 */ 492 public void testGetAccountsByTypeAndFeaturesWithCallbackAndHandler() throws IOException, 493 AuthenticatorException, OperationCanceledException { 494 495 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 496 497 testGetAccountsByTypeAndFeaturesWithCallbackAndHandler(null /* handler */); 498 testGetAccountsByTypeAndFeaturesWithCallbackAndHandler(new Handler()); 499 } 500 501 private void testGetAccountsByTypeAndFeaturesWithCallbackAndHandler(Handler handler) throws 502 IOException, AuthenticatorException, OperationCanceledException { 503 504 final CountDownLatch latch1 = new CountDownLatch(1); 505 506 AccountManagerCallback<Account[]> callback1 = new AccountManagerCallback<Account[]>() { 507 public void run(AccountManagerFuture<Account[]> accountsFuture) { 508 try { 509 Account[] accounts = accountsFuture.getResult(); 510 assertNotNull(accounts); 511 assertEquals(1, accounts.length); 512 assertEquals(true, isAccountPresent(accounts, ACCOUNT)); 513 } catch (OperationCanceledException e) { 514 fail("should not throw an OperationCanceledException"); 515 } catch (IOException e) { 516 fail("should not throw an IOException"); 517 } catch (AuthenticatorException e) { 518 fail("should not throw an AuthenticatorException"); 519 } finally { 520 latch1.countDown(); 521 } 522 } 523 }; 524 525 AccountManagerFuture<Account[]> futureAccounts = am.getAccountsByTypeAndFeatures( 526 ACCOUNT_TYPE, 527 REQUIRED_FEATURES, 528 callback1, 529 handler); 530 531 Account[] accounts = futureAccounts.getResult(); 532 533 assertNotNull(accounts); 534 assertEquals(1, accounts.length); 535 assertEquals(true, isAccountPresent(accounts, ACCOUNT)); 536 537 // Wait with timeout for the callback to do its work 538 try { 539 latch1.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 540 } catch (InterruptedException e) { 541 fail("should not throw an InterruptedException"); 542 } 543 544 final CountDownLatch latch2 = new CountDownLatch(1); 545 546 AccountManagerCallback<Account[]> callback2 = new AccountManagerCallback<Account[]>() { 547 public void run(AccountManagerFuture<Account[]> accountsFuture) { 548 try { 549 Account[] accounts = accountsFuture.getResult(); 550 assertNotNull(accounts); 551 assertEquals(0, accounts.length); 552 } catch (OperationCanceledException e) { 553 fail("should not throw an OperationCanceledException"); 554 } catch (IOException e) { 555 fail("should not throw an IOException"); 556 } catch (AuthenticatorException e) { 557 fail("should not throw an AuthenticatorException"); 558 } finally { 559 latch2.countDown(); 560 } 561 } 562 }; 563 564 accounts = null; 565 566 futureAccounts = am.getAccountsByTypeAndFeatures(ACCOUNT_TYPE, 567 new String[] { NON_EXISTING_FEATURE }, 568 callback2, 569 handler); 570 571 accounts = futureAccounts.getResult(); 572 assertNotNull(accounts); 573 assertEquals(0, accounts.length); 574 575 // Wait with timeout for the callback to do its work 576 try { 577 latch2.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 578 } catch (InterruptedException e) { 579 fail("should not throw an InterruptedException"); 580 } 581 } 582 583 /** 584 * Test setAuthToken() and peekAuthToken() 585 */ 586 public void testSetAndPeekAndInvalidateAuthToken() { 587 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 588 589 am.setAuthToken(ACCOUNT, AUTH_TOKEN_TYPE, AUTH_TOKEN); 590 591 // Ask for the AuthToken 592 String token = am.peekAuthToken(ACCOUNT, AUTH_TOKEN_TYPE); 593 assertNotNull(token); 594 assertEquals(AUTH_TOKEN, token); 595 596 am.invalidateAuthToken(ACCOUNT_TYPE, AUTH_TOKEN); 597 token = am.peekAuthToken(ACCOUNT, AUTH_TOKEN_TYPE); 598 assertNull(token); 599 } 600 601 /** 602 * Test blockingGetAuthToken() 603 */ 604 public void testBlockingGetAuthToken() throws IOException, AuthenticatorException, 605 OperationCanceledException { 606 607 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null); 608 609 String token = am.blockingGetAuthToken(ACCOUNT, 610 AUTH_TOKEN_TYPE, 611 false /* no failure notification */); 612 613 // Ask for the AuthToken 614 assertNotNull(token); 615 assertEquals(AUTH_TOKEN, token); 616 } 617 618 /** 619 * Test getAuthToken() 620 */ 621 public void testGetAuthToken() throws IOException, AuthenticatorException, 622 OperationCanceledException { 623 624 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 625 626 AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT, 627 AUTH_TOKEN_TYPE, 628 false /* no failure notification */, 629 null /* no callback */, 630 null /* no handler */ 631 ); 632 633 Bundle resultBundle = futureBundle.getResult(); 634 635 assertTrue(futureBundle.isDone()); 636 assertNotNull(resultBundle); 637 638 // Assert returned result 639 validateAccountAndAuthTokenResult(resultBundle); 640 } 641 642 /** 643 * Test getAuthToken() with callback and handler 644 */ 645 public void testGetAuthTokenWithCallbackAndHandler() throws IOException, AuthenticatorException, 646 OperationCanceledException { 647 648 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 649 650 testGetAuthTokenWithCallbackAndHandler(null /* handler */); 651 testGetAuthTokenWithCallbackAndHandler(new Handler()); 652 } 653 654 private void testGetAuthTokenWithCallbackAndHandler(Handler handler) throws IOException, 655 AuthenticatorException, OperationCanceledException { 656 657 final CountDownLatch latch = new CountDownLatch(1); 658 659 AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { 660 public void run(AccountManagerFuture<Bundle> bundleFuture) { 661 662 Bundle resultBundle = null; 663 try { 664 resultBundle = bundleFuture.getResult(); 665 666 // Assert returned result 667 validateAccountAndAuthTokenResult(resultBundle); 668 669 } catch (OperationCanceledException e) { 670 fail("should not throw an OperationCanceledException"); 671 } catch (IOException e) { 672 fail("should not throw an IOException"); 673 } catch (AuthenticatorException e) { 674 fail("should not throw an AuthenticatorException"); 675 } 676 finally { 677 latch.countDown(); 678 } 679 } 680 }; 681 682 AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT, 683 AUTH_TOKEN_TYPE, 684 false /* no failure notification */, 685 callback, 686 handler 687 ); 688 689 Bundle resultBundle = futureBundle.getResult(); 690 691 assertTrue(futureBundle.isDone()); 692 assertNotNull(resultBundle); 693 694 // Wait with timeout for the callback to do its work 695 try { 696 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 697 } catch (InterruptedException e) { 698 fail("should not throw an InterruptedException"); 699 } 700 } 701 702 /** 703 * test getAuthToken() with options 704 */ 705 public void testGetAuthTokenWithOptions() throws IOException, AuthenticatorException, 706 OperationCanceledException { 707 708 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 709 710 AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT, 711 AUTH_TOKEN_TYPE, 712 OPTIONS_BUNDLE, 713 ACTIVITY, 714 null /* no callback */, 715 null /* no handler */ 716 ); 717 718 Bundle resultBundle = futureBundle.getResult(); 719 720 assertTrue(futureBundle.isDone()); 721 assertNotNull(resultBundle); 722 723 // Assert returned result 724 validateAccountAndAuthTokenResult(resultBundle); 725 726 validateOptions(null, mockAuthenticator.mOptionsAddAccount); 727 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 728 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 729 validateOptions(OPTIONS_BUNDLE, mockAuthenticator.mOptionsGetAuthToken); 730 validateSystemOptions(mockAuthenticator.mOptionsGetAuthToken); 731 } 732 733 /** 734 * test getAuthToken() with options and callback and handler 735 */ 736 public void testGetAuthTokenWithOptionsAndCallback() throws IOException, 737 AuthenticatorException, OperationCanceledException { 738 739 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 740 741 testGetAuthTokenWithOptionsAndCallbackAndHandler(null /* handler */); 742 testGetAuthTokenWithOptionsAndCallbackAndHandler(new Handler()); 743 } 744 745 private void testGetAuthTokenWithOptionsAndCallbackAndHandler(Handler handler) throws 746 IOException, AuthenticatorException, OperationCanceledException { 747 748 final CountDownLatch latch = new CountDownLatch(1); 749 750 AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { 751 public void run(AccountManagerFuture<Bundle> bundleFuture) { 752 753 Bundle resultBundle = null; 754 try { 755 resultBundle = bundleFuture.getResult(); 756 757 // Assert returned result 758 validateAccountAndAuthTokenResult(resultBundle); 759 760 } catch (OperationCanceledException e) { 761 fail("should not throw an OperationCanceledException"); 762 } catch (IOException e) { 763 fail("should not throw an IOException"); 764 } catch (AuthenticatorException e) { 765 fail("should not throw an AuthenticatorException"); 766 } 767 finally { 768 latch.countDown(); 769 } 770 } 771 }; 772 773 AccountManagerFuture<Bundle> futureBundle = am.getAuthToken(ACCOUNT, 774 AUTH_TOKEN_TYPE, 775 OPTIONS_BUNDLE, 776 ACTIVITY, 777 callback, 778 handler 779 ); 780 781 Bundle resultBundle = futureBundle.getResult(); 782 783 assertTrue(futureBundle.isDone()); 784 assertNotNull(resultBundle); 785 786 // Wait with timeout for the callback to do its work 787 try { 788 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 789 } catch (InterruptedException e) { 790 fail("should not throw an InterruptedException"); 791 } 792 } 793 794 /** 795 * Test getAuthTokenByFeatures() 796 */ 797 public void testGetAuthTokenByFeatures() throws IOException, AuthenticatorException, 798 OperationCanceledException { 799 800 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 801 802 Bundle resultBundle = getAuthTokenByFeature( 803 new String[] { NON_EXISTING_FEATURE }, 804 null /* activity */ 805 ); 806 807 // Assert returned result 808 validateNullResult(resultBundle); 809 810 validateOptions(null, mockAuthenticator.mOptionsAddAccount); 811 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 812 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 813 validateOptions(null, mockAuthenticator.mOptionsGetAuthToken); 814 815 mockAuthenticator.clearData(); 816 817 // Now test with existing features and an activity 818 resultBundle = getAuthTokenByFeature( 819 new String[] { NON_EXISTING_FEATURE }, 820 ACTIVITY 821 ); 822 823 // Assert returned result 824 validateAccountAndAuthTokenResult(resultBundle); 825 826 validateOptions(OPTIONS_BUNDLE, mockAuthenticator.mOptionsAddAccount); 827 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 828 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 829 validateOptions(null, mockAuthenticator.mOptionsGetAuthToken); 830 831 mockAuthenticator.clearData(); 832 833 // Now test with existing features and no activity 834 resultBundle = getAuthTokenByFeature( 835 REQUIRED_FEATURES, 836 null /* activity */ 837 ); 838 839 // Assert returned result 840 validateAccountAndAuthTokenResult(resultBundle); 841 842 validateOptions(null, mockAuthenticator.mOptionsAddAccount); 843 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 844 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 845 validateOptions(null, mockAuthenticator.mOptionsGetAuthToken); 846 847 mockAuthenticator.clearData(); 848 849 // Now test with existing features and an activity 850 resultBundle = getAuthTokenByFeature( 851 REQUIRED_FEATURES, 852 ACTIVITY 853 ); 854 855 // Assert returned result 856 validateAccountAndAuthTokenResult(resultBundle); 857 858 validateOptions(null, mockAuthenticator.mOptionsAddAccount); 859 validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials); 860 validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials); 861 validateOptions(null, mockAuthenticator.mOptionsGetAuthToken); 862 863 } 864 865 /** 866 * Test confirmCredentials() 867 */ 868 public void testConfirmCredentials() throws IOException, AuthenticatorException, 869 OperationCanceledException { 870 871 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 872 873 AccountManagerFuture<Bundle> futureBundle = am.confirmCredentials(ACCOUNT, 874 OPTIONS_BUNDLE, 875 ACTIVITY, 876 null /* callback*/, 877 null /* handler */); 878 879 futureBundle.getResult(); 880 881 // Assert returned result 882 validateCredentials(); 883 } 884 885 /** 886 * Test confirmCredentials() with callback 887 */ 888 public void testConfirmCredentialsWithCallbackAndHandler() throws IOException, 889 AuthenticatorException, OperationCanceledException { 890 891 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 892 893 testConfirmCredentialsWithCallbackAndHandler(null /* handler */); 894 testConfirmCredentialsWithCallbackAndHandler(new Handler()); 895 } 896 897 private void testConfirmCredentialsWithCallbackAndHandler(Handler handler) throws IOException, 898 AuthenticatorException, OperationCanceledException { 899 900 final CountDownLatch latch = new CountDownLatch(1); 901 902 AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { 903 public void run(AccountManagerFuture<Bundle> bundleFuture) { 904 905 Bundle resultBundle = null; 906 try { 907 resultBundle = bundleFuture.getResult(); 908 909 // Assert returned result 910 validateCredentials(); 911 912 assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN)); 913 } catch (OperationCanceledException e) { 914 fail("should not throw an OperationCanceledException"); 915 } catch (IOException e) { 916 fail("should not throw an IOException"); 917 } catch (AuthenticatorException e) { 918 fail("should not throw an AuthenticatorException"); 919 } 920 finally { 921 latch.countDown(); 922 } 923 } 924 }; 925 926 AccountManagerFuture<Bundle> futureBundle = am.confirmCredentials(ACCOUNT, 927 OPTIONS_BUNDLE, 928 ACTIVITY, 929 callback, 930 handler); 931 932 futureBundle.getResult(); 933 934 // Wait with timeout for the callback to do its work 935 try { 936 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 937 } catch (InterruptedException e) { 938 fail("should not throw an InterruptedException"); 939 } 940 } 941 942 /** 943 * Test updateCredentials() 944 */ 945 public void testUpdateCredentials() throws IOException, AuthenticatorException, 946 OperationCanceledException { 947 948 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 949 950 AccountManagerFuture<Bundle> futureBundle = am.updateCredentials(ACCOUNT, 951 AUTH_TOKEN_TYPE, 952 OPTIONS_BUNDLE, 953 ACTIVITY, 954 null /* callback*/, 955 null /* handler */); 956 957 Bundle result = futureBundle.getResult(); 958 959 validateAccountAndNoAuthTokenResult(result); 960 961 // Assert returned result 962 validateCredentials(); 963 } 964 965 /** 966 * Test updateCredentials() with callback and handler 967 */ 968 public void testUpdateCredentialsWithCallbackAndHandler() throws IOException, 969 AuthenticatorException, OperationCanceledException { 970 971 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 972 973 testUpdateCredentialsWithCallbackAndHandler(null /* handler */); 974 testUpdateCredentialsWithCallbackAndHandler(new Handler()); 975 } 976 977 private void testUpdateCredentialsWithCallbackAndHandler(Handler handler) throws IOException, 978 AuthenticatorException, OperationCanceledException { 979 980 final CountDownLatch latch = new CountDownLatch(1); 981 982 AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { 983 public void run(AccountManagerFuture<Bundle> bundleFuture) { 984 985 Bundle resultBundle = null; 986 try { 987 resultBundle = bundleFuture.getResult(); 988 989 // Assert returned result 990 validateCredentials(); 991 assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN)); 992 993 } catch (OperationCanceledException e) { 994 fail("should not throw an OperationCanceledException"); 995 } catch (IOException e) { 996 fail("should not throw an IOException"); 997 } catch (AuthenticatorException e) { 998 fail("should not throw an AuthenticatorException"); 999 } 1000 finally { 1001 latch.countDown(); 1002 } 1003 } 1004 }; 1005 1006 AccountManagerFuture<Bundle> futureBundle = am.updateCredentials(ACCOUNT, 1007 AUTH_TOKEN_TYPE, 1008 OPTIONS_BUNDLE, 1009 ACTIVITY, 1010 callback, 1011 handler); 1012 1013 futureBundle.getResult(); 1014 1015 // Wait with timeout for the callback to do its work 1016 try { 1017 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1018 } catch (InterruptedException e) { 1019 fail("should not throw an InterruptedException"); 1020 } 1021 } 1022 1023 /** 1024 * Test editProperties() 1025 */ 1026 public void testEditProperties() throws IOException, AuthenticatorException, 1027 OperationCanceledException { 1028 1029 AccountManagerFuture<Bundle> futureBundle = am.editProperties(ACCOUNT_TYPE, 1030 ACTIVITY, 1031 null /* callback */, 1032 null /* handler*/); 1033 1034 Bundle result = futureBundle.getResult(); 1035 1036 validateAccountAndNoAuthTokenResult(result); 1037 1038 // Assert returned result 1039 assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType()); 1040 } 1041 1042 /** 1043 * Test editProperties() with callback and handler 1044 */ 1045 public void testEditPropertiesWithCallbackAndHandler() { 1046 testEditPropertiesWithCallbackAndHandler(null /* handler */); 1047 testEditPropertiesWithCallbackAndHandler(new Handler()); 1048 } 1049 1050 private void testEditPropertiesWithCallbackAndHandler(Handler handler) { 1051 final CountDownLatch latch = new CountDownLatch(1); 1052 1053 AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() { 1054 public void run(AccountManagerFuture<Bundle> bundleFuture) { 1055 try { 1056 // Assert returned result 1057 assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType()); 1058 } 1059 finally { 1060 latch.countDown(); 1061 } 1062 } 1063 }; 1064 1065 AccountManagerFuture<Bundle> futureBundle = am.editProperties(ACCOUNT_TYPE, 1066 ACTIVITY, 1067 callback, 1068 handler); 1069 1070 // Wait with timeout for the callback to do its work 1071 try { 1072 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1073 } catch (InterruptedException e) { 1074 fail("should not throw an InterruptedException"); 1075 } 1076 } 1077 1078 /** 1079 * Test addOnAccountsUpdatedListener() with handler 1080 */ 1081 public void testAddOnAccountsUpdatedListenerWithHandler() throws IOException, 1082 AuthenticatorException, OperationCanceledException { 1083 1084 testAddOnAccountsUpdatedListenerWithHandler(null /* handler */, 1085 false /* updateImmediately */); 1086 1087 // Need to cleanup intermediate state 1088 assertTrue(removeAccount(am, ACCOUNT, null /* callback */)); 1089 1090 testAddOnAccountsUpdatedListenerWithHandler(null /* handler */, 1091 true /* updateImmediately */); 1092 1093 // Need to cleanup intermediate state 1094 assertTrue(removeAccount(am, ACCOUNT, null /* callback */)); 1095 1096 testAddOnAccountsUpdatedListenerWithHandler(new Handler(), 1097 false /* updateImmediately */); 1098 1099 // Need to cleanup intermediate state 1100 assertTrue(removeAccount(am, ACCOUNT, null /* callback */)); 1101 1102 testAddOnAccountsUpdatedListenerWithHandler(new Handler(), 1103 true /* updateImmediately */); 1104 } 1105 1106 private void testAddOnAccountsUpdatedListenerWithHandler(Handler handler, 1107 boolean updateImmediately) { 1108 1109 final CountDownLatch latch = new CountDownLatch(1); 1110 1111 OnAccountsUpdateListener listener = new OnAccountsUpdateListener() { 1112 public void onAccountsUpdated(Account[] accounts) { 1113 latch.countDown(); 1114 } 1115 }; 1116 1117 // Add a listener 1118 am.addOnAccountsUpdatedListener(listener, 1119 handler, 1120 updateImmediately); 1121 1122 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 1123 1124 // Wait with timeout for the callback to do its work 1125 try { 1126 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1127 } catch (InterruptedException e) { 1128 fail("should not throw an InterruptedException"); 1129 } 1130 1131 // Cleanup 1132 am.removeOnAccountsUpdatedListener(listener); 1133 } 1134 1135 /** 1136 * Test removeOnAccountsUpdatedListener() with handler 1137 */ 1138 public void testRemoveOnAccountsUpdatedListener() throws IOException, AuthenticatorException, 1139 OperationCanceledException { 1140 1141 testRemoveOnAccountsUpdatedListenerWithHandler(null /* handler */); 1142 1143 // Need to cleanup intermediate state 1144 assertTrue(removeAccount(am, ACCOUNT, null /* callback */)); 1145 1146 testRemoveOnAccountsUpdatedListenerWithHandler(new Handler()); 1147 } 1148 1149 private void testRemoveOnAccountsUpdatedListenerWithHandler(Handler handler) { 1150 final CountDownLatch latch = new CountDownLatch(1); 1151 1152 OnAccountsUpdateListener listener = new OnAccountsUpdateListener() { 1153 public void onAccountsUpdated(Account[] accounts) { 1154 fail("should not be called"); 1155 } 1156 }; 1157 1158 // First add a listener 1159 am.addOnAccountsUpdatedListener(listener, 1160 handler, 1161 false /* updateImmediately */); 1162 1163 // Then remove the listener 1164 am.removeOnAccountsUpdatedListener(listener); 1165 1166 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 1167 1168 // Wait with timeout for the callback to do its work 1169 try { 1170 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1171 } catch (InterruptedException e) { 1172 fail("should not throw an InterruptedException"); 1173 } 1174 } 1175 1176 /** 1177 * Test hasFeature 1178 */ 1179 public void testHasFeature() 1180 throws IOException, AuthenticatorException, OperationCanceledException { 1181 1182 assertHasFeature(null /* handler */); 1183 assertHasFeature(new Handler()); 1184 1185 assertHasFeatureWithCallback(null /* handler */); 1186 assertHasFeatureWithCallback(new Handler()); 1187 } 1188 1189 private void assertHasFeature(Handler handler) 1190 throws IOException, AuthenticatorException, OperationCanceledException { 1191 Bundle resultBundle = addAccount(am, 1192 ACCOUNT_TYPE, 1193 AUTH_TOKEN_TYPE, 1194 REQUIRED_FEATURES, 1195 OPTIONS_BUNDLE, 1196 ACTIVITY, 1197 null /* callback */, 1198 null /* handler */); 1199 1200 // Assert parameters has been passed correctly 1201 validateAccountAndAuthTokenType(); 1202 validateFeatures(); 1203 1204 AccountManagerFuture<Boolean> booleanFuture = am.hasFeatures(ACCOUNT, 1205 new String[]{FEATURE_1}, 1206 null /* callback */, 1207 handler); 1208 assertTrue(booleanFuture.getResult()); 1209 1210 booleanFuture = am.hasFeatures(ACCOUNT, 1211 new String[]{FEATURE_2}, 1212 null /* callback */, 1213 handler); 1214 assertTrue(booleanFuture.getResult()); 1215 1216 booleanFuture = am.hasFeatures(ACCOUNT, 1217 new String[]{FEATURE_1, FEATURE_2}, 1218 null /* callback */, 1219 handler); 1220 assertTrue(booleanFuture.getResult()); 1221 1222 booleanFuture = am.hasFeatures(ACCOUNT, 1223 new String[]{NON_EXISTING_FEATURE}, 1224 null /* callback */, 1225 handler); 1226 assertFalse(booleanFuture.getResult()); 1227 1228 booleanFuture = am.hasFeatures(ACCOUNT, 1229 new String[]{NON_EXISTING_FEATURE, FEATURE_1}, 1230 null /* callback */, 1231 handler); 1232 assertFalse(booleanFuture.getResult()); 1233 1234 booleanFuture = am.hasFeatures(ACCOUNT, 1235 new String[]{NON_EXISTING_FEATURE, FEATURE_1, FEATURE_2}, 1236 null /* callback */, 1237 handler); 1238 assertFalse(booleanFuture.getResult()); 1239 } 1240 1241 private AccountManagerCallback<Boolean> getAssertTrueCallback(final CountDownLatch latch) { 1242 return new AccountManagerCallback<Boolean>() { 1243 public void run(AccountManagerFuture<Boolean> booleanFuture) { 1244 try { 1245 // Assert returned result should be TRUE 1246 assertTrue(booleanFuture.getResult()); 1247 } catch (Exception e) { 1248 fail("Exception: " + e); 1249 } finally { 1250 latch.countDown(); 1251 } 1252 } 1253 }; 1254 } 1255 1256 private AccountManagerCallback<Boolean> getAssertFalseCallback(final CountDownLatch latch) { 1257 return new AccountManagerCallback<Boolean>() { 1258 public void run(AccountManagerFuture<Boolean> booleanFuture) { 1259 try { 1260 // Assert returned result should be FALSE 1261 assertFalse(booleanFuture.getResult()); 1262 } catch (Exception e) { 1263 fail("Exception: " + e); 1264 } finally { 1265 latch.countDown(); 1266 } 1267 } 1268 }; 1269 } 1270 1271 private void waitForLatch(final CountDownLatch latch) { 1272 // Wait with timeout for the callback to do its work 1273 try { 1274 latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS); 1275 } catch (InterruptedException e) { 1276 fail("should not throw an InterruptedException"); 1277 } 1278 } 1279 1280 private void assertHasFeatureWithCallback(Handler handler) 1281 throws IOException, AuthenticatorException, OperationCanceledException { 1282 Bundle resultBundle = addAccount(am, 1283 ACCOUNT_TYPE, 1284 AUTH_TOKEN_TYPE, 1285 REQUIRED_FEATURES, 1286 OPTIONS_BUNDLE, 1287 ACTIVITY, 1288 null /* callback */, 1289 null /* handler */); 1290 1291 // Assert parameters has been passed correctly 1292 validateAccountAndAuthTokenType(); 1293 validateFeatures(); 1294 1295 CountDownLatch latch = new CountDownLatch(1); 1296 am.hasFeatures(ACCOUNT, 1297 new String[]{FEATURE_1}, 1298 getAssertTrueCallback(latch), 1299 handler); 1300 waitForLatch(latch); 1301 1302 latch = new CountDownLatch(1); 1303 am.hasFeatures(ACCOUNT, 1304 new String[]{FEATURE_2}, 1305 getAssertTrueCallback(latch), 1306 handler); 1307 waitForLatch(latch); 1308 1309 latch = new CountDownLatch(1); 1310 am.hasFeatures(ACCOUNT, 1311 new String[]{FEATURE_1, FEATURE_2}, 1312 getAssertTrueCallback(latch), 1313 handler); 1314 waitForLatch(latch); 1315 1316 latch = new CountDownLatch(1); 1317 am.hasFeatures(ACCOUNT, 1318 new String[]{NON_EXISTING_FEATURE}, 1319 getAssertFalseCallback(latch), 1320 handler); 1321 waitForLatch(latch); 1322 1323 latch = new CountDownLatch(1); 1324 am.hasFeatures(ACCOUNT, 1325 new String[]{NON_EXISTING_FEATURE, FEATURE_1}, 1326 getAssertFalseCallback(latch), 1327 handler); 1328 waitForLatch(latch); 1329 1330 latch = new CountDownLatch(1); 1331 am.hasFeatures(ACCOUNT, 1332 new String[]{NON_EXISTING_FEATURE, FEATURE_1, FEATURE_2}, 1333 getAssertFalseCallback(latch), 1334 handler); 1335 waitForLatch(latch); 1336 } 1337 1338 /** 1339 * Tests that AccountManagerService is properly caching data. 1340 */ 1341 public void testGetsAreCached() throws IOException, AuthenticatorException, 1342 OperationCanceledException { 1343 1344 // Add an account, 1345 assertEquals(false, isAccountPresent(am.getAccounts(), ACCOUNT)); 1346 addAccountExplicitly(ACCOUNT, ACCOUNT_PASSWORD, null /* userData */); 1347 1348 // Then verify that we don't hit disk retrieving it, 1349 StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); 1350 try { 1351 StrictMode.setThreadPolicy( 1352 new StrictMode.ThreadPolicy.Builder().detectDiskReads().penaltyDeath().build()); 1353 Account[] accounts = am.getAccounts(); 1354 assertNotNull(accounts); 1355 assertTrue(accounts.length > 0); 1356 } finally { 1357 StrictMode.setThreadPolicy(oldPolicy); 1358 } 1359 } 1360 1361 } 1362