diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java index 8bc7428a6fa82..c0c4c17f4eaa2 100644 --- a/core/java/android/accounts/AbstractAccountAuthenticator.java +++ b/core/java/android/accounts/AbstractAccountAuthenticator.java @@ -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"); } diff --git a/core/java/android/accounts/AccountAuthenticatorResponse.java b/core/java/android/accounts/AccountAuthenticatorResponse.java index 7c09fbffb86ad..614e139653941 100644 --- a/core/java/android/accounts/AccountAuthenticatorResponse.java +++ b/core/java/android/accounts/AccountAuthenticatorResponse.java @@ -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) { diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java index 1bb1d0f3054e9..835602922af74 100644 --- a/core/java/android/accounts/AccountManager.java +++ b/core/java/android/accounts/AccountManager.java @@ -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, ""); + 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 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 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) {