public AccountManagerFuture<Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) { ... }
在程序中创建指定类型的系统帐号,需要提供一个AccountManagerCallback类型的回调,后面会讲到其作用。
本方法要求用户添加指定类型的帐号。
此种帐号类型对应的authenticator将加载对应的UI来处理这个请求。
方法返回一个AccountManagerFuture对象,可解析出一个Bundle,包含以下信息:
- KEY_ACCOUNT_NAME: 创建的帐号的名称
- KEY_ACCOUNT_TYPE: 帐号类型
本方法创建一个匿名AmsTask实例并启动:
return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { mService.addAcount(mResponse, accountType, authTokenType, requiredFeatures, activity != null, optionsIn); } }.start();
这个方法中,创建一个Session类型的匿名实例,并调用其bind()方法,最终捆绑到应用程序提供的authenticator service:
new Session(accounts, response, accountType, expectActivityLaunch, true /* stripAuthTokenFromResult */) { public void run() throws RemoteException { mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures, options); } protected String toDebugString(long now) { return super.toDebugString(now) + ", addAccount" + ", accountType " + accountType + ", requiredFeatures " + (requiredFeatures != null ? TextUtils.join(",", requiredFeatures) : null); } }.bind();
void bind() { ... if (!bindToAuthenticator(mAccountType)) { Log.d(TAG, "bind attempt failed for " + toDebugString()); onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure"); } }
private boolean bindToAuthenticator(String authenticatorType) { final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo; authenticatorInfo = mAuthenticatorCache.getServiceInfo( AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId); ... Intent intent = new Intent(); intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT); intent.setComponent(authenticatorInfo.componentName); ... if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE, mAccounts.userId)) { ... } return true; }
public void onServiceConnected(ComponentName name, IBinder service) { mAuthenticator = IAccountAuthenticator.Stub.asInterface(service); try { run(); } catch (RemoteException e) { onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception"); } }
public abstract class AbstractAccountAuthenticator { ... private class Transport extends IAccountAuthenticator.Stub { public void addAccount(IAccountAuthenticatorResponse response, String accountType, String authTokenType, String[] features, Bundle options) throws RemoteException { ... try { final Bundle result = AbstractAccountAuthenticator.this.addAccount( new AccountAuthenticatorResponse(response), accountType, authTokenType, features, options); ... } ... } ... } ... private Transport mTransport = new Transport(); /** * @return the IBinder for the AccountAuthenticator */ public final IBinder getIBinder() { return mTransport.asBinder(); } ... }
class PopImapAuthenticator extends AbstractAccountAuthenticator { ... @Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { // There are two cases here: // 1) We are called with a username/password; this comes from the traditional email // app UI; we simply create the account and return the proper bundle if (options != null && options.containsKey(OPTIONS_PASSWORD) && options.containsKey(OPTIONS_USERNAME)) { final Account account = new Account(options.getString(OPTIONS_USERNAME), AccountManagerTypes.TYPE_POP_IMAP); AccountManager.get(PopImapAuthenticatorService.this).addAccountExplicitly( account, options.getString(OPTIONS_PASSWORD), null); ... Bundle b = new Bundle(); b.putString(AccountManager.KEY_ACCOUNT_NAME, options.getString(OPTIONS_USERNAME)); b.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountManagerTypes.TYPE_POP_IMAP); return b; // 2) The other case is that we're creating a new account from an Account manager // activity. In this case, we add an intent that will be used to gather the // account information... } else { Bundle b = new Bundle(); Intent intent = AccountSetupBasics.actionSetupPopImapIntent(PopImapAuthenticatorService.this); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); b.putParcelable(AccountManager.KEY_INTENT, intent); return b; } }
private AccountManagerCallback<Bundle> mCallback = new AccountManagerCallback<Bundle>() { public void run(AccountManagerFuture<Bundle> future) { boolean done = true; try { Bundle bundle = future.getResult(); //bundle.keySet(); Intent intent = (Intent) bundle.get(AccountManager.KEY_INTENT); if (intent != null) { done = false; Bundle addAccountOptions = new Bundle(); addAccountOptions.putParcelable(KEY_CALLER_IDENTITY, mPendingIntent); addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, Utils.hasMultipleUsers(AddAccountSettings.this)); intent.putExtras(addAccountOptions); startActivityForResult(intent, ADD_ACCOUNT_REQUEST); ... }