蓝牙pbap协议源码解析
Posted Achillisjack
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝牙pbap协议源码解析相关的知识,希望对你有一定的参考价值。
PBAP协议
使用场景:智能车载中同步联系人等信息
其实,不仅可以同步联系人,还可以同步通话记录等信息。
1.协议概述
协议代码路径:
frameworks\\opt\\bluetooth\\src\\android\\bluetooth\\client\\pbap这个包中
Jar包名称,android.bluetooth.client. pbap
所以进行开发时,在mk文件中需要添加这个包,
并且,在AndroidManifest文件中必须导入Obex库,<uses-libraryandroid:name="javax.obex" />
pbap这个包中文件如下,
使用pbap协议同步联系人/通话记录时的开发流程和其他的协议不一样,并且pbap协议只有客户端,没有服务端. BluetoothPbapClient是其客户端,在此先不看其客户端的方法。
2开发步骤
1) 构造BluetoothPbapClient对象,
2) 调用BluetoothPbapClient对象方法,处理对应的回调消息。
3详细开发过程
3.1构造BluetoothPbapClient
BluetoothPbapClient如何构造呢?源码有2个构造方法,其中一种如下 ,
public BluetoothPbapClient(BluetoothDevice device, Handler handler)
mClientHandler = handler;
mSessionHandler = new SessionHandler(this);
addSdp();
mSession = new BluetoothPbapSession(device, mSessionHandler);
从中可以看到,构造方法有2个参数, device当然是远程蓝牙设备了,这个很容易获取,
另外一个Handler对象,主要用于一些消息的回调,那就先新建一个Handler对象。
所以可以很简单的进行构造,
mPbapClient = new BluetoothPbapClient(device, mPbapHandler);
3.2方法以及回调处理
客户端BluetoothPbapClient的主要方法以及对应的回调消息如下,
方法 |
| 回调消息 |
setPhoneBookFolderRoot | 刷选同步条件/ 根目录/子目录/父目录 |
EVENT_SET_PHONE_BOOK_DONE |
setPhoneBookFolderUp | ||
setPhoneBookFolderDown | ||
pullPhoneBookSize | 电话本大小 | EVENT_PULL_PHONE_BOOK_SIZE_DONE |
pullVcardListingSize | 文件数量 | EVENT_PULL_VCARD_LISTING_SIZE_DONE |
pullPhoneBook | 同步电话本 | EVENT_PULL_PHONE_BOOK_DONE |
pullVcardListing | 同步文件 | EVENT_PULL_VCARD_LISTING_DONE |
pullVcardEntry | 同步单个文件 | EVENT_PULL_VCARD_DONE |
BluetoothPbapClient一些字符串定义如下,
public static final String ICH_PATH = "telecom/ich.vcf"; // 手机来电记录
public static final String OCH_PATH = "telecom/och.vcf"; // 手机去电记录
public static final String MCH_PATH = "telecom/mch.vcf";// 手机未接电话记录
public static final String CCH_PATH = "telecom/cch.vcf"; // 所有通话记录
public static final String PB_PATH = "telecom/pb.vcf"; // 手机联系人
对应的SIM卡上的通话记录以及联系人路径如下,
public static final String SIM_ICH_PATH = "SIM1/telecom/ich.vcf";
public static final String SIM_OCH_PATH = "SIM1/telecom/och.vcf";
public static final String SIM_MCH_PATH = "SIM1/telecom/mch.vcf";
public static final String SIM_CCH_PATH = "SIM1/telecom/cch.vcf";
public static final String SIM_PB_PATH = "SIM1/telecom/pb.vcf";
同步联系人的详细开发如下,
设置路径,调用pullPhoneBook方法,
private String mDownloadSpinner = "telecom/pb.vcf";
mPbapClient. pullPhoneBook(mDownloadSpinner);
回调处理
ArrayList<VCardEntry>pullPhoneBook; // 保存同步的联系人
private final Handler mPbapHandler = new Handler()
@Override
public void handleMessage(Message msg)
switch (msg.what)
case BluetoothPbapClient.EVENT_PULL_PHONE_BOOK_DONE:
pullPhoneBook = (ArrayList<VCardEntry>) msg.obj;
break;
;
到此, pullPhoneBook就保存了同步的联系人,后续就可以进行处理了。
同样的,也可以设置其他路径以方法同步通话记录等。
ArrayList<BluetoothPbapCard> pullVcardListing = null; // 保存同步文件
VCardEntry pullVcardEntry = null; // 保存同步单个文件
4流程图
同步的方法调用流程几乎是一模一样的,所以以pullPhoneBook方法为例,
流程图很简单,没有跨进程通信,只是单开一个线程同步联系人,每个联系人对应一个VCardEntry对象。VCardEntry对象在VCardEntryConstructor类中创建,在BluetoothPbapVcardList的内部类CardEntryHandler的onEntryCreated方法添加到名为mCards的ArrayList中。同步完之后, BluetoothPbapClient中的SessionHandler对象首先获取mCards,然后通过EVENT_PULL_PHONE_BOOK_DONE消息将mCards(VCardEntry数组)发出,因此在开发时处理该消息就可以获取同步的联系人。
5 VCardEntry简析
VCardEntry可以保存联系人/通话记录的各种信息,看枚举EntryLabel
public enum EntryLabel NAME, PHONE, EMAIL, POSTAL_ADDRESS, ORGANIZATION, IM, PHOTO, WEBSITE, SIP, NICKNAME, NOTE, BIRTHDAY, ANNIVERSARY, ANDROID_CUSTOM
|
|
每一个枚举对象都对应一个联系人信息,比如名字/电话号码,也对应一个VCardEntry的内部类,它们都继承内部接口EntryElement。
看下VCardParser_V21类parseOneVCard方法
private boolean parseOneVCard() throws IOException, VCardException
// reset for this entire vCard.
mCurrentEncoding = DEFAULT_ENCODING;
mCurrentCharset = DEFAULT_CHARSET;
boolean allowGarbage = false;
if (!readBeginVCard(allowGarbage))
return false;
for (VCardInterpreter interpreter : mInterpreterList)
interpreter.onEntryStarted();
parseItems();
for (VCardInterpreter interpreter : mInterpreterList)
interpreter.onEntryEnded();
return true;
onEntryStarted最后会构造VCardEntry, parseItems会调用VCardEntry的addProperty方法完成各种信息的保存,最后调用onEntryEnded将所有VCardEntry对象打包到ArrayList中。
在这14个枚举中,并没有时间信息,即使是获取通话记录,也并没有时间的信息。如何同步时间信息呢?
查看PBAP协议,有一个这样的字段,X-IRMC-CALL-DATETIME,说明可以同步时间信息的。通过对VCardParserImpl_V21和VCardEntry的addProperty方法进行调试,发现X-IRMC-CALL-DATETIME参数是有输出的,只是VCardEntry中没有该枚举和对应的类而已。在VCardEntry中添加枚举和对应的内部类就可以实现同步时间的功能。
1,,在枚举EntryLabel最后添加一项,
DATETIME
2,, 添加对应的内部类
public static class DatetimeData implements EntryElement
private final String mDatetime;
public DatetimeData(String datetime)
mDatetime = datetime;
@Override
public EntryLabel getEntryLabel()
return EntryLabel. DATETIME;
@Override
public boolean isEmpty()
return TextUtils.isEmpty(mDatetime);
@Override
public void constructInsertOperation(List<ContentProviderOperation>
operationList, int backReferenceIndex)
@Override
public boolean equals(Object obj)
if (this == obj)
return true;
if (!(obj instanceof DatetimeData))
return false;
DatetimeData datetimeData = (DatetimeData) obj;
return TextUtils.equals(mDatetime, datetimeData.mDatetime);
@Override
public int hashCode()
return mDatetime != null ? mDatetime.hashCode() : 0;
@Override
public String toString()
return "call datetime: " + mDatetime;
public String getCallDatetime()
return mDatetime;
3,addProperty 方法
if(propertyName.equals(VCardConstants.PROPERTY_ DATETIME))
mDatetimeData = new DatetimeData(propValue);
4,,添加getter方法
public final String getCallDatetime()
return mCallDatetimeData != null ? mCallDatetimeData.mCallDatetime : null;
在VCardConstants类中添加字符串,
public static final String PROPERTY_ DATETIME = "X-IRMC-CALL-DATETIME";
以上是关于蓝牙pbap协议源码解析的主要内容,如果未能解决你的问题,请参考以下文章
[RK3568][Android11]蓝牙通讯协议PhoneBookAccessProfile(PBAP)同步通讯录
除了 6 个配置文件(HFP、PBAP、A2DP、AVRCP、PAN、HID)之外,iOS 中是不是有任何受支持的蓝牙配置文件?