android 联系人 --- 读取usim卡的邮箱

       本文主要关于usim卡上邮箱地址分析实例的,同时也附带了一个联系人号码的例子,之前分别写过读取sim/usim卡上短信息和联系人信息的文章,偏向代码调用流程,这次把重点放在具体解析过程。本文可以结合下面的链接一起看。
  
   1 .android -- sim/usim卡导联系人    
   2.android 信息(mms)的故事(七)-- sim卡短信
   3.关于sim/usim的一些概念
  
       我们从这里开始 UsimPhoneBookManager.java的内部类PbrFile.java,从卡上读出来的字节数据在这里解析,代码不算多,流程也还清晰,PbrFile.java的构造函数里调用parseTag,parseTag中又调用parseEf,先看下代码再一起分析。 下面是具体的代码,
    
   private class PbrFile {     
        HashMap<Integer,Map<Integer,Integer>> mFileIds;

        PbrFile(ArrayList<byte[]> records) {
            mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
            SimTlv recTlv;
            int recNum = 0;
            for (byte[] record: records) {
                recTlv = new SimTlv(record, 0, record.length);
                parseTag(recTlv, recNum);
                recNum ++;
            }
        }

        void parseTag(SimTlv tlv, int recNum) {
            SimTlv tlvEf;
            int tag;
            byte[] data;
            Map<Integer, Integer> val = new HashMap<Integer, Integer>();
            do {
                tag = tlv.getTag();
                switch(tag) {
                case USIM_TYPE1_TAG: // A8
                case USIM_TYPE3_TAG: // AA
                case USIM_TYPE2_TAG: // A9
                    data = tlv.getData();
                    tlvEf = new SimTlv(data, 0, data.length);
                    parseEf(tlvEf, val, tag);
                    break;
                }
            } while (tlv.nextObject());
            mFileIds.put(recNum, val);
        }

        void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
            int tag;
            byte[] data;
            int tagNumberWithinParentTag = 0;
            do {
                tag = tlv.getTag();
                if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
                    mEmailPresentInIap = true;
                    mEmailTagNumberInIap = tagNumberWithinParentTag;
                }
                switch(tag) {
                    case USIM_EFEMAIL_TAG:
                    case USIM_EFADN_TAG:
                    case USIM_EFEXT1_TAG:
                    case USIM_EFANR_TAG:
                    case USIM_EFPBC_TAG:
                    case USIM_EFGRP_TAG:
                    case USIM_EFAAS_TAG:
                    case USIM_EFGSD_TAG:
                    case USIM_EFUID_TAG:
                    case USIM_EFCCP1_TAG:
                    case USIM_EFIAP_TAG:
                    case USIM_EFSNE_TAG:
                        data = tlv.getData();
                        int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
                        val.put(tag, efid);
                        break;
                }
                tagNumberWithinParentTag ++;
            } while(tlv.nextObject());
        }
      首先看到以new了一个simTlv(simTlv名称来源,3gpp 31.102中 TLV:Tag length value)对象,将传过来的字节数组数组包装了一下,继续往下看在parseTag函数中的switch语句,A8、A9和AA是什么意思呢?和我们读取数组有什么关系呢?读取,清楚这三个tag是我们解析数据的基础,规则如下,
      1:USIM卡文件系统内EF文件主要分三类:标签tag为A8的type1类型文件、tag为A9的type2类型文件以及tag为AA的type3类型文件。
      2:EFEMAIL(电子邮件)的存在方式只有type1和type2两: 当EFEMAIL以type1方式存在时,其中的记录内容和电话本主文件EFADN一对一映射,即EFADN中的第N条记录与EFEMAIL文件中第N条记录一一对应; 当EFEMAIL以type2方式存在时,EFADN与EFEMAIL中的记录通过EFIAP文件相关联。EFIAP是type1类型文件,与EFADN中的记录一一对应,EFIAP在文件系统内与type2类型文件必同时存在。
      PS:EFEMAIL在文件系统内可能不止一个,且存在方式可能有多种组合。
      再接下来在parseEf又出现几个tag,这里我们关注USIM_EFEMAIL_TAG(CA)、USIM_EFADN_TAG(C0)和USIM_EFIAP_TAG(C1),CA标识出电子邮件ID,C0标识的是电话号码ID,C1的作用可以理解一个索引,根据这个索引再去找CA。规则说得差不多了,来看些例子。以标准AT命令(3gpp 27.007)为例
     
