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卡同步的联系人,当前还有双卡的情况。
在此,就一目了然了。稍微有点不同的是,这里并没有在子线程中采用异步的方法。