+ * 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
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);