博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于Andoird 4.2.2的Account Manager源代码分析学习:创建选定类型的系统帐号
阅读量:4608 次
发布时间:2019-06-09

本文共 7689 字,大约阅读时间需要 25 分钟。

AccountManager.addAccount()

 

public AccountManagerFuture
addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, final Activity activity, AccountManagerCallback
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
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
mCallback = new AccountManagerCallback
() { public void run(AccountManagerFuture
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)中的步骤了。

 

 

转载于:https://www.cnblogs.com/dyllove98/p/3155397.html

你可能感兴趣的文章
集合相关概念
查看>>
Memcache 统计分析!
查看>>
(Python第四天)字符串
查看>>
个人介绍
查看>>
使用python动态特性时,让pycharm自动补全
查看>>
MySQL数据库免安装版配置
查看>>
你必知必会的SQL面试题
查看>>
html5 Canvas绘制时钟以及绘制运动的圆
查看>>
Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween
查看>>
JavaScript空判断
查看>>
洛谷 P1439 【模板】最长公共子序列(DP,LIS?)
查看>>
python timeit
查看>>
Wireless Network 并查集
查看>>
51nod 1019 逆序数
查看>>
20145202马超《JAVA》预备作业1
查看>>
云推送注意(MSDN链接)
查看>>
OpenMobile's Application Compatibility Layer (ACL)
查看>>
竞价广告系统-广告检索
查看>>
强哥PHP面向对象学习笔记
查看>>
[转]基于.NET平台常用的框架整理
查看>>