1 package com.xtremelabs.robolectric.shadows; 2 3 import android.accounts.Account; 4 import android.accounts.AccountManager; 5 import android.accounts.AccountManagerCallback; 6 import android.accounts.AccountManagerFuture; 7 import android.accounts.AuthenticatorException; 8 import android.accounts.OperationCanceledException; 9 import android.app.Activity; 10 import android.content.Context; 11 import android.os.Bundle; 12 import android.os.Handler; 13 14 import com.xtremelabs.robolectric.Robolectric; 15 import com.xtremelabs.robolectric.internal.Implementation; 16 import com.xtremelabs.robolectric.internal.Implements; 17 import com.xtremelabs.robolectric.internal.RealObject; 18 19 import java.io.IOException; 20 import java.util.*; 21 import java.util.concurrent.TimeUnit; 22 23 import static com.xtremelabs.robolectric.Robolectric.newInstanceOf; 24 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 25 26 /** 27 * Shadows the {@code android.accounts.AccountManager} class. 28 */ 29 @SuppressWarnings({"UnusedDeclaration"}) 30 @Implements(AccountManager.class) 31 public class ShadowAccountManager { 32 33 public static final String AUTH_TOKEN_VALUE = "authToken"; 34 35 private static AccountManager singleton; 36 37 private Account[] accounts; 38 private HashMap<Account, HashMap<String, String>> cachedAuthTokenValues = 39 new HashMap<Account, HashMap<String, String>>(); 40 41 @Implementation get(Context context)42 public static AccountManager get(Context context) { 43 if (singleton == null) { 44 singleton = Robolectric.newInstanceOf(AccountManager.class); 45 } 46 return singleton; 47 } 48 49 @Implementation getAuthToken(Account account, String authTokenType, Bundle options, Activity activity, AccountManagerCallback<Bundle> callback, Handler handler)50 public AccountManagerFuture<Bundle> getAuthToken(Account account, String authTokenType, Bundle options, Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { 51 //TODO: Add complete activity to perform the account intent dance. 52 final Account finalAccount = account; 53 return new AccountManagerFuture<Bundle>() { 54 55 private boolean isFutureCancelled; 56 private boolean isFutureDone; 57 58 @Override 59 public boolean cancel(boolean mayInterruptIfRunning) { 60 if (isFutureDone) { 61 return false; 62 } 63 isFutureCancelled = true; 64 return isCancelled(); 65 } 66 67 @Override 68 public Bundle getResult(long timeout, TimeUnit unit) throws OperationCanceledException, 69 AuthenticatorException, IOException { 70 Bundle result = new Bundle(); 71 if (!isCancelled()) { 72 addBundleResults(result, finalAccount); 73 isFutureDone = true; 74 } 75 return result; 76 } 77 78 @Override 79 public Bundle getResult() throws OperationCanceledException, 80 AuthenticatorException, IOException { 81 Bundle result = new Bundle(); 82 if (!isCancelled()) { 83 addBundleResults(result, finalAccount); 84 isFutureDone = true; 85 } 86 return result; 87 } 88 89 @Override 90 public boolean isCancelled() { 91 return isFutureCancelled; 92 } 93 94 @Override 95 public boolean isDone() { 96 return isFutureDone || isFutureCancelled; 97 } 98 99 private void addBundleResults(Bundle bundle, final Account account) { 100 bundle.putString(AccountManager.KEY_AUTHTOKEN, AUTH_TOKEN_VALUE); 101 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); 102 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); 103 } 104 }; 105 } 106 107 @Implementation getAuthTokenByFeatures(String accountType, String authTokenType, String[] features, Activity activity, Bundle addAccountOptions, Bundle getAuthTokenOptions, AccountManagerCallback<Bundle> callback, Handler handler)108 public AccountManagerFuture<Bundle> getAuthTokenByFeatures(String accountType, String authTokenType, String[] features, Activity activity, Bundle addAccountOptions, Bundle getAuthTokenOptions, AccountManagerCallback<Bundle> callback, Handler handler) { 109 //TODO: Add complete activity to perform the account intent dance. 110 final String finalAccountType = accountType; 111 return new AccountManagerFuture<Bundle>() { 112 113 private boolean isFutureCancelled; 114 private boolean isFutureDone; 115 116 @Override 117 public boolean cancel(boolean mayInterruptIfRunning) { 118 if (isFutureDone) { 119 return false; 120 } 121 isFutureCancelled = true; 122 return isCancelled(); 123 } 124 125 @Override 126 public Bundle getResult(long timeout, TimeUnit unit) throws OperationCanceledException, 127 AuthenticatorException, IOException { 128 Bundle result = new Bundle(); 129 if (!isCancelled()) { 130 addBundleResults(result, finalAccountType); 131 isFutureDone = true; 132 } 133 return result; 134 } 135 136 @Override 137 public Bundle getResult() throws OperationCanceledException, 138 AuthenticatorException, IOException { 139 Bundle result = new Bundle(); 140 if (!isCancelled()) { 141 addBundleResults(result, finalAccountType); 142 isFutureDone = true; 143 } 144 return result; 145 } 146 147 @Override 148 public boolean isCancelled() { 149 return isFutureCancelled; 150 } 151 152 @Override 153 public boolean isDone() { 154 return isFutureDone || isFutureCancelled; 155 } 156 157 private void addBundleResults(Bundle bundle, final String accountType) { 158 bundle.putString(AccountManager.KEY_AUTHTOKEN, AUTH_TOKEN_VALUE); 159 bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType); 160 bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "accountName"); 161 } 162 }; 163 } 164 165 @Implementation 166 public void invalidateAuthToken(String accountType, String authToken) {} 167 168 @Implementation 169 public Account[] getAccounts() { 170 return getAccountsByType(null); 171 } 172 173 @Implementation 174 public Account[] getAccountsByType(String accountType) { 175 if (accountType == null) { 176 return accounts; 177 } 178 179 ArrayList<Account> accountList = new ArrayList<Account>(); 180 if (accounts != null) { 181 for (Account account : accounts) { 182 if (accountType.equals(account.type)) { 183 accountList.add(account); 184 } 185 } 186 } 187 return accountList.toArray(new Account[accountList.size()]); 188 } 189 190 @Implementation 191 public String peekAuthToken(Account account, String authTokenType) { 192 HashMap<String, String> tokens = cachedAuthTokenValues.get(account); 193 return (tokens != null) ? tokens.get(authTokenType) : null; 194 } 195 196 public void setCachedAuthToken(Account account, String authTokenType, String authTokenValue) { 197 if (!cachedAuthTokenValues.containsKey(account)) { 198 cachedAuthTokenValues.put(account, new HashMap<String, String>()); 199 } 200 cachedAuthTokenValues.get(account).put(authTokenType, authTokenValue); 201 } 202 203 public void setAccounts(Account[] accounts) { 204 this.accounts = accounts; 205 } 206 } 207