Home | History | Annotate | Download | only in cts
      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