diff options
| author | 2015-11-21 01:05:06 +0000 | |
|---|---|---|
| committer | 2015-11-21 01:05:06 +0000 | |
| commit | 4657518dcff80c7673d09787cf6a72f5be64db1c (patch) | |
| tree | 7a5121c0bca4d914aff1e41ef845908954e25787 | |
| parent | 05a80089aef2b5868e2fd8ae428485cb2660997c (diff) | |
| parent | e68c37eead0b7255d307af91ca284eaee419c944 (diff) | |
Merge "AccountManager: add startUpdateCredentials API."
| -rw-r--r-- | api/current.txt | 2 | ||||
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | core/java/android/accounts/AbstractAccountAuthenticator.java | 95 | ||||
| -rw-r--r-- | core/java/android/accounts/AccountManager.java | 96 | ||||
| -rw-r--r-- | core/java/android/accounts/IAccountAuthenticator.aidl | 6 | ||||
| -rw-r--r-- | core/java/android/accounts/IAccountManager.aidl | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/accounts/AccountManagerService.java | 61 | 
7 files changed, 254 insertions, 11 deletions
diff --git a/api/current.txt b/api/current.txt index 5048788cd556..2f5686e3ad15 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2734,6 +2734,7 @@ package android.accounts {      method public final android.os.IBinder getIBinder();      method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;      method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException; +    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;      method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;      field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";    } @@ -2799,6 +2800,7 @@ package android.accounts {      method public void setPassword(android.accounts.Account, java.lang.String);      method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);      method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler); +    method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);      method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);      field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";      field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator"; diff --git a/api/system-current.txt b/api/system-current.txt index ae0ac0ce7b0c..cbe8db7453f0 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2833,6 +2833,7 @@ package android.accounts {      method public final android.os.IBinder getIBinder();      method public abstract android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;      method public android.os.Bundle startAddAccountSession(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException; +    method public android.os.Bundle startUpdateCredentialsSession(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;      method public abstract android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;      field public static final java.lang.String KEY_CUSTOM_TOKEN_EXPIRY = "android.accounts.expiry";    } @@ -2898,6 +2899,7 @@ package android.accounts {      method public void setPassword(android.accounts.Account, java.lang.String);      method public void setUserData(android.accounts.Account, java.lang.String, java.lang.String);      method public android.accounts.AccountManagerFuture<android.os.Bundle> startAddAccountSession(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler); +    method public android.accounts.AccountManagerFuture<android.os.Bundle> startUpdateCredentialsSession(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);      method public android.accounts.AccountManagerFuture<android.os.Bundle> updateCredentials(android.accounts.Account, java.lang.String, android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);      field public static final java.lang.String ACTION_AUTHENTICATOR_INTENT = "android.accounts.AccountAuthenticator";      field public static final java.lang.String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator"; diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java index 185ceb430e13..041f591e0ba8 100644 --- a/core/java/android/accounts/AbstractAccountAuthenticator.java +++ b/core/java/android/accounts/AbstractAccountAuthenticator.java @@ -119,21 +119,26 @@ public abstract class AbstractAccountAuthenticator {      /**       * Bundle key used for the {@link String} account type in session bundle.       * This is used in the default implementation of -     * {@link #startAddAccountSession}. TODO: and startUpdateCredentialsSession. +     * {@link #startAddAccountSession} and {@link startUpdateCredentialsSession}.       */      private static final String KEY_AUTH_TOKEN_TYPE = "android.accounts.KEY_AUTH_TOKEN_TYPE";      /**       * Bundle key used for the {@link String} array of required features in       * session bundle. This is used in the default implementation of -     * {@link #startAddAccountSession}. TODO: and startUpdateCredentialsSession. +     * {@link #startAddAccountSession} and {@link startUpdateCredentialsSession}.       */      private static final String KEY_REQUIRED_FEATURES = "android.accounts.AbstractAccountAuthenticator.KEY_REQUIRED_FEATURES";      /**       * Bundle key used for the {@link Bundle} options in session bundle. This is -     * used in default implementation of {@link #startAddAccountSession}. TODO: -     * and startUpdateCredentialsSession. +     * used in default implementation of {@link #startAddAccountSession} and +     * {@link startUpdateCredentialsSession}.       */      private static final String KEY_OPTIONS = "android.accounts.AbstractAccountAuthenticator.KEY_OPTIONS"; +    /** +     * Bundle key used for the {@link Account} account in session bundle. This is used +     * used in default implementation of {@link startUpdateCredentialsSession}. +     */ +    private static final String KEY_ACCOUNT = "android.accounts.AbstractAccountAuthenticator.KEY_ACCOUNT";      private final Context mContext; @@ -385,6 +390,43 @@ public abstract class AbstractAccountAuthenticator {                  handleException(response, "startAddAccountSession", accountType, e);              }          } + +        @Override +        public void startUpdateCredentialsSession( +                IAccountAuthenticatorResponse response, +                Account account, +                String authTokenType, +                Bundle loginOptions) throws RemoteException { +            if (Log.isLoggable(TAG, Log.VERBOSE)) { +                Log.v(TAG, "startUpdateCredentialsSession: " +                        + account +                        + ", authTokenType " +                        + authTokenType); +            } +            checkBinderPermission(); +            try { +                final Bundle result = AbstractAccountAuthenticator.this +                        .startUpdateCredentialsSession( +                                new AccountAuthenticatorResponse(response), +                                account, +                                authTokenType, +                                loginOptions); +                if (Log.isLoggable(TAG, Log.VERBOSE)) { +                    // Result may be null. +                    if (result != null) { +                        result.keySet(); // force it to be unparcelled +                    } +                    Log.v(TAG, "startUpdateCredentialsSession: result " +                            + AccountManager.sanitizeResult(result)); +                } +                if (result != null) { +                    response.onResult(result); +                } +            } catch (Exception e) { +                handleException(response, "startUpdateCredentialsSession", +                        account.toString() + "," + authTokenType, e); +            } +        }      }      private void handleException(IAccountAuthenticatorResponse response, String method, @@ -700,4 +742,49 @@ public abstract class AbstractAccountAuthenticator {          }).start();          return null;      } + +    /** +     * Asks user to re-authenticate for an account but defers updating the locally stored +     * credentials. +     * +     * @param response to send the result back to the AccountManager, will never +     *            be null +     * @param account the account whose credentials are to be updated, will +     *            never be null +     * @param authTokenType the type of auth token to retrieve after updating +     *            the credentials, may be null (TODO) +     * @param options a Bundle of authenticator-specific options, may be null +     * @return a Bundle result or null if the result is to be returned via the +     *         response. The result will contain either: +     *         <ul> +     *         <li>{@link AccountManager#KEY_INTENT}, or +     *         <li>{@link AccountManager#KEY_ACCOUNT_SESSION_BUNDLE} for updating the +     *         locally stored credentials later, and if account is +     *         re-authenticated, {@link AccountManager#KEY_PASSWORD} and +     *         {@link AccountManager#KEY_ACCOUNT_STATUS_TOKEN} for checking the +     *         status of the account later, or +     *         <li>{@link AccountManager#KEY_ERROR_CODE} and +     *         {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error +     *         </ul> +     * @throws NetworkErrorException if the authenticator could not honor the +     *             request due to a network error +     */ +    public Bundle startUpdateCredentialsSession(final AccountAuthenticatorResponse response, +            final Account account, final String authTokenType, final Bundle options) +                    throws NetworkErrorException { +        new Thread(new Runnable() { +            @Override +            public void run() { +                Bundle sessionBundle = new Bundle(); +                sessionBundle.putString(KEY_AUTH_TOKEN_TYPE, authTokenType); +                sessionBundle.putParcelable(KEY_ACCOUNT, account); +                sessionBundle.putBundle(KEY_OPTIONS, options); +                Bundle result = new Bundle(); +                result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle); +                response.onResult(result); +            } + +        }).start(); +        return null; +    }  } diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 42e5e2a5fb6e..5557905e4f47 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -2666,9 +2666,14 @@ public class AccountManager {       *         trouble       *         </ul>       */ -    public AccountManagerFuture<Bundle> startAddAccountSession(final String accountType, -            final String authTokenType, final String[] requiredFeatures, final Bundle options, -            final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { +    public AccountManagerFuture<Bundle> startAddAccountSession( +            final String accountType, +            final String authTokenType, +            final String[] requiredFeatures, +            final Bundle options, +            final Activity activity, +            AccountManagerCallback<Bundle> callback, +            Handler handler) {          if (accountType == null) throw new IllegalArgumentException("accountType is null");          final Bundle optionsIn = new Bundle();          if (options != null) { @@ -2679,8 +2684,89 @@ public class AccountManager {          return new AmsTask(activity, handler, callback) {              @Override              public void doWork() throws RemoteException { -                mService.startAddAccountSession(mResponse, accountType, authTokenType, -                        requiredFeatures, activity != null, optionsIn); +                mService.startAddAccountSession( +                        mResponse, +                        accountType, +                        authTokenType, +                        requiredFeatures, +                        activity != null, +                        optionsIn); +            } +        }.start(); +    } + +    /** +     * Asks the user to enter a new password for an account but not updating the +     * saved credentials for the account until finishSession is +     * called. +     * <p> +     * This method may be called from any thread, but the returned +     * {@link AccountManagerFuture} must not be used on the main thread. +     * <p> +     * <b>NOTE:</b> The saved credentials for the account alone will not be +     * updated by calling this API alone . +     * +     * @param account The account to update credentials for +     * @param authTokenType The credentials entered must allow an auth token of +     *            this type to be created (but no actual auth token is +     *            returned); may be null +     * @param options Authenticator-specific options for the request; may be +     *            null or empty +     * @param activity The {@link Activity} context to use for launching a new +     *            authenticator-defined sub-Activity to prompt the user to enter +     *            a password; used only to call startActivity(); if null, the +     *            prompt will not be launched directly, but the necessary +     *            {@link Intent} will be returned to the caller instead +     * @param callback Callback to invoke when the request completes, null for +     *            no callback +     * @param handler {@link Handler} identifying the callback thread, null for +     *            the main thread +     * @return An {@link AccountManagerFuture} which resolves to a Bundle with +     *         these fields if an activity was supplied and user was +     *         successfully re-authenticated to the account (TODO: default impl +     *         only returns escorw?): +     *         <ul> +     *         <li>{@link #KEY_ACCOUNT_SESSION_BUNDLE} - encrypted Bundle for +     *         updating the local credentials on device later. +     *         <li>{@link #KEY_PASSWORD} - optional, the password or password hash of the +     *         account +     *         <li>{@link #KEY_ACCOUNT_STATUS_TOKEN} - optional, token to check status of +     *         the account +     *         </ul> +     *         If no activity was specified, the returned Bundle contains +     *         {@link #KEY_INTENT} with the {@link Intent} needed to launch the +     *         password prompt. If an error occurred, +     *         {@link AccountManagerFuture#getResult()} throws: +     *         <ul> +     *         <li>{@link AuthenticatorException} if the authenticator failed to +     *         respond +     *         <li>{@link OperationCanceledException} if the operation was +     *         canceled for any reason, including the user canceling the +     *         password prompt +     *         <li>{@link IOException} if the authenticator experienced an I/O +     *         problem verifying the password, usually because of network +     *         trouble +     *         </ul> +     */ +    public AccountManagerFuture<Bundle> startUpdateCredentialsSession( +            final Account account, +            final String authTokenType, +            final Bundle options, +            final Activity activity, +            final AccountManagerCallback<Bundle> callback, +            final Handler handler) { +        if (account == null) { +            throw new IllegalArgumentException("account is null"); +        } +        return new AmsTask(activity, handler, callback) { +            @Override +            public void doWork() throws RemoteException { +                mService.startUpdateCredentialsSession( +                        mResponse, +                        account, +                        authTokenType, +                        activity != null, +                        options);              }          }.start();      } diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl index b326070ddfc7..921fb19ddb63 100644 --- a/core/java/android/accounts/IAccountAuthenticator.aidl +++ b/core/java/android/accounts/IAccountAuthenticator.aidl @@ -90,4 +90,10 @@ oneway interface IAccountAuthenticator {       */      void startAddAccountSession(in IAccountAuthenticatorResponse response, String accountType,          String authTokenType, in String[] requiredFeatures, in Bundle options); + +    /** +     * Prompts the user for a new password but does not write it to the IAccountManager. +     */ +    void startUpdateCredentialsSession(in IAccountAuthenticatorResponse response, in Account account, +        String authTokenType, in Bundle options);  } diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl index 5de311ea6ec7..8489e47c0ba4 100644 --- a/core/java/android/accounts/IAccountManager.aidl +++ b/core/java/android/accounts/IAccountManager.aidl @@ -88,4 +88,7 @@ interface IAccountManager {          String authTokenType, in String[] requiredFeatures, boolean expectActivityLaunch,          in Bundle options); +    /* Update credentials in two steps. */ +    void startUpdateCredentialsSession(in IAccountManagerResponse response, in Account account, +        String authTokenType, boolean expectActivityLaunch, in Bundle options);  } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 37d47c3b0568..93eaf0e66460 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -2286,8 +2286,11 @@ public class AccountManagerService      }      @Override -    public void startAddAccountSession(final IAccountManagerResponse response, final String accountType, -            final String authTokenType, final String[] requiredFeatures, +    public void startAddAccountSession( +            final IAccountManagerResponse response, +            final String accountType, +            final String authTokenType, +            final String[] requiredFeatures,              final boolean expectActivityLaunch,              final Bundle optionsIn) {          if (Log.isLoggable(TAG, Log.VERBOSE)) { @@ -2571,6 +2574,60 @@ public class AccountManagerService      }      @Override +    public void startUpdateCredentialsSession( +            IAccountManagerResponse response, +            final Account account, +            final String authTokenType, +            final boolean expectActivityLaunch, +            final Bundle loginOptions) { +        if (Log.isLoggable(TAG, Log.VERBOSE)) { +            Log.v(TAG, +                    "startUpdateCredentialsSession: " + account + ", response " + response +                            + ", authTokenType " + authTokenType + ", expectActivityLaunch " +                            + expectActivityLaunch + ", caller's uid " + Binder.getCallingUid() +                            + ", pid " + Binder.getCallingPid()); +        } +        if (response == null) { +            throw new IllegalArgumentException("response is null"); +        } +        if (account == null) { +            throw new IllegalArgumentException("account is null"); +        } +        int userId = UserHandle.getCallingUserId(); +        long identityToken = clearCallingIdentity(); +        try { +            UserAccounts accounts = getUserAccounts(userId); +            new StartAccountSession( +                    accounts, +                    response, +                    account.type, +                    expectActivityLaunch, +                    account.name, +                    false /* authDetailsRequired */, +                    true /* updateLastCredentialTime */) { +                @Override +                public void run() throws RemoteException { +                    mAuthenticator.startUpdateCredentialsSession(this, account, authTokenType, +                            loginOptions); +                } + +                @Override +                protected String toDebugString(long now) { +                    if (loginOptions != null) +                        loginOptions.keySet(); +                    return super.toDebugString(now) +                            + ", startUpdateCredentialsSession" +                            + ", " + account +                            + ", authTokenType " + authTokenType +                            + ", loginOptions " + loginOptions; +                } +            }.bind(); +        } finally { +            restoreCallingIdentity(identityToken); +        } +    } + +    @Override      public void editProperties(IAccountManagerResponse response, final String accountType,              final boolean expectActivityLaunch) {          final int callingUid = Binder.getCallingUid();  |