【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 注释掉后, 电话号码为空的联系人,也可以正常在车机进行显示了。

相关推荐
ktl18 小时前
Android 编译加速/优化 80%:一个文件搞定,零侵入零配置
android
alexhilton1 天前
使用FunctionGemma进行设备端函数调用
android·kotlin·android jetpack
冬奇Lab1 天前
InputManagerService:输入事件分发与ANR机制
android·源码阅读
张小潇1 天前
AOSP15 Input专题InputManager源码分析
android·操作系统
RdoZam2 天前
Android-封装基类Activity\Fragment,从0到1记录
android·kotlin
奥陌陌2 天前
android 打印函数调用堆栈
android
用户985120035832 天前
Compose Navigation 3 深度解析(二):基础用法
android·android jetpack
恋猫de小郭2 天前
Android 官方正式官宣 AI 支持 AppFunctions ,Android 官方 MCP 和系统级 OpenClaw 雏形
android·前端·flutter
黄林晴2 天前
Android 17 Beta 2,隐私这把锁又拧紧了
android
Kapaseker2 天前
研究表明,开发者对Kotlin集合的了解不到 20%
android·kotlin