读电子邮件:
    1.利用AT命令AT+CRSM=178,20272(EF_PBR:4F30),记录下标,4,0来读取EFPBR文件的记录,获取各个文件的文件ID以及短文件标识SFI。下面是两条USIM卡两条真实的数据记录。
A8  标识
1E  长度(16进制)
C0034F3A01C1034F3102C4034F5A0AC5034F4106C6034F5107C9034F6108
A9  标识
05  长度
CA034F7109
AA14C2034F4A03C7034F4B0BC8034F4C0CCB034F4F16FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF

这段就不重复标注了,和上面的一样。
A8
28
C0034F3A04C1034F3105C4034F5A06C4034F6A07C4034F7A08C5034F4109C6034F510AC9034F610B
A9
05
CA034F710C
AA14
C2034F4A0DC7034F4B0EC8034F4C0FCB034F4F10

     从此真实记录中看出标识A9下有标识CA(电子邮件),EFEMAIL文件ID为4F71。标识A8下有标识C0(EFADN文件),EFADN文件ID为4F3A,短文件标识为04。标识C1(EFIAP文件)文件ID为4F31。
    读得过程中 若电子邮件是type1类型文件,则EFEMAIL与EFADN一对一映射,在对应下标处写即可。  如果电子邮件是type2类型文件则:
     1)利用AT命令读取此记录对应EFEMAIL文件中的记录下标:
          AT+CRSM=178,EFIAP文件ID,对应EFADN文件中的记录下标,4,0
          在返回的记录中找到order次序的字段值email_record_index。
     2)利用AT命令读取电子邮件文件中email_record_index下标的记录:
           AT+CRSM=178,EFEMAIL文件的ID,email_record_index,4,0

针对第二种给出一下例子
===>>[Send AT cmd][5] AT+CRSM=178,(4F31)20273,2,4,1,,3F007F105F3A,
<<====[Recv AT cmd][5] +CRSM: 144,0,01,
===>>[Send AT cmd][5] AT+CRSM=178, (4F71)20337,1,4,42,,3F007F105F3A,
<<====[Recv AT cmd][5] +CRSM: 144,0,6775750074792E636F6DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,

      到这里故事还没有结束,在上面串里我们看到了EFADN,这家伙指示着电话号码,也许有时候我们还要在去这里找找电话号码,联系人的号码记录是这样
===>>[Send AT cmd][5] AT+CRSM=178,20282,1,4,28,,3F007F105F3A, time=Sat Jan  1 08:06:39 2000
<<====[Recv AT cmd][5] +CRSM: 144,0,804E09FFFFFFFFFFFFFFFFFFFFFF0480333333FFFFFFFFFFFFFFFFFF

80、81编码格式,后面紧跟着升序  联系人名字4E09 :三, 号码:3333333(相信聪明的你已经知道80,81代表什么了)。

      内容差不多就这些,主要的东西应该都写出来了,导卡这部分给个人的感觉是如果想读全读卡上联系人信息(所有的号码和邮箱)要考虑的东西还是挺多的, 流程本身没有多复杂,但是过程比较绕,如果想导卡时间短一些,只导主要的信息就好了(比如忽略附加号码,只找一个邮箱地址),这样能快不少, 有些手机确实就是这么做的,不过这种导法从技术的角度是不应该的,对于这种时间与质量的取舍根据项目的具体要求来决定吧。
      最后,上面对于 type1类型的电子邮件还没有实例,如果你有欢迎分享一下,当然对文章写得不对地方也欢迎拍砖。

你可能感兴趣的:(android 联系人 --- 读取usim卡的邮箱)