你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
Android蓝牙——HID开发
立即下载
用AI写一个
金额:
2
元
支付方式:
友情提醒:源码购买后不支持退换货
立即支付
我要免费下载
发布时间:2018-08-24
197人
|
浏览:17760次
|
收藏
|
分享
技术:java+Android4.4+jdk1.8
运行环境:Android8.0(华为V10)
概述
Android蓝牙开发——hid,连接蓝牙鼠标、键盘等输入设备。
详细
# 原文地址: https://blog.csdn.net/VNanyesheshou/article/details/61914974 # 一 环境 开发环境: jdk1.6 Eclipse or jdk1.8 AS3.0.1 运行环境: 华为V10(Android8.0) 实现功能: Android 蓝牙Hid——连接蓝牙鼠标、键盘等输入设备。 # 二 代码结构 ![AS](/contentImages/image/20180823/Ul4AereN6ds63H6ASai.png "AS") ![Eclipse](/contentImages/image/20180823/z5voFsWYFm2qqmw7A9d.png "Eclipse") # 三、代码 ### 1 Hid简介 HID设备(Hunman Interface Device Profile),即人机交互设备,常见的有鼠标,键盘,游戏手柄,等等。一般有线方式都是通过USB连线连接到机器设备,作为用户输入设备。在蓝牙技术中,HID设备的接入就是无线的了。 网上查资料说hid从android4.0开始支持(可能是usb hid),不过蓝牙hid应该从android4.2开始支持的,如下图所示: ![](https://img-blog.csdn.net/20170313113645190) android4.1.2中的Bluetooth应用中没有hid的相关代码,而android4.2源码中Bluetooth应用中才有hid的代码。 ![](https://img-blog.csdn.net/20170313113633799) ### 2 实现 连接hid设备步骤: 1. 开启蓝牙 2. 获得inputDevice profile 3. 扫描 4. 配对 5. 连接 #### 2.1 开启蓝牙,通过广播接收者监听蓝牙相关状态。 ```java 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); ``` #### 2.2 获得inputDevice profile // 4.2以上才支持HID模式 if (Build.VERSION.SDK_INT >= 17) { mHidUtil = HidUtil.getInstance(this); } ```java 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。 ```java 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的子类)。 获取到输入设备的代理对象,之后就可以进行连接操作了。 #### 2.3 扫描(点击连接按钮开始扫描蓝牙设备) ```java mBluetoothAdapter.startDiscovery(); ``` #### 2.4 配对 广播接收者监听扫描到蓝牙设备,过滤出所需蓝牙设备进行配对,如果之前配对过则直接连接。 ```java 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类中的配对方法: ```java /** * 配对 * @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(); } } ``` #### 2.5 连接(配对成功后) ```java 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 方法 ```java /** * 连接设备 * @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方法是隐藏的,所以需要通过反射机制获取该方法进行调用。 #### 2.6 监听连接状态 通过广播接收者监听连接状态。 ```java 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(); } } ``` #### 2.7 断开连接 ```java if(mConnectDevice != null) mHidUtil.disConnect(mConnectDevice); ``` HidUtil中disconnect方法 ```java /** * 断开连接 * @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(); } } ``` 手机端断开连接后,重新连接会提示“只能有鼠标发起重新连接请求,请使用鼠标重新连接”。 ### 3 接收数据 adb shell getevent -l 当连接成功后,会看到如下内容: ```java could not get driver version for /dev/input/mouse1, Not a typewriter add device 7: /dev/input/event6 name: "Bluetooth Mouse" ``` 这表示蓝牙鼠标成为一个输入设备。 左击鼠标: ```cpp /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 ``` 我们应用中打印 ```java 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 } ``` 表示在屏幕中某位置处点击了一下。 右击鼠标: ```cpp /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。
true
## 欢迎关注我的微信公众号: ![](https://img-blog.csdn.net/20170415165019939)
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
5
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
zpengyong
15
例子数量
3604
帮助
125
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
基于FFmpeg的音频编码(PCM数据编码成AAC android)
Android基于TCP的局域网聊天通信
Android 进程间通信——Service、Messenger
AsyncTask 异步任务基本使用-下载视频
Android IntentService使用
Android HandlerThread详解
Eclipse集成ijkplayer并实现本地和网络视频播放等
Android WiFi开发
Android -传统蓝牙通信聊天
Android 进程间通信——AIDL
Android -BLE蓝牙小DEMO
Android蓝牙——HID开发
Android8.0及以上系统 WiFi热点 版本适配
Android WiFi直连 双向通信
Android蓝牙A2DP连接实现