時(shí)間好快,轉(zhuǎn)眼又一個(gè)月了叁丧,每天工作很忙啤誊,也沒(méi)有什么時(shí)間學(xué)習(xí)岳瞭,下一篇打算研究一下 framwork 的一些東西。
藍(lán)牙
Android 平臺(tái)包含藍(lán)牙網(wǎng)絡(luò)堆棧支持蚊锹,憑借此項(xiàng)支持瞳筏,設(shè)備能以無(wú)線方式與其他藍(lán)牙設(shè)備交換數(shù)據(jù)。應(yīng)用框架提供了通過(guò) Android Bluetooth API 訪問(wèn)藍(lán)牙功能的途徑牡昆。 這些 API 允許應(yīng)用以無(wú)線方式連接到其他藍(lán)牙設(shè)備姚炕,從而實(shí)現(xiàn)點(diǎn)到點(diǎn)和多點(diǎn)無(wú)線功能。
傳統(tǒng)藍(lán)牙
使用藍(lán)牙進(jìn)行通信的四項(xiàng)主要任務(wù):
- 設(shè)置藍(lán)牙
- 查找局部區(qū)域內(nèi)的配對(duì)設(shè)備或可用設(shè)備
- 連接設(shè)備
- 在設(shè)備之間傳輸數(shù)據(jù)
1丢烘、聲明權(quán)限
<manifest ... >
<uses-permission android:name="android.permission.BLUETOOTH" />
...
</manifest>
2柱宦、設(shè)置藍(lán)牙
- a、獲取 BluetoothAdapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
- b播瞳、啟用藍(lán)牙
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
您的應(yīng)用還可以選擇偵聽(tīng) ACTION_STATE_CHANGED 廣播 Intent掸刊,每當(dāng)藍(lán)牙狀態(tài)發(fā)生變化時(shí),系統(tǒng)都會(huì)廣播此 Intent赢乓。 此廣播包含額外字段
- EXTRA_STATE : 新的藍(lán)牙狀態(tài)
- EXTRA_PREVIOUS_STATE : 舊的藍(lán)牙狀態(tài)
這些額外字段可能的值包括 :
- STATE_TURNING_ON
- STATE_ON
- STATE_TURNING_OFF
- STATE_OFF
偵聽(tīng)此廣播適用于檢測(cè)在您的應(yīng)用運(yùn)行期間對(duì)藍(lán)牙狀態(tài)所做的更改忧侧。
3、查找設(shè)備
設(shè)備發(fā)現(xiàn)是一個(gè)掃描過(guò)程牌芋,它會(huì)搜索局部區(qū)域內(nèi)已啟用藍(lán)牙功能的設(shè)備蚓炬,然后請(qǐng)求一些關(guān)于各臺(tái)設(shè)備的信息。
但局部區(qū)域內(nèi)的藍(lán)牙設(shè)備僅在其當(dāng)前已啟用可檢測(cè)性時(shí)才會(huì)響應(yīng)發(fā)現(xiàn)請(qǐng)求姜贡。
利用此信息试吁,執(zhí)行發(fā)現(xiàn)的設(shè)備可以選擇發(fā)起到被發(fā)現(xiàn)設(shè)備的連接。
請(qǐng)記住楼咳,被配對(duì)與被連接之間存在差別熄捍。被配對(duì)意味著兩臺(tái)設(shè)備知曉彼此的存在,具有可用于身份驗(yàn)證的共享鏈路密鑰母怜,并且能夠與彼此建立加密連接余耽。 被連接意味著設(shè)備當(dāng)前共享一個(gè) RFCOMM 通道,并且能夠向彼此傳輸數(shù)據(jù)苹熏。 當(dāng)前的 Android Bluetooth API 要求對(duì)設(shè)備進(jìn)行配對(duì)碟贾,然后才能建立 RFCOMM 連接。
- a轨域、查詢(xún)配對(duì)的設(shè)備
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
- b袱耽、發(fā)現(xiàn)設(shè)備
要開(kāi)始發(fā)現(xiàn)設(shè)備,只需調(diào)用 startDiscovery()干发。該進(jìn)程為異步進(jìn)程朱巨,并且該方法會(huì)立即返回一個(gè)布爾值,指示是否已成功啟動(dòng)發(fā)現(xiàn)操作枉长。
針對(duì) ACTION_FOUND Intent 注冊(cè)一個(gè) BroadcastReceiver冀续,以便接收每臺(tái)發(fā)現(xiàn)的設(shè)備的相關(guān)信息琼讽。 針對(duì)每臺(tái)設(shè)備,系統(tǒng)將會(huì)廣播 ACTION_FOUND Intent洪唐。此 Intent 將攜帶額外字段
- EXTRA_DEVICE // 包含 BluetoothDevice
- EXTRA_CLASS // 包含 BluetoothClass
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// Add the name and address to an array adapter to show in a ListView
mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
- c钻蹬、啟用可檢測(cè)性
如果您希望將本地設(shè)備設(shè)為可被其他設(shè)備檢測(cè)到,請(qǐng)使用
ACTION_REQUEST_DISCOVERABLE
操作 Intent 凭需,您可以通過(guò)添加 :
EXTRA_DISCOVERABLE_DURATION
Intent Extra 來(lái)定義不同的持續(xù)時(shí)間问欠。 應(yīng)用可以設(shè)置的最大持續(xù)時(shí)間為 3600 秒,值為 0 則表示設(shè)備始終可檢測(cè)到功炮。 任何小于 0 或大于 3600 的值都會(huì)自動(dòng)設(shè)為 120 秒溅潜。 例如,以下片段會(huì)將持續(xù)時(shí)間設(shè)為 300 秒:
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
如果您希望在可檢測(cè)到模式發(fā)生變化時(shí)收到通知薪伏,您可以針對(duì)
ACTION_SCAN_MODE_CHANGED Intent
注冊(cè) BroadcastReceiver滚澜。 它將包含額外字段
- EXTRA_SCAN_MODE
- EXTRA_PREVIOUS_SCAN_MODE
二者分別告知您新的和舊的掃描模式。 每個(gè)字段可能的值包括:
- SCAN_MODE_CONNECTABLE_DISCOVERABLE :可檢測(cè)到模式
- SCAN_MODE_CONNECTABLE :未處于可檢測(cè)到模式但仍能接收連接
- SCAN_MODE_NONE :未處于可檢測(cè)到模式并且無(wú)法接收連接
4嫁怀、連接設(shè)備
要在兩臺(tái)設(shè)備上的應(yīng)用之間創(chuàng)建連接设捐,必須同時(shí)實(shí)現(xiàn)服務(wù)器端和客戶(hù)端機(jī)制,因?yàn)槠渲幸慌_(tái)設(shè)備必須開(kāi)放服務(wù)器套接字塘淑,而另一臺(tái)設(shè)備必須發(fā)起連接(使用服務(wù)器設(shè)備的 MAC 地址發(fā)起連接)萝招。 當(dāng)服務(wù)器和客戶(hù)端在同一 RFCOMM 通道上分別擁有已連接的 BluetoothSocket 時(shí),二者將被視為彼此連接存捺。
藍(lán)牙套接字接口(與 TCP Socket 相似)槐沼。這是允許應(yīng)用通過(guò) InputStream 和 OutputStream 與其他藍(lán)牙設(shè)備交換數(shù)據(jù)的連接點(diǎn)。
- a捌治、連接為服務(wù)器
以下是設(shè)置服務(wù)器套接字并接受連接的基本過(guò)程:
1岗钩、通過(guò)調(diào)用 listenUsingRfcommWithServiceRecord(String, UUID) 獲取 BluetoothServerSocket。
2肖油、通過(guò)調(diào)用 accept() 開(kāi)始偵聽(tīng)連接請(qǐng)求兼吓。
3、除非您想要接受更多連接森枪,否則請(qǐng)調(diào)用 close()视搏。
這將釋放服務(wù)器套接字及其所有資源,但不會(huì)關(guān)閉 accept() 所返回的已連接的 BluetoothSocket县袱。
accept() 調(diào)用不應(yīng)在主 Activity UI 線程中執(zhí)行浑娜,因?yàn)樗亲枞{(diào)用,并會(huì)阻止與應(yīng)用的任何其他交互式散。 在您的應(yīng)用所管理的新線程中使用 BluetoothServerSocket 或 BluetoothSocket 完成所有工作棚愤。
- b、連接為客戶(hù)端
以下是基本過(guò)程:
1、使用 BluetoothDevice宛畦,通過(guò)調(diào)用 createRfcommSocketToServiceRecord(UUID) 獲取 BluetoothSocket。
2揍移、通過(guò)調(diào)用 connect() 發(fā)起連接次和。
系統(tǒng)將會(huì)在遠(yuǎn)程設(shè)備上執(zhí)行 SDP 查找,以便匹配 UUID那伐。 如果查找成功并且遠(yuǎn)程設(shè)備接受了該連接踏施,它將共享 RFCOMM 通道以便在連接期間使用,并且 connect() 將會(huì)返回罕邀。 此方法為阻塞調(diào)用畅形。
- c、管理連接
在成功連接兩臺(tái)(或更多臺(tái))設(shè)備后诉探,每臺(tái)設(shè)備都會(huì)有一個(gè)已連接的 BluetoothSocket日熬。 這一點(diǎn)非常有趣,因?yàn)檫@表示您可以在設(shè)備之間共享數(shù)據(jù)肾胯。 利用 BluetoothSocket竖席,傳輸任意數(shù)據(jù)的一般過(guò)程非常簡(jiǎn)單:
獲取 InputStream 和 OutputStream,二者分別通過(guò)套接字以及 getInputStream() 和 getOutputStream() 來(lái)處理數(shù)據(jù)傳輸敬肚。
使用 read(byte[]) 和 write(byte[]) 讀取數(shù)據(jù)并寫(xiě)入到流式傳輸毕荐。
就這么簡(jiǎn)單。
5艳馒、使用配置文件
從 Android 3.0 開(kāi)始憎亚,Bluetooth API 便支持使用藍(lán)牙配置文件。 藍(lán)牙配置文件是適用于設(shè)備間藍(lán)牙通信的無(wú)線接口規(guī)范弄慰。
對(duì)于連接到無(wú)線耳機(jī)的手機(jī)第美,兩臺(tái)設(shè)備都必須支持 “免提配置文件”。
Android Bluetooth API 提供了以下藍(lán)牙配置文件的實(shí)現(xiàn):
- 耳機(jī)
耳機(jī)配置文件提供了藍(lán)牙耳機(jī)支持曹动,以便與手機(jī)配合使用斋日。
- A2DP
高級(jí)音頻分發(fā)配置文件 (A2DP) 定義了高質(zhì)量音頻如何通過(guò)藍(lán)牙連接和流式傳輸,從一個(gè)設(shè)備傳輸?shù)搅硪粋€(gè)設(shè)備墓陈。 Android 提供了 BluetoothA2dp 類(lèi)恶守,它是用于通過(guò) IPC 來(lái)控制藍(lán)牙 A2DP 服務(wù)的代理。
- 健康設(shè)備
Android 4.0(API 級(jí)別 14)引入了對(duì)藍(lán)牙健康設(shè)備配置文件 (HDP) 的支持贡必。 這允許您創(chuàng)建應(yīng)用兔港,使用藍(lán)牙與支持藍(lán)牙功能的健康設(shè)備進(jìn)行通信,例如心率監(jiān)測(cè)儀仔拟、血糖儀衫樊、溫度計(jì)、臺(tái)秤等等。
以下是使用配置文件的基本步驟:
1科侈、獲取默認(rèn)適配器(請(qǐng)參閱設(shè)置藍(lán)牙)载佳。
2、使用 getProfileProxy() 建立到配置文件所關(guān)聯(lián)的配置文件代理對(duì)象的連接臀栈。在以下示例中蔫慧,配置文件代理對(duì)象是一個(gè) BluetoothHeadset 的實(shí)例。
3权薯、設(shè)置 BluetoothProfile.ServiceListener姑躲。此偵聽(tīng)程序會(huì)在 BluetoothProfile IPC 客戶(hù)端連接到服務(wù)或斷開(kāi)服務(wù)連接時(shí)向其發(fā)送通知。
4盟蚣、在 onServiceConnected() 中黍析,獲取配置文件代理對(duì)象的句柄。
5屎开、獲得配置文件代理對(duì)象后阐枣,可以立即將其用于監(jiān)視連接狀態(tài)和執(zhí)行其他與該配置文件相關(guān)的操作。
以下代碼片段顯示了如何連接到 BluetoothHeadset 代理對(duì)象牍戚,以便能夠控制耳機(jī)配置文件:
BluetoothHeadset mBluetoothHeadset;
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = (BluetoothHeadset) proxy;
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
mBluetoothHeadset = null;
}
}
};
// ... call functions on mBluetoothHeadset
// Close proxy connection after use.
mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);
供應(yīng)商特定的 AT 命令
從 Android 3.0 開(kāi)始侮繁,應(yīng)用可以注冊(cè)接收耳機(jī)所發(fā)送的預(yù)定義的供應(yīng)商特定 AT 命令的系統(tǒng)廣播(例如 Plantronics +XEVENT 命令)。
例如如孝,應(yīng)用可以接收指示所連接設(shè)備的電池電量的廣播宪哩,并根據(jù)需要通知用戶(hù)或采取其他操作。 為
ACTION_VENDOR_SPECIFIC_HEADSET_EVENT intent
創(chuàng)建廣播接收器第晰,以處理耳機(jī)的供應(yīng)商特定 AT 命令锁孟。
下面是獲取藍(lán)牙耳機(jī)電池電量:
/**
* Handle {@link BluetoothHeadset#ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intent
* @param intent must be {@link BluetoothHeadset#ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intent
*/
@VisibleForTesting
void onVendorSpecificHeadsetEvent(Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device == null) {
Log.e(TAG, "onVendorSpecificHeadsetEvent() remote device is null");
return;
}
String cmd =
intent.getStringExtra(BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD);
if (cmd == null) {
Log.e(TAG, "onVendorSpecificHeadsetEvent() command is null");
return;
}
int cmdType = intent.getIntExtra(
BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE, -1);
// Only process set command
if (cmdType != BluetoothHeadset.AT_CMD_TYPE_SET) {
debugLog("onVendorSpecificHeadsetEvent() only SET command is processed");
return;
}
Object[] args = (Object[]) intent.getExtras().get(
BluetoothHeadset.EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS);
if (args == null) {
Log.e(TAG, "onVendorSpecificHeadsetEvent() arguments are null");
return;
}
int batteryPercent = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
switch (cmd) {
case BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT:
batteryPercent = getBatteryLevelFromXEventVsc(args);
break;
case BluetoothHeadset.VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV:
batteryPercent = getBatteryLevelFromAppleBatteryVsc(args);
break;
}
if (batteryPercent != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
updateBatteryLevel(device, batteryPercent);
infoLog("Updated device " + device + " battery level to "
+ String.valueOf(batteryPercent) + "%");
}
}
健康設(shè)備配置文件
源設(shè)備:在 HDP 中定義的角色。源設(shè)備是將醫(yī)療數(shù)據(jù)傳輸?shù)?Android 手機(jī)或平板電腦等智能設(shè)備的健康設(shè)備(體重秤茁瘦、血糖儀品抽、溫度計(jì)等)。
匯集設(shè)備:在 HDP 中定義的角色甜熔。在 HDP 中圆恤,匯集設(shè)備是接收醫(yī)療數(shù)據(jù)的智能設(shè)備。 在 Android HDP 應(yīng)用中腔稀,匯集設(shè)備表示為 BluetoothHealthAppConfiguration 對(duì)象盆昙。
注冊(cè):指的是注冊(cè)特定健康設(shè)備的匯集設(shè)備。
連接:指的是開(kāi)放健康設(shè)備與 Android 手機(jī)或平板電腦等智能設(shè)備之間的通道焊虏。
創(chuàng)建 HDP 應(yīng)用
以下是創(chuàng)建 Android HDP 應(yīng)用所涉及的基本步驟:
1淡喜、獲取 BluetoothHealth 代理對(duì)象的引用。
2诵闭、與常規(guī)耳機(jī)和 A2DP 配置文件設(shè)備相似炼团,您必須使用 BluetoothProfile.ServiceListener 和 HEALTH 配置文件類(lèi)型來(lái)調(diào)用 getProfileProxy()澎嚣,以便與配置文件代理對(duì)象建立連接。
3瘟芝、創(chuàng)建 BluetoothHealthCallback 并注冊(cè)充當(dāng)健康匯集設(shè)備的應(yīng)用配置 (BluetoothHealthAppConfiguration)易桃。
4、建立到健康設(shè)備的連接模狭。一些設(shè)備將會(huì)發(fā)起該連接颈抚。 對(duì)于這類(lèi)設(shè)備,無(wú)需執(zhí)行該步驟嚼鹉。
成功連接到健康設(shè)備后,使用文件描述符對(duì)健康設(shè)備執(zhí)行讀/寫(xiě)操作驱富。
5锚赤、接收的數(shù)據(jù)需要使用實(shí)現(xiàn)了 IEEE 11073-xxxxx 規(guī)范的健康管理器進(jìn)行解釋。
完成后褐鸥,關(guān)閉健康通道并取消注冊(cè)該應(yīng)用线脚。該通道在長(zhǎng)期閑置時(shí)也會(huì)關(guān)閉。