android -- sim/usim卡导联系人

 from: http://blog.csdn.net/baimy1985/article/details/7820024

 

 

前面有一篇说了导卡上的信息(android 信息(mms)的故事(七)-- sim卡短信),sim卡上还有一类非常重要的信息,就是卡上的联系人。不知道大家注意到没有,android手机,尤其是那些带有运营商标识的手机开机都比较慢,这个和开机导卡上的联系人和信息不无关系,运营商是要求开机必须导卡的,不过要说句公道话,开机慢和导卡有关但也不能完全归咎于它(android手机启动时加载的东西本身也很多),当然如果你的手机开机不导卡也慢那肯定是另有原因的。 

        当然Android源码开机是不导卡,如果我们需要查看卡上的联系人需要手动导入,从联系人Contact应用ContactsListActivity.java这个类的menu菜单找到导入导出,选择导入sim卡联系人,进入SimContactsSelectActivity.java这个类,在这个类里会执行query()方法,对应的provider和uri分别是IccProvider.java与uri.parse(content://icc/adn),进入IccProvider.java后的代码是本文要关注的部分,从query()方法看起

 

  1. public Cursor query(Uri url, String[] projection, String selection,  
  2.       String[] selectionArgs, String sort) {  
  3.   ArrayList<ArrayList> results;  
  4.       switch (URL_MATCHER.match(url)) {  
  5.           case ADN:  
  6.           results = loadFromEf(IccConstants.EF_ADN);  
  7.           break;  

 

       我们关心这个loadFromEf()方法,IccConstants.EF_AND这个值是6F3A,这是告诉告诉我们要先去查找卡上这个位置的内容。  

 

  1. private ArrayList<ArrayList> loadFromEf(int efType) {  
  2.     ArrayList<ArrayList> results = new ArrayList<ArrayList>();  
  3.     List<AdnRecord> adnRecords = null;   
  4.     try {  
  5.         IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(//Binder来了                    ServiceManager.getService("simphonebook"));  
  6.         if (iccIpb != null) {  
  7.             adnRecords = iccIpb.getAdnRecordsInEf(efType);//proxy模式  
  8.         }  
  9.     } …省略次要代码….        }  

 

        接下来代码走到IccPhoneBookInterfaceManager.java这个类的getAdnRecordsInEf(intefid)方法,其中涉及了代理模式,IccPhoneBookInterfaceManagerProxy.java在中间做了个转换。在getAdnRecordsInEf(intefid)方法里调用了下updateEfForIccType(efid),判断是sim卡还是usim卡,确定下面的efid是用IccConstants.EF_AND还是IccConstants.EF_PBR,真正的查询是requestLoadAllAdnLike()是这个方法,这里要注意EVENT_LOAD_DONE这个标志,要用它来接收查询结果的。

  1. requestLoadAllAdnLike (int efid, int extensionEf, Message response) {  
  2.     ArrayList<Message> waiters;  
  3.     ArrayList<AdnRecord> result;  
  4.     if (efid == EF_PBR) {  //usim卡,这里我们看这个方法  
  5.         result = mUsimPhoneBookManager.loadEfFilesFromUsim();  
  6.     } else {//sim卡  
  7.         result = getRecordsIfLoaded(efid);  
  8.     }。  

 

       看下loadEfFilesFromUsim()方法,循环读取直到所有file读完后再返回,里面又分了两种,一种是电话号码的联系人,一种是邮箱地址的联系人,邮箱的相比电话号码还要麻烦点。

  1. public ArrayList<AdnRecord> loadEfFilesFromUsim() {  
  2.      synchronized (mLock) {  
  3.         //…省略次要代码….  
  4.          numRecs = mPbrFile.mFileIds.size();  
  5.          for (int i = 0; i < numRecs; i++) {  
  6.              readAdnFileAndWait(i);  
  7.              readEmailFileAndWait(i);  
  8.          } // All EF files are loaded, post the response.  
  9.      }  

 

       readAdnFileAndWait(i)和readEmailFileAndWait(i)最后都会调用mPhone.getIccFileHandler().loadEFLinearFixedAll()方法,只不过具体的参数不同。看下loadEFLinearFixedAll()的代码。

  1. public void loadEFLinearFixedAll(int fileid, Message onLoaded) {  
  2.     Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,  
  3.                     new LoadLinearFixedContext(fileid,onLoaded));  
  4.     phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),  
  5.                     00, GET_RESPONSE_EF_SIZE_BYTES, nullnull, response);  
  6. }  

        iccIO()方法显示代码跑到RIL.java了, 之前读卡上的信息代码也是走这里       

  1.  public void iccIO (int command, int fileid, String path, int p1, int p2, int p3,  
  2.          String data, String pin2, Message result) {        
  3.      RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIM_IO, result);//关注这个TAG标志  
  4.      rr.mp.writeInt(command);  
  5.      rr.mp.writeInt(fileid);  
  6.      rr.mp.writeString(path);  
  7.      rr.mp.writeInt(p1);  
  8.      rr.mp.writeInt(p2);  
  9.      rr.mp.writeInt(p3);  
  10.      rr.mp.writeString(data);  
  11.      rr.mp.writeString(pin2);  
  12.      send(rr);  
  13.  }  
  14. 根据上面那个TAG,可以在Reference-ril.c找到这个分支。  
  15. case RIL_REQUEST_SIM_IO:  
  16.          requestSIM_IO(data,datalen,t);  
  17.          break;  

      阅读requestSIM_IO()方法可以看到android源码是如何读取sim卡上的联系人的,源码使用了AT +CRSM命令,关于AT命令可以看3gpp 27.007这个文档。读取完成时会收到EVENT_PBR_LOAD_DONE这个消息,在里面createPbrFile()方法中完成字符串的解析得到联系人信息。

 

  1. public void handleMessage(Message msg) {  
  2.  …省略代码….      
  3.         switch (msg.what) {  
  4.             case EVENT_PBR_LOAD_DONE:  
  5.                 if (ar.exception == null) {  
  6.                     createPbrFile((ArrayList<byte[]>) ar.result);  
  7.                 }…省略代码….                 
  8.                 break;  

 

        到这里,卡联系人导入大部分流程就走完了,后面还有些写入联系人数据库的操作比较简单就不写了,总体上流程还算清晰,只是循环比较多,远程调试的时候并不是很方便,通常一个sim卡可以存250个联系人,一个usim卡能存的联系人要多些,但数量不固定,其中读写联系人的邮箱地址要麻烦一些,由于存储空间的限制需要多次找对应的索引能找到我们想要的东西。至于读写卡联系人的具体例子,后续单独补充吧。最后贴图一张,有图有真相。








posted @ 2012-08-29 19:17  wanqi  阅读(3932)  评论(0编辑  收藏  举报