android 蓝牙 pbap 获取通话记录以及通话日期时间

android 蓝牙 pbap 获取通话时间

之前,我们利用 pbap 协议获取到了用户的通讯录。那自然而然产生了衍生需求:能否获取通话记录?包括打电话记录(DIALED)、接电话记录(RECEIVED)、未接电话记录(MISSED)?
答案是肯定的。类比获取通讯录的方式,我们可以通过修改client.pullPhoneBook(BluetoothPbapClient.PB_PATH);中的PB_PATH参数,来获取其他的信息。比如:

    /**
     * Path to local incoming calls history object
     */
    public static final String ICH_PATH = "telecom/ich.vcf";

    /**
     * Path to local outgoing calls history object
     */
    public static final String OCH_PATH = "telecom/och.vcf";

    /**
     * Path to local missed calls history object
     */
    public static final String MCH_PATH = "telecom/mch.vcf";

    /**
     * Path to local combined calls history object
     */
    public static final String CCH_PATH = "telecom/cch.vcf";

    /**
     * Path to local main phone book object
     */
    public static final String PB_PATH = "telecom/pb.vcf";

但是,在替换PB_PATH为其他的各种 PATH 之后,我们发现获取的信息不完全。我们从控制台中输出的信息只有按时间顺序倒叙排列的一堆联系人信息(其实是VCardEntry对象,控制台输出的时候调用了VCardEntry#toString())。每一个联系人信息如下:

[[  
hash: 427457895   
NAME: [family: nameOfThePerson, given: null, middle: null, prefix: null, suffix: null]  
PHONE: [type: 2, data: 1-111-111-1111, label: null, isPrimary: false]  
]]

问题来了,怎么没有时间信息?对于通话记录而言,时间信息还是比较重要的。那么,是 pbap 协议就不会给我们返回时间?还是我们解析时间数据的时候出了错误?或者是手机厂商在实现 pbap server 端的时候偷工减料了呢?

首先,先去蓝牙 pbap 协议中查看是否有通话记录对应的描述:

3.1.4.1 Call History extension
The time of each call found in och, ich, mch and cch folder, can be shown using the
IrMC [13] defined X-IRMC-CALL-DATETIME property that extends the vCard
specification. This attribute can be used in combination with three newly created
property parameters:
• MISSED
• RECEIVED
• DIALED
These are used to indicate the nature of the call that is time-stamped with X-IRMCCALL-DATETIME.
For instance, a call that was missed on March 20th, 2005 at 10 am would be stamped:
X-IRMC-CALL-DATETIME;MISSED:20050320T100000
It is strongly recommended to use this property parameter whenever possible. They are
especially useful in vCards that are retrieved from the cch folder ( see Section 3.1.2 ).
Note that it is legal to use this property with no data; i.e,
X-IRMC-CALL-DATETIME;MISSED:

看来,关于通话记录,PBAP 协议是有所规定的。所以,问题可能出在手机厂商的 pbap server 端或者是出在我们解析数据的时候。通过对VCardParserImp_V21进行深层次的调试,我们发现,X-IRMC-CALL-DATETIME参数是有输出的。那就说明是手机端的 pbap server 是没有问题的。问题出在我们的 pbap client 上。更具体的定位一下,是我们解析这个参数的时候出了问题,或者是根据解析出的参数构造VCardEntry的时候出了问题。

继续调试,在 VCardEntry#addProperty(VCardProperty property) 函数中,可以输出 property 并且也是有 X-IRMC-CALL-DATETIME 对应的数据的。那么,最终锁定了问题:我们构造 VCardEntry 的时候,没有把 X-IRMC-CALL-DATETIME 加进来。更本质的原因是,android sdk 23 的相关源码中,没有定义 X-IRMC-CALL-DATETIME 相关的字段。

找到了问题所在,改的时候就非常好改了。

首先,在 VCardConstants.java 中添加

    public static final String PROPERTY_X_IRMC_CALL_DATETIME = "X-IRMC-CALL-DATETIME"; // added

然后,在 VCardEntry.java 中添加:

    public enum EntryLabel {
        NAME,
        PHONE,
        EMAIL,
        POSTAL_ADDRESS,
        ORGANIZATION,
        IM,
        PHOTO,
        WEBSITE,
        SIP,
        NICKNAME,
        NOTE,
        BIRTHDAY,
        ANNIVERSARY,
        ANDROID_CUSTOM,
        CALL_DATETIME // added
    }

然后,添加 CALL_DATETIME 对应的类:

public static class CallDatetimeData implements EntryElement {

        private final String mCallDatetime;

        public CallDatetimeData(String datetime) {
            mCallDatetime = datetime;
        }



        /** start implementing EntryElement */

        @Override
        public EntryLabel getEntryLabel() {
            return EntryLabel.CALL_DATETIME;
        }

        @Override
        public boolean isEmpty() {
            return TextUtils.isEmpty(mCallDatetime);
        }

        @Override
        public void constructInsertOperation(List<ContentProviderOperation> operationList, int backReferenceIndex) {
            // 我没看懂这个函数要干嘛,时间有限,先不改了。
        }

        /** end implementing EntryElement */



        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof CallDatetimeData)) {
                return false;
            }
            CallDatetimeData datetimeData = (CallDatetimeData) obj;
            return TextUtils.equals(mCallDatetime, datetimeData.mCallDatetime);
        }

        @Override
        public int hashCode() {
            return mCallDatetime != null ? mCallDatetime.hashCode() : 0;
        }

        @Override
        public String toString() {
            return "call datetime: " + mCallDatetime;
        }

        public String getCallDatetime() {
            return mCallDatetime;
        }
    }

最后是在构造 VCardEntry 对象的时候,将这个字段添加进来:
VCardEntry#addProperty() 中,添加:

if (propertyName.equals(VCardConstants.PROPERTY_X_IRMC_CALL_DATETIME)) {
            mCallDatetimeData = new CallDatetimeData(propValue);  
}

然后在 VCardEntry 中添加一个 getter 就完事了:

    public final String getCallDatetime() {
        return mCallDatetimeData != null ? mCallDatetimeData.mCallDatetime : null;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,810评论 19 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,919评论 25 709
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,365评论 4 61
  • 有没有不自私的爱情? 没有。 爱情就是从对方那里各取所需 我要你爱我 我要你陪伴我 这就是索取 说什么无私的爱 没...
    禾豆阅读 4,138评论 1 1
  • 近十年的光阴,即使是曾经分秒难熬的低谷,回忆起来也是寥寥字数一恍而过。再追溯回更早的起初,也仿佛就在触手可及的昨天...
    蓝得出奇阅读 2,939评论 0 0

友情链接更多精彩内容