
org.robolectric.shadows.ShadowAccountManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of framework Show documentation
Show all versions of framework Show documentation
An alternative Android testing framework.
The newest version!
package org.robolectric.shadows;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
import android.accounts.*;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.util.Scheduler.IdleState;
@Implements(AccountManager.class)
public class ShadowAccountManager {
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 Map> accountFeatures = new HashMap<>();
private Map> packageVisibileAccounts = new HashMap<>();
private List addAccountOptionsList = new ArrayList<>();
private Handler mainHandler;
private RoboAccountManagerFuture pendingAddFuture;
public void __constructor__(Context context, IAccountManager service) {
mainHandler = new Handler(context.getMainLooper());
}
/**
* @deprecated This method will be removed in Robolectric 3.4 Use {@link AccountManager#get(Context)} instead.
*/
@Deprecated
@Implementation
public static AccountManager get(Context context) {
return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
}
@Implementation
public Account[] getAccounts() {
return accounts.toArray(new Account[accounts.size()]);
}
@Implementation
public Account[] getAccountsByType(String type) {
if (type == null) {
return getAccounts();
}
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);
}
/**
* The remove operation is posted to the given {@code handler}, and will be
* executed according to the {@link IdleState} of the corresponding {@link org.robolectric.util.Scheduler}.
*/
@Implementation
public AccountManagerFuture removeAccount(final Account account,
AccountManagerCallback callback,
Handler handler) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
return start(
new BaseRoboAccountManagerFuture(callback, handler) {
@Override
public Boolean doWork()
throws OperationCanceledException, IOException, AuthenticatorException {
return removeAccountExplicitly(account);
}
});
}
@Implementation(minSdk = LOLLIPOP_MR1)
public boolean removeAccountExplicitly(Account account) {
passwords.remove(account);
userData.remove(account);
return accounts.remove(account);
}
/**
* Removes all accounts that have been added.
*/
public void removeAllAccounts() {
passwords.clear();
userData.clear();
accounts.clear();
}
@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 void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
listeners.remove(listener);
}
@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);
}
}
/**
* @param account User account.
*/
public void addAccount(Account account) {
accounts.add(account);
if (pendingAddFuture != null) {
pendingAddFuture.resultBundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
start(pendingAddFuture);
pendingAddFuture = null;
}
notifyListeners();
}
/**
* Adds an account to the AccountManager but when {@link AccountManager#getAccountsByTypeForPackage(String, String)}
* is called will be included if is in one of the #visibileToPackages
*
* @param account User account.
*/
public void addAccount(Account account, String... visibileToPackages) {
addAccount(account);
HashSet value = new HashSet<>();
Collections.addAll(value, visibileToPackages);
packageVisibileAccounts.put(account, value);
}
/**
* Consumes and returns the next {@code addAccountOptions} passed to {@link #addAccount}.
*
* @return the next {@code addAccountOptions}
*/
public Bundle getNextAddAccountOptions() {
if (addAccountOptionsList.isEmpty()) {
return null;
} else {
return addAccountOptionsList.remove(0);
}
}
/**
* Returns the next {@code addAccountOptions} passed to {@link #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 extends BaseRoboAccountManagerFuture {
private final String accountType;
private final Activity activity;
private final Bundle resultBundle;
RoboAccountManagerFuture(AccountManagerCallback callback, Handler handler, String accountType, Activity activity) {
super(callback, handler);
this.accountType = accountType;
this.activity = activity;
this.resultBundle = new Bundle();
}
@Override
public Bundle doWork() throws OperationCanceledException, IOException, AuthenticatorException {
if (!authenticators.containsKey(accountType)) {
throw new AuthenticatorException("No authenticator specified for " + accountType);
}
resultBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, accountType);
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]");
}
return resultBundle;
}
}
@Implementation
public AccountManagerFuture addAccount(final String accountType, String authTokenType, String[] requiredFeatures, Bundle addAccountOptions, Activity activity, AccountManagerCallback callback, Handler handler) {
addAccountOptionsList.add(addAccountOptions);
pendingAddFuture = new RoboAccountManagerFuture(callback, handler, accountType, activity);
return pendingAddFuture;
}
public void setFeatures(Account account, String[] accountFeatures) {
HashSet featureSet = new HashSet<>();
featureSet.addAll(Arrays.asList(accountFeatures));
this.accountFeatures.put(account, featureSet);
}
/**
* @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();
/**
* Sets the previous name for an account, which will be returned by {@link AccountManager#getPreviousName(Account)}.
*
* @param account User account.
* @param previousName Previous account name.
*/
public void setPreviousAccountName(Account account, String previousName) {
previousNames.put(account, previousName);
}
/**
* @see #setPreviousAccountName(Account, String)
*/
@Implementation(minSdk = LOLLIPOP)
public String getPreviousName(Account account) {
return previousNames.get(account);
}
@Implementation
public AccountManagerFuture getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final Activity activity, final AccountManagerCallback callback, Handler handler) {
return start(new BaseRoboAccountManagerFuture(callback, handler) {
@Override
public Bundle doWork() throws OperationCanceledException, IOException, AuthenticatorException {
Bundle result = new Bundle();
String authToken = blockingGetAuthToken(account, authTokenType, false);
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
return result;
}
});
}
@Implementation
public AccountManagerFuture hasFeatures(final Account account,
final String[] features,
AccountManagerCallback callback, Handler handler) {
return start(new BaseRoboAccountManagerFuture(callback, handler) {
@Override
public Boolean doWork() throws OperationCanceledException, IOException, AuthenticatorException {
Set availableFeatures = accountFeatures.get(account);
for (String feature : features) {
if (!availableFeatures.contains(feature)) {
return false;
}
}
return true;
}
});
}
@Implementation
public AccountManagerFuture getAccountsByTypeAndFeatures(
final String type, final String[] features,
AccountManagerCallback callback, Handler handler) {
return start(new BaseRoboAccountManagerFuture(callback, handler) {
@Override
public Account[] doWork() throws OperationCanceledException, IOException, AuthenticatorException {
List result = new LinkedList<>();
Account[] accountsByType = getAccountsByType(type);
for (Account account : accountsByType) {
Set featureSet = accountFeatures.get(account);
if (featureSet.containsAll(Arrays.asList(features))) {
result.add(account);
}
}
return result.toArray(new Account[result.size()]);
}
});
}
private T start(T future) {
future.start();
return future;
}
@Implementation(minSdk = JELLY_BEAN_MR2)
public Account[] getAccountsByTypeForPackage (String type, String packageName) {
List result = new LinkedList<>();
Account[] accountsByType = getAccountsByType(type);
for (Account account : accountsByType) {
if (packageVisibileAccounts.containsKey(account) && packageVisibileAccounts.get(account).contains(packageName)) {
result.add(account);
}
}
return result.toArray(new Account[result.size()]);
}
private abstract class BaseRoboAccountManagerFuture implements AccountManagerFuture {
protected final AccountManagerCallback callback;
private final Handler handler;
protected T result;
private Exception exception;
private boolean started = false;
BaseRoboAccountManagerFuture(AccountManagerCallback callback, Handler handler) {
this.callback = callback;
this.handler = handler == null ? mainHandler : handler;
}
void start() {
if (started) return;
started = true;
try {
result = doWork();
} catch (OperationCanceledException | IOException | AuthenticatorException e) {
exception = e;
}
if (callback != null) {
handler.post(
new Runnable() {
@Override
public void run() {
callback.run(BaseRoboAccountManagerFuture.this);
}
});
}
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isDone() {
return result != null;
}
@Override
public T getResult() throws OperationCanceledException, IOException, AuthenticatorException {
start();
if (exception instanceof OperationCanceledException) {
throw new OperationCanceledException(exception);
} else if (exception instanceof IOException) {
throw new IOException(exception);
} else if (exception instanceof AuthenticatorException) {
throw new AuthenticatorException(exception);
}
return result;
}
@Override
public T getResult(long timeout, TimeUnit unit) throws OperationCanceledException, IOException, AuthenticatorException {
return getResult();
}
public abstract T doWork() throws OperationCanceledException, IOException, AuthenticatorException;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy