zoukankan      html  css  js  c++  java
  • 基于Andoird 4.2.2的Account Manager源代码分析学习:创建选定类型的系统帐号

    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)中的步骤了。



  • 相关阅读:
    Windows下React Native环境配置
    数据处理函数$.grep,$.map,$.makeArray,sort
    gulp的安装与使用
    模块化管理ajax
    Windows操作系统下ionic开发环境搭建
    css平行四边形与菱形变换
    JavaScript数组排序总结
    JavaScript数组去重总结
    vue之修饰符
    深拷贝、浅拷贝
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3155397.html
Copyright © 2011-2022 走看看