基于Andoird 4.2.2的Account Manager源代码分析

系统 1498 0

AccountManager.addAccount()

 

        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();
  


这里,以异步的方式请求AccountManagerService.addAccount()
start()方法立即返回,返回值是AccountManagerFuture类型的。

 

AccountManagerService.addAccount()

这个方法中,创建一个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();
  


这是Session.bind()方法的相关细节:

 

 

            void bind() {

            ...

            if (!bindToAuthenticator(mAccountType)) {

                Log.d(TAG, "bind attempt failed for " + toDebugString());

                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");

            }

        }


  


bindToAuthenticator()方法找到对应的组件名称(应用程序中定义的相关service),并且对Service发起绑定:

 

 

            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;

        }
  


Session类实现了ServiceConnection接口,因此,当成功绑定到对应的应用程序中的Service,其实现的onServiceConnected()方法将被调用:

 

 

            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");

            }

        }
  


这里的service,即是AbstractAuthenticator抽象类提供的IBinder:

 

 

    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();

    }

    ...

}
  


AbstractAccountAuthenticator的内部类Transport是IAccountAuthenticator接口的一个实现。后者规定了Authenticator的一组行为。
以添加帐号的操作为例,作为接口实现的Transport的addAccount()方法调用了AbstractAccountAuthenticator类的addAccount()抽象方法,这个方法的具体实现,则由应用程序中定义的authenticator子类来完成。

这里涉及到IPC,应用程序是服务端,提供服务的实现,而AccountManagerService则是客户端,负责通过代理对象发起调用。

 

Email的authenticator实现:

 

        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;

            }

        }
  


1) 如果是Email应用程序内部添加新的电子邮件帐号,此时已经取得了帐号的用户名和密码,那么直接创建对应的系统帐号,并调用AccountManager.addAccountExplicitly()将其添加到系统帐号数据库中,并返回帐号名称和类型。
2) 如果是从外部,比如系统设置中添加Email帐号,则创建指向Email应用中创建帐号对应的activity的Intent,并返回。这样,AmsTask实例在完成时会通过Handler机制调用AddAccountSettings活动提交的一个回调:

 

 

       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);

            ...

    }
  


这样就会启动Email创建帐号的activity,之后又会走到1)中的步骤了。

 



 

基于Andoird 4.2.2的Account Manager源代码分析学习:创建选定类型的系统帐号


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论