【android bluetooth 协议分析 18】【PBAP详解 2】【车机为何不显示电话号码为空的联系人信息】
一、问题描述
在苹果手机中, 会将 只有名字,没有电话号码的 vcard 传到 车机侧。 但是应用侧确显示不出来。针对这个问题,我们深入探讨一下,究竟是谁把他给过滤掉了。
下面的log 是从 btsnoop 中导出的。
BEGIN:VCARD
VERSION:3.0
FN:空号测试
N:空号测试
TEL:
END:VCARDBEGIN: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
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 注释掉后, 电话号码为空的联系人,也可以正常在车机进行显示了。
