- add verbose logging to the authenticator
- fix a bug in AccountManager.getAuthTokenByFeatures() where getAuthToken() isn't called after adding the account when necessary
This commit is contained in:
@@ -24,6 +24,10 @@ import android.content.pm.PackageManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.Manifest;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Abstract base class for creating AccountAuthenticators.
|
||||
@@ -103,6 +107,8 @@ import android.Manifest;
|
||||
* writing activities to handle these requests.
|
||||
*/
|
||||
public abstract class AbstractAccountAuthenticator {
|
||||
private static final String TAG = "AccountAuthenticator";
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public AbstractAccountAuthenticator(Context context) {
|
||||
@@ -111,19 +117,34 @@ public abstract class AbstractAccountAuthenticator {
|
||||
|
||||
private class Transport extends IAccountAuthenticator.Stub {
|
||||
public void addAccount(IAccountAuthenticatorResponse response, String accountType,
|
||||
String authTokenType, String[] requiredFeatures, Bundle options)
|
||||
String authTokenType, String[] features, Bundle options)
|
||||
throws RemoteException {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "addAccount: accountType " + accountType
|
||||
+ ", authTokenType " + authTokenType
|
||||
+ ", features " + (features == null ? "[]" : Arrays.toString(features)));
|
||||
}
|
||||
checkBinderPermission();
|
||||
try {
|
||||
final Bundle result = AbstractAccountAuthenticator.this.addAccount(
|
||||
new AccountAuthenticatorResponse(response),
|
||||
accountType, authTokenType, requiredFeatures, options);
|
||||
accountType, authTokenType, features, options);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
result.keySet(); // force it to be unparcelled
|
||||
Log.v(TAG, "addAccount: result " + AccountManager.sanitizeResult(result));
|
||||
}
|
||||
if (result != null) {
|
||||
response.onResult(result);
|
||||
}
|
||||
} catch (NetworkErrorException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "addAccount", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_NETWORK_ERROR, e.getMessage());
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "addAccount", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
|
||||
"addAccount not supported");
|
||||
}
|
||||
@@ -131,16 +152,30 @@ public abstract class AbstractAccountAuthenticator {
|
||||
|
||||
public void confirmCredentials(IAccountAuthenticatorResponse response,
|
||||
Account account, Bundle options) throws RemoteException {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "confirmCredentials: " + account);
|
||||
}
|
||||
checkBinderPermission();
|
||||
try {
|
||||
final Bundle result = AbstractAccountAuthenticator.this.confirmCredentials(
|
||||
new AccountAuthenticatorResponse(response), account, options);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
result.keySet(); // force it to be unparcelled
|
||||
Log.v(TAG, "confirmCredentials: result "
|
||||
+ AccountManager.sanitizeResult(result));
|
||||
}
|
||||
if (result != null) {
|
||||
response.onResult(result);
|
||||
}
|
||||
} catch (NetworkErrorException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "confirmCredentials", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_NETWORK_ERROR, e.getMessage());
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "confirmCredentials", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
|
||||
"confirmCredentials not supported");
|
||||
}
|
||||
@@ -149,16 +184,32 @@ public abstract class AbstractAccountAuthenticator {
|
||||
public void getAuthTokenLabel(IAccountAuthenticatorResponse response,
|
||||
String authTokenType)
|
||||
throws RemoteException {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthTokenLabel: authTokenType " + authTokenType);
|
||||
}
|
||||
checkBinderPermission();
|
||||
try {
|
||||
Bundle result = new Bundle();
|
||||
result.putString(AccountManager.KEY_AUTH_TOKEN_LABEL,
|
||||
AbstractAccountAuthenticator.this.getAuthTokenLabel(authTokenType));
|
||||
response.onResult(result);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
result.keySet(); // force it to be unparcelled
|
||||
Log.v(TAG, "getAuthTokenLabel: result "
|
||||
+ AccountManager.sanitizeResult(result));
|
||||
}
|
||||
if (result != null) {
|
||||
response.onResult(result);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthTokenLabel", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_BAD_ARGUMENTS,
|
||||
"unknown authTokenType");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthTokenLabel", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
|
||||
"getAuthTokenTypeLabel not supported");
|
||||
}
|
||||
@@ -167,35 +218,64 @@ public abstract class AbstractAccountAuthenticator {
|
||||
public void getAuthToken(IAccountAuthenticatorResponse response,
|
||||
Account account, String authTokenType, Bundle loginOptions)
|
||||
throws RemoteException {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthToken: " + account
|
||||
+ ", authTokenType " + authTokenType);
|
||||
}
|
||||
checkBinderPermission();
|
||||
try {
|
||||
final Bundle result = AbstractAccountAuthenticator.this.getAuthToken(
|
||||
new AccountAuthenticatorResponse(response), account,
|
||||
authTokenType, loginOptions);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
result.keySet(); // force it to be unparcelled
|
||||
Log.v(TAG, "getAuthToken: result " + AccountManager.sanitizeResult(result));
|
||||
}
|
||||
if (result != null) {
|
||||
response.onResult(result);
|
||||
}
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthToken", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
|
||||
"getAuthToken not supported");
|
||||
} catch (NetworkErrorException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "getAuthToken", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_NETWORK_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCredentials(IAccountAuthenticatorResponse response, Account account,
|
||||
String authTokenType, Bundle loginOptions) throws RemoteException {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "updateCredentials: " + account
|
||||
+ ", authTokenType " + authTokenType);
|
||||
}
|
||||
checkBinderPermission();
|
||||
try {
|
||||
final Bundle result = AbstractAccountAuthenticator.this.updateCredentials(
|
||||
new AccountAuthenticatorResponse(response), account,
|
||||
authTokenType, loginOptions);
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
result.keySet(); // force it to be unparcelled
|
||||
Log.v(TAG, "updateCredentials: result "
|
||||
+ AccountManager.sanitizeResult(result));
|
||||
}
|
||||
if (result != null) {
|
||||
response.onResult(result);
|
||||
}
|
||||
} catch (NetworkErrorException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "updateCredentials", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_NETWORK_ERROR, e.getMessage());
|
||||
} catch (UnsupportedOperationException e) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "updateCredentials", e);
|
||||
}
|
||||
response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
|
||||
"updateCredentials not supported");
|
||||
}
|
||||
|
||||
@@ -20,11 +20,14 @@ import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Object used to communicate responses back to the AccountManager
|
||||
*/
|
||||
public class AccountAuthenticatorResponse implements Parcelable {
|
||||
private static final String TAG = "AccountAuthenticator";
|
||||
|
||||
private IAccountAuthenticatorResponse mAccountAuthenticatorResponse;
|
||||
|
||||
/**
|
||||
@@ -40,6 +43,11 @@ public class AccountAuthenticatorResponse implements Parcelable {
|
||||
}
|
||||
|
||||
public void onResult(Bundle result) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
result.keySet(); // force it to be unparcelled
|
||||
Log.v(TAG, "AccountAuthenticatorResponse.onResult: "
|
||||
+ AccountManager.sanitizeResult(result));
|
||||
}
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
@@ -48,6 +56,9 @@ public class AccountAuthenticatorResponse implements Parcelable {
|
||||
}
|
||||
|
||||
public void onRequestContinued() {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "AccountAuthenticatorResponse.onRequestContinued");
|
||||
}
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onRequestContinued();
|
||||
} catch (RemoteException e) {
|
||||
@@ -56,6 +67,9 @@ public class AccountAuthenticatorResponse implements Parcelable {
|
||||
}
|
||||
|
||||
public void onError(int errorCode, String errorMessage) {
|
||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||
Log.v(TAG, "AccountAuthenticatorResponse.onError: " + errorCode + ", " + errorMessage);
|
||||
}
|
||||
try {
|
||||
mAccountAuthenticatorResponse.onError(errorCode, errorMessage);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.os.RemoteException;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -222,6 +223,19 @@ public class AccountManager {
|
||||
mMainHandler = handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide for internal use only
|
||||
*/
|
||||
public static Bundle sanitizeResult(Bundle result) {
|
||||
if (result.containsKey(KEY_AUTHTOKEN)
|
||||
&& !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
|
||||
final Bundle newResult = new Bundle(result);
|
||||
newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
|
||||
return newResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an AccountManager instance associated with a Context.
|
||||
* The {@link Context} will be used as long as the AccountManager is
|
||||
@@ -1447,6 +1461,7 @@ public class AccountManager {
|
||||
final Bundle mAddAccountOptions;
|
||||
final Bundle mLoginOptions;
|
||||
final AccountManagerCallback<Bundle> mMyCallback;
|
||||
private volatile int mNumAccounts = 0;
|
||||
|
||||
public void doWork() throws RemoteException {
|
||||
getAccountsByTypeAndFeatures(mAccountType, mFeatures,
|
||||
@@ -1466,6 +1481,8 @@ public class AccountManager {
|
||||
return;
|
||||
}
|
||||
|
||||
mNumAccounts = accounts.length;
|
||||
|
||||
if (accounts.length == 0) {
|
||||
if (mActivity != null) {
|
||||
// no accounts, add one now. pretend that the user directly
|
||||
@@ -1538,7 +1555,21 @@ public class AccountManager {
|
||||
|
||||
public void run(AccountManagerFuture<Bundle> future) {
|
||||
try {
|
||||
set(future.getResult());
|
||||
final Bundle result = future.getResult();
|
||||
if (mNumAccounts == 0) {
|
||||
final String accountName = result.getString(KEY_ACCOUNT_NAME);
|
||||
final String accountType = result.getString(KEY_ACCOUNT_TYPE);
|
||||
if (TextUtils.isEmpty(accountName) || TextUtils.isEmpty(accountType)) {
|
||||
setException(new AuthenticatorException("account not in result"));
|
||||
return;
|
||||
}
|
||||
final Account account = new Account(accountName, accountType);
|
||||
mNumAccounts = 1;
|
||||
getAuthToken(account, mAuthTokenType, null /* options */, mActivity,
|
||||
mMyCallback, mHandler);
|
||||
return;
|
||||
}
|
||||
set(result);
|
||||
} catch (OperationCanceledException e) {
|
||||
cancel(true /* mayInterruptIfRUnning */);
|
||||
} catch (IOException e) {
|
||||
|
||||
Reference in New Issue
Block a user