AccountManager: add isCredentialsUpdateSuggested API.

Change-Id: I27e0db0345f3431b796a944740dab767b45f7871
This commit is contained in:
Sandra Kwan
2016-01-12 14:13:37 -08:00
parent ca1b71b6fa
commit 390c9d2d91
6 changed files with 212 additions and 12 deletions

View File

@@ -2860,6 +2860,7 @@ package android.accounts {
method public abstract java.lang.String getAuthTokenLabel(java.lang.String);
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 isCredentialsUpdateSuggested(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;
@@ -2915,6 +2916,7 @@ package android.accounts {
method public java.lang.String getUserData(android.accounts.Account, java.lang.String);
method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
method public void invalidateAuthToken(java.lang.String, java.lang.String);
method public android.accounts.AccountManagerFuture<java.lang.Boolean> isCredentialsUpdateSuggested(android.accounts.Account, java.lang.String, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
method public static deprecated android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.List<android.accounts.Account>, java.lang.String[], java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
method public boolean notifyAccountAuthenticated(android.accounts.Account);

View File

@@ -16,16 +16,16 @@
package android.accounts;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
import android.os.Binder;
import android.os.IBinder;
import android.content.pm.PackageManager;
import android.content.Context;
import android.content.Intent;
import android.Manifest;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
@@ -436,6 +436,7 @@ public abstract class AbstractAccountAuthenticator {
}
}
@Override
public void finishSession(
IAccountAuthenticatorResponse response,
String accountType,
@@ -461,6 +462,24 @@ public abstract class AbstractAccountAuthenticator {
}
}
@Override
public void isCredentialsUpdateSuggested(
IAccountAuthenticatorResponse response,
Account account,
String statusToken) throws RemoteException {
checkBinderPermission();
try {
final Bundle result = AbstractAccountAuthenticator.this
.isCredentialsUpdateSuggested(
new AccountAuthenticatorResponse(response), account, statusToken);
if (result != null) {
response.onResult(result);
}
} catch (Exception e) {
handleException(response, "isCredentialsUpdateSuggested", account.toString(), e);
}
}
}
private void handleException(IAccountAuthenticatorResponse response, String method,
@@ -873,7 +892,8 @@ public abstract class AbstractAccountAuthenticator {
* <li>{@link AccountManager#KEY_ERROR_CODE} and
* {@link AccountManager#KEY_ERROR_MESSAGE} to indicate an error
* </ul>
* @throws NetworkErrorException
* @throws NetworkErrorException if the authenticator could not honor the request due to a
* network error
* @see #startAddAccountSession and #startUpdateCredentialsSession
* @hide
*/
@@ -944,4 +964,32 @@ public abstract class AbstractAccountAuthenticator {
// Otherwise, session bundle was created by startAddAccountSession default implementation.
return addAccount(response, accountType, authTokenType, requiredFeatures, sessionOptions);
}
/**
* Checks if update of the account credentials is suggested.
*
* @param response to send the result back to the AccountManager, will never be null.
* @param account the account to check, will never be null
* @param statusToken a String of token to check if update of credentials is suggested.
* @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_BOOLEAN_RESULT}, true if update of account's
* credentials is suggested, false otherwise
* <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
* @hide
*/
@SystemApi
public Bundle isCredentialsUpdateSuggested(
final AccountAuthenticatorResponse response,
Account account,
String statusToken) throws NetworkErrorException {
Bundle result = new Bundle();
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
return result;
}
}

View File

@@ -16,6 +16,8 @@
package android.accounts;
import static android.Manifest.permission.GET_ACCOUNTS;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.Size;
@@ -54,8 +56,6 @@ import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static android.Manifest.permission.GET_ACCOUNTS;
/**
* This class provides access to a centralized registry of the user's
* online accounts. The user enters credentials (username and password) once
@@ -2866,4 +2866,50 @@ public class AccountManager {
}
}.start();
}
/**
* Checks whether {@link #updateCredentials} or {@link #startUpdateCredentialsSession} should be
* called with respect to the specified account.
* <p>
* This method may be called from any thread, but the returned {@link AccountManagerFuture} must
* not be used on the main thread.
*
* @param account The {@link Account} to be checked whether {@link #updateCredentials} or
* {@link #startUpdateCredentialsSession} should be called
* @param statusToken a String of token to check account staus
* @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 Boolean, true if the credentials
* of the account should be updated.
* @hide
*/
@SystemApi
public AccountManagerFuture<Boolean> isCredentialsUpdateSuggested(
final Account account,
final String statusToken,
AccountManagerCallback<Boolean> callback,
Handler handler) {
if (account == null) {
throw new IllegalArgumentException("account is null");
}
if (TextUtils.isEmpty(statusToken)) {
throw new IllegalArgumentException("status token is empty");
}
return new Future2Task<Boolean>(handler, callback) {
public void doWork() throws RemoteException {
mService.isCredentialsUpdateSuggested(
mResponse,
account,
statusToken);
}
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();
}
}

View File

@@ -104,4 +104,10 @@ oneway interface IAccountAuthenticator {
*/
void finishSession(in IAccountAuthenticatorResponse response, String accountType,
in Bundle sessionBundle);
/**
* Checks if the credentials of the provided account should be updated.
*/
void isCredentialsUpdateSuggested(in IAccountAuthenticatorResponse response, in Account account,
String statusToken);
}

View File

@@ -98,4 +98,8 @@ interface IAccountManager {
/* Check if an account exists on any user on the device. */
boolean someUserHasAccount(in Account account);
/* Check if credentials update is suggested */
void isCredentialsUpdateSuggested(in IAccountManagerResponse response, in Account account,
String statusToken);
}

View File

@@ -176,6 +176,7 @@ public class AccountManagerService
private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
private static final Intent ACCOUNTS_CHANGED_INTENT;
static {
ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -2491,7 +2492,7 @@ public class AccountManagerService
Bundle appInfo) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
"finishSession: response "+ response
"finishSession: response " + response
+ ", expectActivityLaunch " + expectActivityLaunch
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
@@ -2777,6 +2778,99 @@ public class AccountManagerService
}
}
@Override
public void isCredentialsUpdateSuggested(
IAccountManagerResponse response,
final Account account,
final String statusToken) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
"isCredentialsUpdateSuggested: " + account + ", response " + response
+ ", 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");
}
if (TextUtils.isEmpty(statusToken)) {
throw new IllegalArgumentException("status token is empty");
}
int uid = Binder.getCallingUid();
// Only allow system to start session
if (!isSystemUid(uid)) {
String msg = String.format(
"uid %s cannot stat add account session.",
uid);
throw new SecurityException(msg);
}
int usrId = UserHandle.getCallingUserId();
long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(usrId);
new Session(accounts, response, account.type, false /* expectActivityLaunch */,
false /* stripAuthTokenFromResult */, account.name,
false /* authDetailsRequired */) {
@Override
protected String toDebugString(long now) {
return super.toDebugString(now) + ", isCredentialsUpdateSuggested"
+ ", " + account;
}
@Override
public void run() throws RemoteException {
mAuthenticator.isCredentialsUpdateSuggested(this, account, statusToken);
}
@Override
public void onResult(Bundle result) {
IAccountManagerResponse response = getResponseAndClose();
if (response == null) {
return;
}
if (result == null) {
sendErrorResponse(
response,
AccountManager.ERROR_CODE_INVALID_RESPONSE,
"null bundle");
return;
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
+ response);
}
// Check to see if an error occurred. We know if an error occurred because all
// error codes are greater than 0.
if ((result.getInt(AccountManager.KEY_ERROR_CODE, -1) > 0)) {
sendErrorResponse(response,
result.getInt(AccountManager.KEY_ERROR_CODE),
result.getString(AccountManager.KEY_ERROR_MESSAGE));
return;
}
if (!result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)) {
sendErrorResponse(
response,
AccountManager.ERROR_CODE_INVALID_RESPONSE,
"no result in response");
return;
}
final Bundle newResult = new Bundle();
newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
sendResponse(response, newResult);
}
}.bind();
} finally {
restoreCallingIdentity(identityToken);
}
}
@Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {