【android bluetooth 协议分析 18】【PBAP详解 2】【车机为何不显示电话号码为空的联系人信息】

一、问题描述

在苹果手机中, 会将 只有名字,没有电话号码的 vcard 传到 车机侧。 但是应用侧确显示不出来。针对这个问题,我们深入探讨一下,究竟是谁把他给过滤掉了。

下面的log 是从 btsnoop 中导出的。

c 复制代码
BEGIN:VCARD
VERSION:3.0
FN:空号测试
N:空号测试
TEL:
END:VCARD


BEGIN:VCARD
VERSION:3.0
FN:Konghao 
N:Konghao 
TEL:
END:VCARD

备注:

  • 但是用其他手机, 例如 IQOO Nevo 3E 上述 vcard 并不会 通过蓝牙 传递到 车机侧, 只有 苹果手机会传。

二、源码回溯

当车机解析手机传递过来的 vcard 时, 将触发 VCardEntry.java::addProperty. 调用流程可以参考 【android bluetooth 协议分析 18】【PBAP详解 1】【为何我们的通话记录中会出现1-521-8xx-1x9x】 这里不再重复。

  • android/frameworks/opt/vcard/java/com/android/vcard/VCardEntry.java
c 复制代码
    public void addProperty(final VCardProperty property) {
        final String propertyName = property.getName();
        final Map<String, Collection<String>> paramMap = property.getParameterMap();
        final List<String> propertyValueList = property.getValueList();
        byte[] propertyBytes = property.getByteValue();

        if ((propertyValueList == null || propertyValueList.size() == 0)
                && propertyBytes == null) {
            return;
        }
        final String propValue = (propertyValueList != null
                ? listToString(propertyValueList).trim()
                : null);

        if (propertyName.equals(VCardConstants.PROPERTY_VERSION)) {
            // vCard version. Ignore this.
        } else if (propertyName.equals(VCardConstants.PROPERTY_FN)) {
			...
        } else if (propertyName.equals(VCardConstants.PROPERTY_NAME)) {
			...
        } else if (propertyName.equals(VCardConstants.PROPERTY_N)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_SORT_STRING)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_NICKNAME)
                || propertyName.equals(VCardConstants.ImportOnly.PROPERTY_X_NICKNAME)) {
           ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_SOUND)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_ADR)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_EMAIL)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_ORG)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_TITLE)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_ROLE)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_PHOTO)
                || propertyName.equals(VCardConstants.PROPERTY_LOGO)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_TEL)) {
            String phoneNumber = null;
            boolean isSip = false;
            if (VCardConfig.isVersion40(mVCardType)) {
				...
            } else {
                phoneNumber = propValue;
            }

            if (isSip) {
				...
            } else {
                if (propValue.length() == 0) {
                    return; // 这里当 TEL 标签 空时,直接返回了。 这里直接将 TEL 为空的联系人给过滤掉了。
                }

                final Collection<String> typeCollection = paramMap.get(VCardConstants.PARAM_TYPE);
                final Object typeObject = VCardUtils.getPhoneTypeFromStrings(typeCollection,
                        phoneNumber);
                final int type;
                final String label;
                if (typeObject instanceof Integer) {
                    type = (Integer) typeObject;
                    label = null;
                } else {
                    type = Phone.TYPE_CUSTOM;
                    label = typeObject.toString();
                }

                final boolean isPrimary;
                if (typeCollection != null &&
                        typeCollection.contains(VCardConstants.PARAM_TYPE_PREF)) {
                    isPrimary = true;
                } else {
                    isPrimary = false;
                }
                addPhone(type, phoneNumber, label, isPrimary);
            }
        } else if (propertyName.equals(VCardConstants.PROPERTY_X_SKYPE_PSTNNUMBER)) {
            ...
        } else if (sImMap.containsKey(propertyName)) {
           ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_NOTE)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_URL)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_BDAY)) {
            mBirthday = new BirthdayData(propValue);
        } else if (propertyName.equals(VCardConstants.PROPERTY_ANNIVERSARY)) {
            mAnniversary = new AnniversaryData(propValue);
        } else if (propertyName.equals(VCardConstants.PROPERTY_X_PHONETIC_FIRST_NAME)) {
            mNameData.mPhoneticGiven = propValue;
        } else if (propertyName.equals(VCardConstants.PROPERTY_X_PHONETIC_MIDDLE_NAME)) {
            mNameData.mPhoneticMiddle = propValue;
        } else if (propertyName.equals(VCardConstants.PROPERTY_X_PHONETIC_LAST_NAME)) {
            mNameData.mPhoneticFamily = propValue;
        } else if (propertyName.equals(VCardConstants.PROPERTY_IMPP)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_X_SIP)) {
            ...
        } else if (propertyName.equals(VCardConstants.PROPERTY_X_ANDROID_CUSTOM)) {
            ...
        } else if (propertyName.toUpperCase().startsWith("X-")) {
            ...
        } else {
        }
        // Be careful when adding some logic here, as some blocks above may use "return".
    }

return 注释掉后, 电话号码为空的联系人,也可以正常在车机进行显示了。

相关推荐
深盾科技3 小时前
安卓二次打包技术深度拆解:从逆向篡改到防护逻辑
android
4Forsee3 小时前
【Android】消息机制
android·java·前端
2501_915921434 小时前
iOS 虚拟位置设置实战,多工具协同打造精准调试与场景模拟环境
android·ios·小程序·https·uni-app·iphone·webview
龚礼鹏4 小时前
Android 图像显示框架三——演示demo以及解析
android·交互
QuantumLeap丶5 小时前
《Flutter全栈开发实战指南:从零到高级》- 11 -状态管理Provider
android·flutter·ios
百锦再5 小时前
第6章 结构体与方法
android·java·c++·python·rust·go
gustt5 小时前
用小程序搭建博客首页:从数据驱动到界面展示
android·前端·微信小程序
金鸿客5 小时前
Compose从相册和系统相机拍照获取照片
android
IT乐手6 小时前
Android 获取定位信息工具类
android