diff --git a/api/current.xml b/api/current.xml index f3e614a11db64..113b9e0c53325 100644 --- a/api/current.xml +++ b/api/current.xml @@ -14690,6 +14690,25 @@ + + + + + + + + + + + * This call returns immediately but runs asynchronously and the result is accessed via the + * {@link AccountManagerFuture} that is returned. This future is also passed as the sole + * parameter to the {@link AccountManagerCallback}. If the caller wished to use this + * method asynchronously then they will generally pass in a callback object that will get + * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then + * they will generally pass null for the callback and instead call + * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value, + * which will then block until the request completes. + *

+ * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}. + * + * @param account The {@link Account} to test + * @param features the features for which to test + * @param callback A callback to invoke when the request completes. If null then + * no callback is invoked. + * @param handler The {@link Handler} to use to invoke the callback. If null then the + * main thread's {@link Handler} is used. + * @return an {@link AccountManagerFuture} that represents the future result of the call. + * The future result is a {@link Boolean} that is true if the account exists and has the + * specified features. + */ + public AccountManagerFuture testHasFeatures(final Account account, + final String[] features, + AccountManagerCallback callback, Handler handler) { + return new Future2Task(handler, callback) { + public void doWork() throws RemoteException { + mService.testHasFeatures(mResponse, account, features); + } + public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException { + if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) { + throw new AuthenticatorException("no result in response"); + } + return bundle.getBoolean(KEY_BOOLEAN_RESULT); + } + }.start(); + } + /** * Add an account to the AccountManager's set of known accounts. *

diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java index d5a9b0215ac09..f5166c292f0a6 100644 --- a/core/java/android/accounts/AccountManagerService.java +++ b/core/java/android/accounts/AccountManagerService.java @@ -449,6 +449,64 @@ public class AccountManagerService return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values); } + public void testHasFeatures(IAccountManagerResponse response, + Account account, String[] features) { + checkReadAccountsPermission(); + long identityToken = clearCallingIdentity(); + try { + new TestFeaturesSession(response, account, features).bind(); + } finally { + restoreCallingIdentity(identityToken); + } + } + + private class TestFeaturesSession extends Session { + private final String[] mFeatures; + private final Account mAccount; + + public TestFeaturesSession(IAccountManagerResponse response, + Account account, String[] features) { + super(response, account.type, false /* expectActivityLaunch */); + mFeatures = features; + mAccount = account; + } + + public void run() throws RemoteException { + try { + mAuthenticator.hasFeatures(this, mAccount, mFeatures); + } catch (RemoteException e) { + onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception"); + } + } + + public void onResult(Bundle result) { + IAccountManagerResponse response = getResponseAndClose(); + if (response != null) { + try { + if (result == null) { + onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle"); + return; + } + final Bundle newResult = new Bundle(); + newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, + result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)); + response.onResult(newResult); + } catch (RemoteException e) { + // if the caller is dead then there is no one to care about remote exceptions + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.v(TAG, "failure while notifying response", e); + } + } + } + } + + protected String toDebugString(long now) { + return super.toDebugString(now) + ", testHasFeatures" + + ", " + mAccount + + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null); + } + } + public void removeAccount(IAccountManagerResponse response, Account account) { checkManageAccountsPermission(); long identityToken = clearCallingIdentity(); diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 0e318c051ff45..cbd26eebd92f9 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -31,6 +31,8 @@ interface IAccountManager { String getUserData(in Account account, String key); AuthenticatorDescription[] getAuthenticatorTypes(); Account[] getAccounts(String accountType); + void testHasFeatures(in IAccountManagerResponse response, in Account account, + in String[] features); void getAccountsByFeatures(in IAccountManagerResponse response, String accountType, in String[] features); boolean addAccount(in Account account, String password, in Bundle extras); void removeAccount(in IAccountManagerResponse response, in Account account);