代碼地址以下:<br>http://www.demodashi.com/demo/13891.htmlhtml
https://blog.csdn.net/VNanyesheshou/article/details/61914974java
開發環境: jdk1.6 Eclipse or jdk1.8 AS3.0.1 運行環境: 華爲V10(Android8.0) 實現功能: Android 藍牙Hid——鏈接藍牙鼠標、鍵盤等輸入設備。android
HID設備(Hunman Interface Device Profile),即人機交互設備,常見的有鼠標,鍵盤,遊戲手柄,等等。通常有線方式都是經過USB連線鏈接到機器設備,做爲用戶輸入設備。在藍牙技術中,HID設備的接入就是無線的了。shell
網上查資料說hid從android4.0開始支持(多是usb hid),不過藍牙hid應該從android4.2開始支持的,以下圖所示: android4.1.2中的Bluetooth應用中沒有hid的相關代碼,而android4.2源碼中Bluetooth應用中才有hid的代碼。 微信
鏈接hid設備步驟:app
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Toast.makeText(this, "不支持藍牙功能", 0).show(); // 不支持藍牙 return; } // 若是沒有打開藍牙 if (!mBluetoothAdapter.isEnabled()) { mBluetoothAdapter.enable(); } // 初始化廣播接收者 mBroadcastReceiver = new BlueBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); intentFilter.addAction("android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"); this.registerReceiver(mBroadcastReceiver, intentFilter);
// 4.2以上才支持HID模式 if (Build.VERSION.SDK_INT >= 17) { mHidUtil = HidUtil.getInstance(this); }ide
public static HidUtil getInstance(Context context){ if(null == instance){ instance = new HidUtil(context); } return instance; } private HidUtil(Context context) { this.context = context; mBtAdapter = BluetoothAdapter.getDefaultAdapter(); try { mBtAdapter.getProfileProxy(context, mListener, INPUT_DEVICE); } catch (Exception e) { e.printStackTrace(); } }
經過BluetoothAdapter對象調用getProfileProxy()函數獲取代理藍牙輸入設備代理對象。函數
其中參數mListener必須實現BluetoothProfile.ServiceListener()。獲取代理對象成功或失敗都會回調該Listener。ui
private BluetoothProfile.ServiceListener mListener = new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { Log.i(TAG, "mConnectListener onServiceConnected"); //BluetoothProfile proxy這個已是BluetoothInputDevice類型了 try { if (profile == INPUT_DEVICE) { mBluetoothProfile = proxy; } } catch (Exception e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(int profile) { Log.i(TAG, "mConnectListener onServiceConnected"); } };
當鏈接代理服務成功,回調onServiceConnected()函數,失敗則回調onServiceDisconnected()函數。 其中onServiceConnected()中的參數proxy類型爲BluetoothProfile,這裏由於獲取BluetoothHeadset、BluetoothA2dp對象也要使用該回調函數,因此參數類型設置爲BluetoothInputDevice、BluetoothHeadset、BluetoothA2dp的父類。這裏能夠將其轉換成BluetoothInputDevice類型(BluetoothInputDevice是BluetoothProfile的子類)。this
獲取到輸入設備的代理對象,以後就能夠進行鏈接操做了。
mBluetoothAdapter.startDiscovery();
廣播接收者監聽掃描到藍牙設備,過濾出所需藍牙設備進行配對,若是以前配對過則直接鏈接。
if(action.equals(BluetoothDevice.ACTION_FOUND)){ // 經過廣播接收到了BluetoothDevice final BluetoothDevice device = (BluetoothDevice) intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device == null) return; String btname = device.getName(); String address = device.getAddress(); Log.i(TAG, "bluetooth name:"+btname+",address:"+address); if((address != null&& address.equals(HID_ADDR))||(btname != null && btname.equals(HID_NAME))){ mConnectDevice = device; mBluetoothAdapter.cancelDiscovery(); if(!mHidUtil.isBonded(device)){ //先配對 mHidUtil.pair(device); }else { //已經配對則直接鏈接 mHidUtil.connect(device); } } }
HidUtil類中的配對方法:
/** * 配對 * @param BluetoothDevice */ public void pair(BluetoothDevice device) { Log.i(TAG, "pair device:"+device); Method createBondMethod; try { createBondMethod = BluetoothDevice.class.getMethod("createBond"); createBondMethod.invoke(device); } catch (Exception e) { e.printStackTrace(); } }
if(action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){ BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String name = device.getName(); String address = device.getAddress(); Log.i(TAG,"name:"+name+",address:"+address+",bondstate:"+device.getBondState()); if((address != null&& address.equals(HID_ADDR))||(name != null && name.equals(HID_NAME))){ if(device.getBondState() == BluetoothDevice.BOND_BONDED) mHidUtil.connect(device); } }
判斷是不是要鏈接的輸入設備,若是符合條件則進行鏈接。
HidUtil中connect 方法
/** * 鏈接設備 * @param bluetoothDevice */ public void connect(final BluetoothDevice device) { Log.i(TAG, "connect device:"+device); try { //獲得BluetoothInputDevice而後反射connect鏈接設備 Method method = mBluetoothProfile.getClass().getMethod("connect", new Class[] { BluetoothDevice.class }); method.invoke(mBluetoothProfile, device); } catch (Exception e) { e.printStackTrace(); } }
BluetoothInputDevice中的connect方法是隱藏的,因此須要經過反射機制獲取該方法進行調用。
經過廣播接收者監聽鏈接狀態。
if(action.equals("android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED")){ int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,0); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); Log.i(TAG,"state="+state+",device="+device); if(state == BluetoothProfile.STATE_CONNECTED){//鏈接成功 Toast.makeText(MainActivity.this, R.string.connnect_success, Toast.LENGTH_SHORT).show(); } else if(state == BluetoothProfile.STATE_DISCONNECTED){//鏈接失敗 Toast.makeText(MainActivity.this, R.string.disconnected, Toast.LENGTH_SHORT).show(); } }
if(mConnectDevice != null) mHidUtil.disConnect(mConnectDevice);
HidUtil中disconnect方法
/** * 斷開鏈接 * @param BluetoothDevice */ public void disConnect(BluetoothDevice device) { Log.i(TAG, "disConnect device:"+device); try { if (device != null) { Method method = mBluetoothProfile.getClass().getMethod("disconnect", new Class[] { BluetoothDevice.class }); method.invoke(mBluetoothProfile, device); } } catch (Exception e) { e.printStackTrace(); } }
手機端斷開鏈接後,從新鏈接會提示「只能有鼠標發起從新鏈接請求,請使用鼠標從新鏈接」。
adb shell getevent -l 當鏈接成功後,會看到以下內容:
could not get driver version for /dev/input/mouse1, Not a typewriter add device 7: /dev/input/event6 name: "Bluetooth Mouse"
這表示藍牙鼠標成爲一個輸入設備。
左擊鼠標:
/dev/input/event6: EV_MSC MSC_SCAN 00090001 /dev/input/event6: EV_KEY BTN_MOUSE DOWN /dev/input/event6: EV_SYN SYN_REPORT 00000000 /dev/input/event6: EV_MSC MSC_SCAN 00090001 /dev/input/event6: EV_KEY BTN_MOUSE UP /dev/input/event6: EV_SYN SYN_REPORT 00000000
咱們應用中打印
03-13 12:08:36.526 I/MainActivity(23670): dispatchTouchEvent ev:MotionEvent { action=ACTION_DOWN, actionButton=0, id[0]=0, x[0]=269.7555, y[0]=543.9628, toolType[0]=TOOL_TYPE_MOUSE, buttonState=BUTTON_PRIMARY, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=16788085, downTime=16788085, deviceId=39, source=0x2002 } 03-13 12:08:36.653 I/MainActivity(23670): dispatchTouchEvent ev:MotionEvent { action=ACTION_UP, actionButton=0, id[0]=0, x[0]=269.7555, y[0]=543.9628, toolType[0]=TOOL_TYPE_MOUSE, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=16788216, downTime=16788085, deviceId=39, source=0x2002 }
表示在屏幕中某位置處點擊了一下。
右擊鼠標:
/dev/input/event6: EV_MSC MSC_SCAN 00090002 /dev/input/event6: EV_KEY BTN_RIGHT DOWN /dev/input/event6: EV_SYN SYN_REPORT 00000000 /dev/input/event6: EV_MSC MSC_SCAN 00090002 /dev/input/event6: EV_KEY BTN_RIGHT UP /dev/input/event6: EV_SYN SYN_REPORT 00000000
表示點擊了一下返回鍵,程序退出。
移動鼠標會發現屏幕上小光標在移動,滑動鼠標也會觸發相應事件。 4 其餘 如今大部分手機是支持hid的,而且也將該功能打開狀態。
若是是作系統開發,就須要注意將Bluetooth中的hid開關打開。 將源碼中的packages/apps/Bluetooth/res/values/config.xml的profile_supported_hid 修改成true。 <bool name="profile_supported_hid">true</bool>
Android藍牙——HID開發
代碼地址以下:<br>http://www.demodashi.com/demo/13891.html
注:本文著做權歸做者,由demo大師代發,拒絕轉載,轉載須要做者受權