org.robolectric.shadows.ShadowAccountManager Maven / Gradle / Ivy
package org.robolectric.shadows;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorDescription;
import android.accounts.AuthenticatorException;
import android.accounts.OnAccountsUpdateListener;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.robolectric.internal.Shadow;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
/**
* Shadow for {@link android.accounts.AccountManager}.
*/
@Implements(AccountManager.class)
public class ShadowAccountManager {
private static final Object lock = new Object();
private static AccountManager instance;
private List accounts = new ArrayList();
private Map> authTokens = new HashMap>();
private Map authenticators = new LinkedHashMap();
private List listeners = new ArrayList();
private Map> userData = new HashMap>();
private Map passwords = new HashMap();
private AccountManagerCallback pendingAddCallback;
private RoboAccountManagerFuture pendingAddFuture;
private List addAccountOptionsList = new ArrayList();
@Resetter
public static void reset() {
synchronized (lock) {
instance = null;
}
}
@Implementation
public static AccountManager get(Context context) {
synchronized (lock) {
if (instance == null) {
instance = Shadow.newInstanceOf(AccountManager.class);
}
return instance;
}
}
@Implementation
public Account[] getAccounts() {
return accounts.toArray(new Account[accounts.size()]);
}
@Implementation
public Account[] getAccountsByType(String type) {
List accountsByType = new ArrayList();
for (Account a : accounts) {
if (type.equals(a.type)) {
accountsByType.add(a);
}
}
return accountsByType.toArray(new Account[accountsByType.size()]);
}
@Implementation
public synchronized void setAuthToken(Account account, String tokenType, String authToken) {
if(accounts.contains(account)) {
Map tokenMap = authTokens.get(account);
if(tokenMap == null) {
tokenMap = new HashMap();
authTokens.put(account, tokenMap);
}
tokenMap.put(tokenType, authToken);
}
}
@Implementation
public String peekAuthToken(Account account, String tokenType) {
Map tokenMap = authTokens.get(account);
if(tokenMap != null) {
return tokenMap.get(tokenType);
}
return null;
}
@Implementation
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
for (Account a: getAccountsByType(account.type)) {
if (a.name.equals(account.name)) {
return false;
}
}
if (!accounts.add(account)) {
return false;
}
setPassword(account, password);
if(userdata != null) {
for (String key : userdata.keySet()) {
setUserData(account, key, userdata.get(key).toString());
}
}
return true;
}
@Implementation
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
if (authTokenType == null) {
throw new IllegalArgumentException("authTokenType is null");
}
Map tokensForAccount = authTokens.get(account);
if (tokensForAccount == null) {
return null;
}
return tokensForAccount.get(authTokenType);
}
@Implementation
public AccountManagerFuture removeAccount (final Account account,
AccountManagerCallback callback,
Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
final boolean accountRemoved = accounts.remove(account);
passwords.remove(account);
userData.remove(account);
return new AccountManagerFuture() {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return false;
}
@Override
public Boolean getResult() throws OperationCanceledException, IOException,
AuthenticatorException {
return accountRemoved;
}
@Override
public Boolean getResult(long timeout, TimeUnit unit) throws OperationCanceledException,
IOException, AuthenticatorException {
return accountRemoved;
}
};
}
@Implementation
public AuthenticatorDescription[] getAuthenticatorTypes() {
return authenticators.values().toArray(new AuthenticatorDescription[authenticators.size()]);
}
@Implementation
public void addOnAccountsUpdatedListener(final OnAccountsUpdateListener listener,
Handler handler, boolean updateImmediately) {
if (listeners.contains(listener)) {
return;
}
listeners.add(listener);
if (updateImmediately) {
listener.onAccountsUpdated(getAccounts());
}
}
@Implementation
public String getUserData(Account account, String key) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
if (!userData.containsKey(account)) {
return null;
}
Map userDataMap = userData.get(account);
if (userDataMap.containsKey(key)) {
return userDataMap.get(key);
}
return null;
}
@Implementation
public void setUserData(Account account, String key, String value) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
if (!userData.containsKey(account)) {
userData.put(account, new HashMap());
}
Map userDataMap = userData.get(account);
if (value == null) {
userDataMap.remove(key);
} else {
userDataMap.put(key, value);
}
}
@Implementation
public void setPassword (Account account, String password) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
if (password == null) {
passwords.remove(account);
} else {
passwords.put(account, password);
}
}
@Implementation
public String getPassword (Account account) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
if (passwords.containsKey(account)) {
return passwords.get(account);
} else {
return null;
}
}
@Implementation
public void invalidateAuthToken(final String accountType, final String authToken) {
Account[] accountsByType = getAccountsByType(accountType);
for (Account account : accountsByType) {
Map tokenMap = authTokens.get(account);
if (tokenMap != null) {
Iterator> it = tokenMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry map = it.next();
if (map.getValue().equals(authToken)) {
it.remove();
}
}
authTokens.put(account, tokenMap);
}
}
}
private void notifyListeners() {
Account[] accounts = getAccounts();
Iterator iter = listeners.iterator();
OnAccountsUpdateListener listener;
while (iter.hasNext()) {
listener = iter.next();
listener.onAccountsUpdated(accounts);
}
}
/**
* Non-android accessor.
*
* @param account User account.
*/
public void addAccount(Account account) {
accounts.add(account);
if (pendingAddCallback != null) {
pendingAddFuture.resultBundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
pendingAddCallback.run(pendingAddFuture);
}
notifyListeners();
}
/**
* Non-Android accessor consumes and returns the next {@code addAccountOptions} passed to addAccount.
*
* @return the next {@code addAccountOptions}
*/
public Bundle getNextAddAccountOptions() {
if (addAccountOptionsList.isEmpty()) {
return null;
} else {
return addAccountOptionsList.remove(0);
}
}
/**
* Non-Android accessor returns the next {@code addAccountOptions} passed to addAccount without consuming it.
*
* @return the next {@code addAccountOptions}
*/
public Bundle peekNextAddAccountOptions() {
if (addAccountOptionsList.isEmpty()) {
return null;
} else {
return addAccountOptionsList.get(0);
}
}
private class RoboAccountManagerFuture implements AccountManagerFuture {
private final String accountType;
final Bundle resultBundle;
public RoboAccountManagerFuture(String accountType, Bundle resultBundle) {
this.accountType = accountType;
this.resultBundle = resultBundle;
}
@Override
public boolean cancel(boolean b) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return resultBundle.containsKey(AccountManager.KEY_ACCOUNT_NAME);
}
@Override
public Bundle getResult() throws OperationCanceledException, IOException, AuthenticatorException {
if (!authenticators.containsKey(accountType)) {
throw new AuthenticatorException("No authenticator specified for " + accountType);
}
resultBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
return resultBundle;
}
@Override
public Bundle getResult(long l, TimeUnit timeUnit) throws OperationCanceledException, IOException, AuthenticatorException {
if (!authenticators.containsKey(accountType)) {
throw new AuthenticatorException("No authenticator specified for " + accountType);
}
return resultBundle;
}
}
@Implementation
public AccountManagerFuture addAccount(final String accountType, String authTokenType, String[] requiredFeatures, Bundle addAccountOptions, Activity activity, AccountManagerCallback callback, Handler handler) {
final Bundle resultBundle = new Bundle();
if (activity == null) {
Intent resultIntent = new Intent();
resultBundle.putParcelable(AccountManager.KEY_INTENT, resultIntent);
} else if (callback == null) {
resultBundle.putString(AccountManager.KEY_ACCOUNT_NAME, "[email protected]");
}
addAccountOptionsList.add(addAccountOptions);
pendingAddCallback = callback;
pendingAddFuture = new RoboAccountManagerFuture(accountType, resultBundle);
return pendingAddFuture;
}
/**
* Non-android accessor.
*
* @param authenticator System authenticator.
*/
public void addAuthenticator(AuthenticatorDescription authenticator) {
authenticators.put(authenticator.type, authenticator);
}
public void addAuthenticator(String type) {
addAuthenticator(AuthenticatorDescription.newKey(type));
}
private Map previousNames = new HashMap();
/**
* Non-android accessor.
*
* @param account User account.
* @param previousName Previous account name.
*/
public void setPreviousAccountName(Account account, String previousName) {
previousNames.put(account, previousName);
}
@Implementation
public String getPreviousName(Account account) {
return previousNames.get(account);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy