4,SIM卡联系人
Contacts2.db数据库中联系人其实包括2部分,手机上面的联系人以及SIM卡中的联系人。
当然, SIM卡中的联系人是保存在单独的数据库中,其对应的Provider为IccProvider,在packages\services\Telephony 路径下,也就是phone进程中。
AndroidManifest.xml对应的定义如下,
<provider android:name="IccProvider"
android:authorities="icc"
android:multiprocess="true"
android:exported="true"
android:readPermission="android.permission.READ_CONTACTS"
android:writePermission="android.permission.WRITE_CONTACTS" />
IccProvider定义如下,
public class IccProvider extends com.android.internal.telephony.IccProvider {
public IccProvider() {
super();
}
}
直接继承系统jar包中的IccProvider类。因此,增删改查直接看jar包中的IccProvider类就可以了。
----找了好久都找不到对应的db数据库。
在联系人相关界面上,可以看到,
1,拔出SIM卡,仅显示phone中的联系人;
2,插上SIM卡,又会显示SIM卡上的联系人。
因此,可以这样推断,当拨号SIM卡时,会从Contacts2.db数据库中删除SIM卡的联系人;
当插上SIM卡时,会将插上SIM卡中的联系人同步到Contacts2.db数据库中。并且在这2种情况下,导出Contacts2.db数据库,的确是这样的。到底是怎么发生的呢?
分析SimContacts apk,路径:vendor\qcom\proprietary\telephony-apps\SimContacts
4.1 删除联系人
AndroidManifest.xml的SimStateReceiver服务,配置如下,
<receiver android:name="SimStateReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.SIM_STATE_CHANGED"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="org.codeaurora.intent.action.ACTION_SIM_REFRESH_UPDATE"/>
</intent-filter>
</receiver>
注册了三个广播。分别是开机广播,SIM卡状态变化的广播,SIM卡状态更新的广播。
SimStateReceiver的逻辑也很简单,就是启动SimStateReceiver服务完成真正的功能。
sendPhoneBoot/sendSimState/sendSimRefreshUpdate/这三个方法最后都会启动SimContactsService服务,
mContext.startService(new Intent(mContext, SimContactsService.class).putExtras(args));
AndroidManifest.xml的SimStateReceiver服务,配置如下,
<receiver android:name="SimStateReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.SIM_STATE_CHANGED"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="org.codeaurora.intent.action.ACTION_SIM_REFRESH_UPDATE"/>
</intent-filter>
</receiver>
注册了三个action,分别是开机,SIM卡状态变化的广播,SIM卡插拔的广播。也就是说, SimContactsService服务在Android系统启动之后就会启动。
SimContactsService是利用Handler切换到UI线程来执行的。
当SIM卡状态变化时, SimContactsService 的onCreate方法内的匿名Handler的handleMessage方法对应的处理如下,
case MSG_SIM_STATE_CHANGED:
•••
if (mSimState[slotId] == SimContactsConstants.SIM_STATE_NOT_READY
|| mSimState[slotId] == SimContactsConstants.SIM_STATE_ERROR) {
// To handle card absent/error, hot swap related cases.
deleteDatabaseSimContacts(slotId);
break;
•••
调用deleteDatabaseSimContacts方法删除Contacts2.db数据库中的SIM联系人。
deleteDatabaseSimContacts方法如下,
getContentResolver().delete(ContactsContract.RawContacts.CONTENT_URI,
SIM_DATABASE_SELECTION, getSimAccountDBSelectArgs(slotId));
调用ContentResolver的delete方法从Contacts2.db数据库的raw_contacts表中删除对应SIM卡联系人。
SIM_DATABASE_SELECTION变量如下,
static final String SIM_DATABASE_SELECTION = RawContacts.ACCOUNT_TYPE + "=?" + " AND " +RawContacts.ACCOUNT_NAME + "=?" + " AND " + RawContacts.DELETED + "=?";
getSimAccountDBSelectArgs方法如下,
return new String[] {
SimContactsConstants.ACCOUNT_TYPE_SIM,
SimContactsConstants.getSimAccountName(slotId), "0"
};
SimContactsConstants的ACCOUNT_TYPE_SIM定义如下,
public static final String ACCOUNT_TYPE_SIM = "com.android.sim";
SimContactsConstants的getSimAccountName方法如下,
if (TelephonyManager.getDefault().isMultiSimEnabled()) {
return ACCOUNT_NAME_SIM + (slotId + 1);
} else {
return ACCOUNT_NAME_SIM;
}
ACCOUNT_NAME_SIM定义如下,
public static final String ACCOUNT_NAME_SIM = "SIM";
因此,删除语句意思为:
从raw_contacts表中删除account_type为"com.android.sim", account_name为SIM1,并且deleted为0的联系人。
Contacts2.db数据库的account表单部分如下,
raw_contacts表单部分如下,
分析这2张表单, deleted为0表示当前的联系人,为1表示已经删除的联系人。
account_type为1的表示是phone联系人,其他的表示从SIM卡同步的联系人,当前还有双卡的情况。
在此,就一目了然了。稍微有点不同的是,这里并没有在子线程中采用异步的方法。