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源代码分析学习:创建选定类型的系统帐号的更多相关文章

  1. 基于Andoird 4.2.2的Account Manager源代码分析学习:AccountManagerService系统服务的添加

    从启动说起 Android系统加载时,首先启动init进程,该进程会启动Zygote进程.Zygote进程执行/system/bin/app_process程序.app_process程序在执行中,通 ...

  2. 基于Andoird 4.2.2的同步框架源代码学习——同步发起端

    关键组件: ContentResolver ContentService SyncManager SyncManager.ActiveSyncContext SyncManager.SyncOpera ...

  3. 基于Andoird 4.2.2的同步框架源代码学习——同步提供端

    Android同步框架 同步(synchronization)允许用户将远程数据下载到新的设备上,同时将设备上的帐户数据上传到远端.同步还保证用户能够看到最新的数据. 开发者自然可以通过自己的方式来设 ...

  4. [IOS]从零开始搭建基于Xcode7的IOS开发环境和免开发者帐号真机调试运行第一个IOS程序HelloWorld

    首先这篇文章比较长,若想了解Xcode7的免开发者帐号真机调试运行IOS程序的话,直接转到第五部分. 转载请注明原文地址:http://www.cnblogs.com/litou/p/4843772. ...

  5. Windows Vista for Developers——第四部分:用户帐号控制(User Account Control,UAC)

    作者:Kenny Kerr 翻译:Dflying Chen 原文:http://weblogs.asp.net/kennykerr/archive/2006/09/29/Windows-Vista-f ...

  6. 基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统

    很久没更新博客,最近也有点忙,然后业余时间搞了一个比较完整基于react全家桶+antd-design+webpack2+node+express+mongodb开发的前后台博客系统的流程系统,希望对 ...

  7. Python 基于python实现ADSL宽带帐号,密码的获取及宽带拨号

    基于python实现ADSL宽带帐号的获取及宽带拨号     基本思想: 1.研究上网方式(实验环境为电信网线接入式ADSL,拨号方式PPPOE) 2.研究宽带帐号和密码生成规律(实验环境,宽带帐号为 ...

  8. Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源代码实现

    假设Spark的部署方式选择Standalone,一个採用Master/Slaves的典型架构,那么Master是有SPOF(单点故障,Single Point of Failure).Spark能够 ...

  9. Android应用程序资源管理器(Asset Manager)的创建过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8791064 在前面一篇文章中,我们分析了And ...

随机推荐

  1. poj 百练 2765 八进制小数(精度问题)

    2765:八进制小数 查看 提交 统计 提示 提问 总时间限制:  1000ms  内存限制:  65536kB 描写叙述 八进制小数能够用十进制小数精确的表示.比方,八进制里面的0.75等于十进制里 ...

  2. asp.net2.0安全性(1)--用户角色篇(代码实现2)--转载来自车老师

    加载所有用户 MembershipUserCollection user = Membership.GetAllUsers(); listUser.DataSource = user; listUse ...

  3. 重操JS旧业第十弹:闭包

    闭包是js最难理解,也是最蛋疼的一个名词,仿佛只可意会不可言传一样,有人说闭包说白了就是函数嵌套,也有人说闭包就是函数能够访问函数外部的变量,而内部的外部访问不了: 貌似都非常有道理,其实仔细想来只不 ...

  4. 升级版:深入浅出Hadoop实战开发(云存储、MapReduce、HBase实战微博、Hive应用、Storm应用)

          Hadoop是一个分布式系统基础架构,由Apache基金会开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力高速运算和存储.Hadoop实现了一个分布式文件系 ...

  5. Boost::thread库的使用

    阅读对象 本文假设读者有几下Skills [1]在C++中至少使用过一种多线程开发库,有Mutex和Lock的概念. [2]熟悉C++开发,在开发工具中,能够编译.设置boost::thread库. ...

  6. StackOverFlow的2016统计

    http://stackoverflow.com/research/developer-survey-2016

  7. boost::asio网络传输错误码的一些实验结果(recv error_code)

    错误码很重要,可以由此判断网络连接到底发生了神马事情,从而驱动高层逻辑的行为.只有笼统的错误码判断的网络层是不够规范的,鄙人觉得有些错误码还是需要在网络层就区分开的,特此记录一些当前实验的错误码以及发 ...

  8. C++中字母大写和小写转换实现的优化

    C++中字母大写和小写转换实现的优化 write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 在本文中所有以转换为小写为例. 从推荐复用代 ...

  9. 关于Delphi中的字符串的浅析(瓢虫大作,里面有内存错误的举例)

    关于Delphi中的字符串的浅析 只是浅浅的解析下,让大家可以快速的理解字符串. 其中的所有代码均在Delphi7下测试通过. Delphi 4,5,6,7中有字符串类型包括了: 短字符串(Short ...

  10. OCA读书笔记(7) - 管理数据库存储结构

    7.Managing Database Storage Structures 逻辑结构 数据库的存储结构有物理结构和逻辑结构组成的 物理结构:物理上,oracle是由一些操作系统文件组成的 SQL&g ...