Android?8.0實(shí)現(xiàn)藍(lán)牙遙控器自動配對
本文要實(shí)現(xiàn)的是在 android 8.0 的平臺上,藍(lán)牙遙控器與TV自動配對,具體就是在TV端打開配對界面,TV端開始搜索遠(yuǎn)程藍(lán)牙設(shè)備,按下遙控器按鍵讓藍(lán)牙遙控器進(jìn)入對碼模式,此時(shí)藍(lán)牙遙控器就能作為一個(gè)遠(yuǎn)程藍(lán)牙設(shè)備被發(fā)現(xiàn),TV端掃描到這個(gè)遠(yuǎn)程藍(lán)牙設(shè)備(藍(lán)牙遙控器),就會自動進(jìn)行配對連接。
話不多說,直接上代碼分析。
public class RcConnectActivity extends Activity { ? ? ?? ?private static final String TAG = "RcConnectActivity"; ?? ??? ?private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); ?? ? ? ?private BluetoothDevice mBluetoothDevice; ?? ??? ?private BluetoothReceiver mBluetoothReceiver = null; ?? ??? ?private boolean isConnected = false; ?? ? ?? ? ? ?@Override ?? ? ? ?protected void onCreate(Bundle savedInstanceState) { ?? ??? ??? ?Log.d(TAG, "onCreate"); ?? ? ? ? ? ?super.onCreate(savedInstanceState); ?? ? ? ? ? ?setContentView(R.layout.rc_connect); ?? ??? ??? ?registerReceiver(); ?? ??? ??? ?if (mBluetoothAdapter != null) { ?? ??? ??? ??? ?if (mBluetoothAdapter.isEnabled()) { ?? ??? ??? ??? ??? ?mBluetoothAdapter.startDiscovery(); ?? ??? ??? ??? ??? ?Log.d(TAG, "mBluetoothAdapter.startDiscovery"); ?? ??? ??? ??? ?} else { ?? ??? ??? ??? ??? ?mBluetoothAdapter.enable(); ?? ??? ??? ??? ??? ?Log.d(TAG, "mBluetoothAdapter.enable"); ?? ??? ??? ??? ?} ?? ??? ??? ?} else { ?? ??? ??? ??? ?Toast.makeText(this, R.string.bluetooth_tip, Toast.LENGTH_SHORT).show(); ?? ??? ??? ?} ?? ? ? ?}
首先我們要注冊一個(gè)廣播接收器,用來接收藍(lán)牙掃描搜索配對過程中一些藍(lán)牙相關(guān)的廣播,以便進(jìn)行相對應(yīng)的操作。
public void registerReceiver() { ?? ??? ?Log.d(TAG, "registerReceiver"); ? ? ? ? IntentFilter filter = new IntentFilter(); ? ? ? ? filter.addAction(BluetoothDevice.ACTION_FOUND); ? ? ? ? filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); ? ? ? ? filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); ? ? ? ? filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); ?? ??? ?mBluetoothReceiver = new BluetoothReceiver(); ? ? ? ? registerReceiver(mBluetoothReceiver, filter); ? ? }
BluetoothDevice.ACTION_FOUND 也就是 android.bluetooth.device.action.FOUND,當(dāng)發(fā)現(xiàn)遠(yuǎn)程藍(lán)牙設(shè)備的時(shí)候,系統(tǒng)就會發(fā)出這條廣播。接收這條廣播需要以下權(quán)限。
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED:當(dāng)藍(lán)牙連接狀態(tài)改變時(shí),就會發(fā)送此廣播。
BluetoothAdapter.ACTION_STATE_CHANGED:也就是 android.bluetooth.adapter.action.STATE_CHANGED 當(dāng)本地藍(lán)牙適配器的狀態(tài)改變時(shí),比如打開藍(lán)牙或者關(guān)閉藍(lán)牙的時(shí)候,就會發(fā)送此廣播。
BluetoothAdapter.ACTION_DISCOVERY_FINISHED:當(dāng)本地藍(lán)牙適配器完成設(shè)備掃描搜索過程的時(shí)候,就會發(fā)送此廣播。
注冊完廣播接著就是通過 BluetoothAdapter.getDefaultAdapter() 來獲取本地藍(lán)牙適配器,如果硬件不支持藍(lán)牙的話,那么返回值為null。如果能獲取到,證明TV端是有可用的藍(lán)牙模塊,接著通過 isEnabled() 這個(gè)方法來判斷TV端的藍(lán)牙模塊是否已經(jīng)打開并且可以使用,相當(dāng)于 getBluetoothState() == STATE_ON 。如果已經(jīng)打開藍(lán)牙,那么就可以通過 startDiscovery() 進(jìn)行掃描藍(lán)牙設(shè)備,否則就通過 enable() 來打開藍(lán)牙。
startDiscovery() 需要<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
這個(gè)權(quán)限。
private class BluetoothReceiver extends BroadcastReceiver { ? ? ? ? @Override ? ? ? ? public void onReceive(Context context, Intent intent) { ?? ??? ??? ? ?? ??? ??? ?String action = intent.getAction();? ?? ??? ??? ?Log.d(TAG, "action = " + action); ?? ??? ??? ?if(BluetoothDevice.ACTION_FOUND.equals(action)){? ?? ??? ??? ??? ?mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); ?? ??? ??? ??? ?Log.d(TAG, "find device : " + "[ "+ mBluetoothDevice.getName() +" ]" + ":" + mBluetoothDevice.getAddress()); ?? ??? ??? ??? ? ?? ??? ??? ??? ?if (mBluetoothDevice.getName() == null || !mBluetoothDevice.getName().equals("RCSP")) { ?? ??? ??? ??? ??? ?return; ?? ??? ??? ??? ?} else? ?? ??? ??? ??? ?{ ?? ??? ??? ??? ??? ?if (mBluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) { ?? ??? ??? ??? ??? ??? ?Log.d(TAG, "attemp to bond: " + "[ " + mBluetoothDevice.getName() + " ]"); ?? ??? ??? ??? ??? ??? ?try { ?? ??? ??? ??? ??? ??? ??? ?mBluetoothDevice.createBond(); ?? ??? ??? ??? ??? ??? ??? ?isConnected = true; ?? ??? ??? ??? ??? ??? ?} catch (Exception e) { ?? ??? ??? ??? ??? ??? ??? ?e.printStackTrace(); ?? ??? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ?}? ?? ??? ??? ??? ??? ??? ? ?? ??? ??? ??? ?} ?? ??? ??? ?} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { ?? ??? ??? ??? ?int status = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0); ?? ??? ??? ??? ?if (BluetoothAdapter.STATE_ON == status) { ?? ??? ??? ??? ??? ?mBluetoothAdapter.startDiscovery(); ?? ??? ??? ??? ??? ?Log.d(TAG, "mBluetoothAdapter.startDiscovery---STATE_ON"); ?? ??? ??? ??? ?} ?? ??? ??? ?} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { ?? ??? ??? ??? ?if (!isConnected) { ?? ??? ??? ??? ??? ?mBluetoothAdapter.startDiscovery(); ?? ??? ??? ??? ??? ?Log.d(TAG, "mBluetoothAdapter.startDiscovery---ACTION_DISCOVERY_FINISHED"); ?? ??? ??? ??? ?} ?? ??? ??? ?} else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action)) { ? ? ? ? ? ? ? ? int newState = intent.getExtras().getInt(BluetoothProfile.EXTRA_STATE); ? ? ? ? ? ? ? ? switch (newState) { ? ? ? ? ? ? ? ? ? ? case BluetoothProfile.STATE_CONNECTING: ? ? ? ? ? ? ? ? ? ? ? ? Log.d(TAG, "CONNECTING"); ?? ??? ??? ??? ??? ??? ?Toast.makeText(context, R.string.bluetooth_connecting, Toast.LENGTH_SHORT).show(); ? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? ? ? case BluetoothProfile.STATE_CONNECTED: ?? ??? ??? ??? ??? ??? ?Log.d(TAG, "CONNECTED"); ?? ??? ??? ??? ??? ??? ?Toast.makeText(context, R.string.bluetooth_connected, Toast.LENGTH_SHORT).show(); ? ? ? ? ? ? ? ? ? ? ? ? RcConnectActivity.this.finish(); ? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? } ?? ??? ??? ?}?? ? ? ? ? ? } ? ? }
流程分析:
1、如果TV端的藍(lán)牙模塊已經(jīng)打開,那么就執(zhí)行 startDiscovery(),否則通過 enable() 打開藍(lán)牙,此時(shí)會接收到 BluetoothAdapter.ACTION_STATE_CHANGED 這條廣播。藍(lán)牙有四種狀態(tài),分別是STATE_OFF、STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFF。當(dāng)藍(lán)牙狀態(tài)為STATE_ON,表示藍(lán)牙已經(jīng)打開并且已經(jīng)準(zhǔn)備就緒,此時(shí)才可以進(jìn)行startDiscovery(),否則 startDiscovery() 會返回false,無法掃描搜索遠(yuǎn)程藍(lán)牙設(shè)備。
2、掃描搜索到遠(yuǎn)程設(shè)備之后,判斷是不是目標(biāo)設(shè)備,目標(biāo)設(shè)備藍(lán)牙遙控器的名字為 RCSP 。如果 getName() 獲取到的名字為null,或者不是 RCSP,直接 return,不進(jìn)行任何操作。android 8.0 要對 getName() 為 null 進(jìn)行處理,不然程序會運(yùn)行出錯(cuò)。如果搜索到目標(biāo)設(shè)備,通過 createBond() 方法,實(shí)現(xiàn)自動配對。
3、startDiscovery() 會進(jìn)行大約12秒的掃描搜索,有可能此時(shí)我們的目標(biāo)設(shè)備還沒有進(jìn)入對碼模式,還不能被TV端發(fā)現(xiàn),從而也無法自動配對。當(dāng)掃描搜索完成之后,會發(fā)送 BluetoothAdapter.ACTION_DISCOVERY_FINISHED 這條廣播,此時(shí)我們在判斷目標(biāo)設(shè)備是否已經(jīng)配對連接,如果沒有,再次調(diào)用 startDiscovery() 進(jìn)行掃描搜索。
4、當(dāng)目標(biāo)設(shè)備在進(jìn)行自動配對的時(shí)候,我們通過接收BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED 這條廣播,來判斷目標(biāo)設(shè)備的狀態(tài),并用 Toast 提示配對是否成功。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)類似于PC中的右鍵彈出菜單效果
這篇文章主要介紹了Android實(shí)現(xiàn)類似于PC中的右鍵彈出菜單效果,需要的朋友可以參考下2015-12-12android 仿微信demo——注冊功能實(shí)現(xiàn)(服務(wù)端)
本篇文章主要介紹了微信小程序-閱讀小程序?qū)嵗?,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望能給你們提供幫助2021-06-06Android ViewFlipper翻轉(zhuǎn)視圖使用詳解
這篇文章主要為大家詳細(xì)介紹了Android ViewFlipper翻轉(zhuǎn)視圖的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05Android如何從實(shí)現(xiàn)到封裝一個(gè)MVP詳解
原生的 MVC 框架遇到大規(guī)模的應(yīng)用,就會變得代碼難讀,不好維護(hù),無法測試的囧境。因此,Android 開發(fā)方面也有很多對應(yīng)的框架來解決這些問題。所以這篇文章主要給大家介紹了關(guān)于Android如何從實(shí)現(xiàn)到封裝一個(gè)MVP的相關(guān)資料,需要的朋友可以參考下。2017-09-09Android GestureDetector用戶手勢檢測實(shí)例講解
這篇文章主要為大家詳細(xì)介紹了Android GestureDetector用戶手勢檢測實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03解決android studio 打開java文件 內(nèi)容全變了的問題
這篇文章主要介紹了解決android studio 打開java文件 內(nèi)容全變了的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03