Android HID设备的连接
2016-06-11 13:48
309 查看
Hid是Human Interface Device的缩写,由其名称可以了解HID设备是直接与人交互的设备,例如键盘、鼠标与游戏手柄等。
我们知道在手机设置--蓝牙功能界面可以手动搜索蓝牙HID设备并进行连接,这篇博客就是介绍如何在android代码中实现HID设备的连接。最后会给出完整的代码工程。一个前提条件是android4.0以上才支持HID设备。
android手机与蓝牙HID设备连接的步骤:
1.开启蓝牙功能
2.手机搜索蓝牙HID设备
3.得到BluetoothDevice,配对HID设备
4.连接HID设备
了解过蓝牙开发的同学相信前面3个步骤都不是问题,本文会重点介绍第四个步骤,前面的步骤简单列出来。
1.开启蓝牙功能
2.手机搜索蓝牙HID设备
3.配对HID设备
搜索到蓝牙设备后系统会发送这个广播
BluetoothDevice.ACTION_FOUND
通过监听这个广播就可以得到BluetoothDevice
//通过广播接收到了BluetoothDevice
然后通过反射配对BluetoothDevice
相信以上步骤大家都十分了解了,下面最重要的部分来了。
4.连接HID设备
找遍所有公开的api中是没用方法可以直接连接HID设备的,既然手机设置-蓝牙界面可以连接HID设备,说明系统是可以做到的,那是不是把这个方法隐藏了,我们带着这个疑问去源码看看。
1)首先我们找到android/bluetooth/BluetoothProfile.class这个类
为什么是先找到这个类?
Bluetooth的一个很重要特性,就是所有的Bluetooth产品都无须实现全部的Bluetooth规范。为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规范中定义了Profile。Profile定义了设备如何实现一种连接或者应用,你可以把Profile理解为连接层或者应用层协议。
所以我们要先确认HID设备属于哪种Profile。
找到定义的INPUT_DEVICE,这就是我们HID设备的Profile,字面意思就是输入设备。
2)找到BluetoothProfile的子类BluetoothInputDevice
查看到该类里面的connect方法,入参BluetoothDevice,我们通过步骤三已经得到BluetoothDevice,我们大胆猜想是不是调用这个方法就可以实现连接了呢。
我们再来看下该类的说明
首先注意到该类是个隐藏类并不能直接调用,调用方法已经进行说明了。通过BluetoothAdapter#getProfileProxy方法得到隐藏类BluetoothInputDevice
3)BluetoothAdapter#getProfileProxy方法
第一个参数就不用说了,我们先看第三个参数 int profile,前面介绍了INPUT_DEVICE,这就是我们HID设备的Profile,我们看到也是隐藏字段,所以我们必须先通过反射获得这个参数。方法如下:
那我们再看第二个参数BluetoothProfile.ServiceListener,这个参数可以回调出BluetoothInputDevice,然后再反射connect方法。
最后HID设备连接成功,事实证明我们的猜想是正确的。
项目下载地址:
https://github.com/liushenwenyuan/HIDConnect
http://download.csdn.net/detail/szydwy/9546246
我们知道在手机设置--蓝牙功能界面可以手动搜索蓝牙HID设备并进行连接,这篇博客就是介绍如何在android代码中实现HID设备的连接。最后会给出完整的代码工程。一个前提条件是android4.0以上才支持HID设备。
android手机与蓝牙HID设备连接的步骤:
1.开启蓝牙功能
2.手机搜索蓝牙HID设备
3.得到BluetoothDevice,配对HID设备
4.连接HID设备
了解过蓝牙开发的同学相信前面3个步骤都不是问题,本文会重点介绍第四个步骤,前面的步骤简单列出来。
1.开启蓝牙功能
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Toast.makeText(this,"不支持蓝牙功能",0).show(); //不支持蓝牙 return; } //如果没有打开蓝牙 if (!mBluetoothAdapter.isEnabled()) { mBluetoothAdapter.enable(); }
2.手机搜索蓝牙HID设备
//扫描蓝牙设备 if (!mBluetoothAdapter.isDiscovering()) { mBluetoothAdapter.startDiscovery(); }
3.配对HID设备
搜索到蓝牙设备后系统会发送这个广播
BluetoothDevice.ACTION_FOUND
通过监听这个广播就可以得到BluetoothDevice
//通过广播接收到了BluetoothDevice
final BluetoothDevice localBluetoothDevice = (BluetoothDevice) intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
然后通过反射配对BluetoothDevice
/** * 配对 * @param bluetoothDevice */ public void pair(BluetoothDevice bluetoothDevice) { device = bluetoothDevice; Method createBondMethod; try { createBondMethod = BluetoothDevice.class.getMethod("createBond"); createBondMethod.invoke(device); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }
相信以上步骤大家都十分了解了,下面最重要的部分来了。
4.连接HID设备
找遍所有公开的api中是没用方法可以直接连接HID设备的,既然手机设置-蓝牙界面可以连接HID设备,说明系统是可以做到的,那是不是把这个方法隐藏了,我们带着这个疑问去源码看看。
1)首先我们找到android/bluetooth/BluetoothProfile.class这个类
为什么是先找到这个类?
Bluetooth的一个很重要特性,就是所有的Bluetooth产品都无须实现全部的Bluetooth规范。为了更容易的保持Bluetooth设备之间的兼容,Bluetooth规范中定义了Profile。Profile定义了设备如何实现一种连接或者应用,你可以把Profile理解为连接层或者应用层协议。
所以我们要先确认HID设备属于哪种Profile。
/** * Input Device Profile * @hide */ public static final int INPUT_DEVICE = 4;
找到定义的INPUT_DEVICE,这就是我们HID设备的Profile,字面意思就是输入设备。
2)找到BluetoothProfile的子类BluetoothInputDevice
查看到该类里面的connect方法,入参BluetoothDevice,我们通过步骤三已经得到BluetoothDevice,我们大胆猜想是不是调用这个方法就可以实现连接了呢。
/** * Initiate connection to a profile of the remote bluetooth device. * * <p> The system supports connection to multiple input devices. * * <p> This API returns false in scenarios like the profile on the * device is already connected or Bluetooth is not turned on. * When this API returns true, it is guaranteed that * connection state intent for the profile will be broadcasted with * the state. Users can get the connection state of the profile * from this intent. * * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * permission. * * @param device Remote Bluetooth Device * @return false on immediate error, * true otherwise * @hide */ public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); if (mService != null && isEnabled() && isValidDevice(device)) { try { return mService.connect(device); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; }
我们再来看下该类的说明
/** * This class provides the public APIs to control the Bluetooth Input * Device Profile. * *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get * the BluetoothInputDevice proxy object. * *<p>Each method is protected with its appropriate permission. *@hide */
首先注意到该类是个隐藏类并不能直接调用,调用方法已经进行说明了。通过BluetoothAdapter#getProfileProxy方法得到隐藏类BluetoothInputDevice
3)BluetoothAdapter#getProfileProxy方法
* @param context Context of the application * @param listener The service Listener for connection callbacks. * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH}, * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}. * {@link BluetoothProfile#GATT} or {@link BluetoothProfile#GATT_SERVER}. * @return true on success, false on error */ public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)
第一个参数就不用说了,我们先看第三个参数 int profile,前面介绍了INPUT_DEVICE,这就是我们HID设备的Profile,我们看到也是隐藏字段,所以我们必须先通过反射获得这个参数。方法如下:
public static int getInputDeviceHiddenConstant() { Class<BluetoothProfile> clazz = BluetoothProfile.class; for (Field f : clazz.getFields()) { int mod = f.getModifiers(); if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) { try { if (f.getName().equals("INPUT_DEVICE")) { return f.getInt(null); } } catch (Exception e) { } } } return -1; }
那我们再看第二个参数BluetoothProfile.ServiceListener,这个参数可以回调出BluetoothInputDevice,然后再反射connect方法。
/** *查看BluetoothInputDevice源码,connect(BluetoothDevice device)该方法可以连接HID设备,但是查看BluetoothInputDevice这个类 * 是隐藏类,无法直接使用,必须先通过BluetoothProfile.ServiceListener回调得到BluetoothInputDevice,然后再反射connect方法连接 * */ private BluetoothProfile.ServiceListener connect = new BluetoothProfile.ServiceListener() { @Override public void onServiceConnected(int profile, BluetoothProfile proxy) { //BluetoothProfile proxy这个已经是BluetoothInputDevice类型了 try { if (profile == getInputDeviceHiddenConstant()) { if (device != null) { //得到BluetoothInputDevice然后反射connect连接设备 Method method = proxy.getClass().getMethod("connect", new Class[] { BluetoothDevice.class }); method.invoke(proxy, device); } } } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); } } @Override public void onServiceDisconnected(int profile) { } };
最后HID设备连接成功,事实证明我们的猜想是正确的。
项目下载地址:
https://github.com/liushenwenyuan/HIDConnect
http://download.csdn.net/detail/szydwy/9546246
相关文章推荐
- Windows系统中使用C#编写蓝牙通信程序的简单实例
- android通过蓝牙接收文件打开时无法自动选择合适的应用程序
- Android开发中编写蓝牙相关功能的核心代码讲解
- Android系统中的蓝牙连接程序编写实例教程
- Android设备间实现蓝牙(Bluetooth)共享上网
- Android提高之蓝牙隐藏API探秘
- Android编程之蓝牙测试实例
- Android提高之蓝牙传感应用实例
- Android Bluetooth蓝牙技术使用流程详解
- Android Bluetooth蓝牙技术初体验
- Android 蓝牙防丢实现(一)
- Win10如何使用蓝牙传输文件?Win10使用蓝牙传输文件的方法
- 蓝牙与红外传输
- 蓝牙-信息时代的黑马
- 玩转Blueteeth Chat蓝牙交友
- SyncML在蓝牙车载免提装置中的应用
- 手机指令大全,需要可以看看
- 蓝牙英文-译文
- ***工具