导入前只是存在rawcontacts和data表里, 而导入后就存在contacts表里了, 还未确定,待研究.....
之前理解的不正确, 即使sim卡上的联系人未导入到本地电话本,也会存储在contacts表里, 只是会用一个contact_type(0,11,12..)来表明是卡上的数据还是本地的数据。
以君正平台-android2.2代码为例,电话本模块的进程名字是android.process.acore,主要包括两个APK,contacts.apk 和contactsprovider.apk。
1. ContactsProvider.apk会启动一个广播接收器SystemStartReceiver来接收发来的广播,首先它会接收到android.intent.action.BOOT_COMPLETED,将raw_contacts表里所有非本地联系人的数据都删除掉
2. 然后读取当前是否存在GSM卡或者CDMA卡,如果存在,则发送android.intent.action.SYNC_ICC_CARD_CONTACTS广播消息,消息中携带的数据包括SIM卡的type和index,发送这个消息的目的就是告诉系统要对哪张sim卡上的联系人进行读取了,
3. 当然这个消息也是被SystemStartReceiver自己接受到,这里会启动一个thread来执行读取sim卡联系人的操作,thread内容实现run函数,在run函数中启动一个emptyService来延长thread的生命周期,
4. 在这个子线程中发送一个MSG_NOTIFY_ICC_LOADING的message给主线程,目的是让主线程再发送一个广播消息android.intent.action.loadicccontacts出去, 谁会接受到呢? contacts.apk也启动了一个广播接收器SystemStartReceiver,它会接收到这个消息,用来设置当前sim卡联系人已经开始读取了,LOADICC_START,
5. 接着开始读取ICC数据库的内容, query("content://icc/adn/phonetype/cardindex"), projection={name,number,index};IccProvider中会执行loadFromEf(),这里面会获取AIDL接口,IIccPhoneBook,getAndRecordsInEf()获取sim卡上的全部联系人数据,这样就返回cursor数据,装载到一个ArrayList<ContactItem>中,
6. 此时子线程给主线程发送一个message:MSG_NOTIFY_ICC_CHECKFINISHING,表示ICC读取完毕,然后主线程会发送广播消息 android.intent.action.loadicccontacts给contacts.apk启动的systemStartReceiver,设置LOADICC_FINISH。
7. 然后发送消息MSG_INSERT_NEW_CONTACTS给主线程,主线程将这些sim卡联系人逐个的添加到raw_contacts表和data表中,这里用到了数据库批量处理的操作,即把几个ContentProviderOperation打包在一起,通过applyBatch()执行,对于某一个sim卡联系人,需要向raw_contacts表中添加一条记录,特别是raw_contact_type,这个值如果非0,就表示是sim卡上的联系人,同时向data表中添加两条记录,一条记录存储name,一条记录存储number。
8. 上述操作完毕,则stopEmptyService。