Android Bluetooth HID实现详解

来源:互联网 发布:linux 运维常见命令 编辑:程序博客网 时间:2024/05/18 02:29

Android Bluetooth HID实现详解

Android 关于蓝牙的部分使用的是BlueZ协议栈。但是直到目前2.3.3都没有扩展HID的profile,只是实现了最基本的Handset和d2dp的profile,所以我们的工作涉及到从应用到jni三层的修改,具体修改文件如图所示,绿色表示新建的类,橙色表示修改的类。

 

一. 本地层

路径:framework/base/core/jni/

参照android_server_BluetoothA2dpService.cpp新建android_server_bluetoothHidServer.cpp。该类中主要是通过dbus对bluez协议栈的访问,dbus 的通用方法都在android_bluetooth_common.cpp中实现,我们做的仅仅是通过dbus_func_args_async调用到bluez提供的input接口。

主要实现以下两个方法函数:

+ expand sourceview plainprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. static jboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) {  
  2.   
  3. #ifdef HAVE_BLUETOOTH  
  4.   
  5.     LOGV(__FUNCTION__);  
  6.   
  7.     if (nat) {  
  8.   
  9.         const char *c_path = env->GetStringUTFChars(path, NULL);  
  10.   
  11.    
  12.   
  13.         bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,  
  14.   
  15.                                     c_path, "org.bluez.Input", "Connect",  
  16.   
  17.                                     DBUS_TYPE_INVALID);  
  18.   
  19.    
  20.   
  21.         env->ReleaseStringUTFChars(path, c_path);  
  22.   
  23.         return ret ? JNI_TRUE : JNI_FALSE;  
  24.   
  25.     }  
  26.   
  27. #endif  
  28.   
  29.     return JNI_FALSE;  
  30.   
  31. }  
  32.   
  33.    
  34.   
  35. static jboolean disconnectSinkNative(JNIEnv *env, jobject object,  
  36.   
  37.                                      jstring path) {  
  38.   
  39. #ifdef HAVE_BLUETOOTH  
  40.   
  41.     LOGV(__FUNCTION__);  
  42.   
  43.     if (nat) {  
  44.   
  45.         const char *c_path = env->GetStringUTFChars(path, NULL);  
  46.   
  47.    
  48.   
  49.         bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,  
  50.   
  51.                                     c_path, "org.bluez.Input", "Disconnect",  
  52.   
  53.                                     DBUS_TYPE_INVALID);  
  54.   
  55.    
  56.   
  57.         env->ReleaseStringUTFChars(path, c_path);  
  58.   
  59.         return ret ? JNI_TRUE : JNI_FALSE;  
  60.   
  61.     }  
  62.   
  63. #endif  
  64.   
  65.     return JNI_FALSE;  
  66.   
  67. }  
  

这里要注意将该文件添加到AndroidRuntime.cpp和Android.mk中,否则不会编译到动态库中。

此部分编译后最终生成libandroid_runtime.so并替换到system/libs下

二.Framework的java部分

路径framework/base/java/android/server/中添加BluetoothHidService.java文件

路径framework/base/java/android/bluetooth/中添加BluetoothHid.java和IBluetoothHid.aidl文件。

view plainprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. interface IBluetoothHid {  
  2.   
  3.     boolean connect(in BluetoothDevice device);  
  4.   
  5.     boolean disconnect(in BluetoothDevice device);  
  6.   
  7.     int getState(in BluetoothDevice device);  
  8.   
  9.     boolean setPriority(in BluetoothDevice device, int priority);  
  10.   
  11.     int getPriority(in BluetoothDevice device);  
  12.   
  13. }  

BluetoothHid.java中主要的两个方法connect和disconnect间接地通过aidl访问BluetoothHidService。这里主要是实现跨进程并为上层提供可直接访问的方法。

由此framework的主要部分打包生成framework.Jar并最终部署到system/framework里。

三.应用(Settings.apk)

最后需要修改应用部分,应用部分的修改点比较分散,不想框架层那样整块模仿A2DP的样子那么方便,但也不是说jni部分有多么容易。反而对于我这种对C语言不熟悉的人来说,修改jni是最头疼得事了。好在蓝牙HID 这部分框架层的修改都是整块进行的,理解上还算比价容易。

总的来说在Settings.apk中要修改的文件主要是这么几个:

LocalBluetoothProfileManager.java 这里主要提供一个HID的profile以便应用层访问。建一个HIDProfile的class调用framework中的BluetoothHID。实际上就是通过bender机制调用了BluetoothHidService。

CashedBluetoothDevice中添加显示蓝牙键盘的图标,BluetoothPairingDialog中则需要添加一段蓝牙配对验证处理的代码,我是参照i9000中先弹出一个随机数,然后在键盘中敲入相同的随机数即配对成功,具体实现如下:

+ expand sourceview plainprint?
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. Private view createView(){  
  2.   
  3. if (mType == BluetoothDevice.PAIRING_VARIANT_PIN) {  
  4.   
  5. ……  
  6.   
  7.                  // HID  
  8.   
  9.                             if (isDeviceKeyboard(mDevice)) {  
  10.   
  11.                                      String pin = String.format("%06d", Long.valueOf(Math  
  12.   
  13.                                                         .abs(new Random().nextLong() % 1000000L)));  
  14.   
  15.                                      mPairingView.setVisibility(View.GONE);  
  16.   
  17.                                      messageView.setText(getString(  
  18.   
  19.                                                         R.string.bluetooth_enter_keyboard_pin_msg, pin, name));  
  20.   
  21.    
  22.   
  23.                                      byte[] bytePin = BluetoothDevice.convertPinToBytes(pin);  
  24.   
  25.                                      if (bytePin != null) {  
  26.   
  27.                                                mDevice.setPin(bytePin);  
  28.   
  29.                                      }  
  30.   
  31.                             }  
  32.   
  33. ……  
  34.   
  35. }  
  

以上为android中实现蓝牙键盘的具体步骤。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 在京东拼购没有拼成已付款的怎么办 微信上买东西发的货不一样怎么办 微信买东西收到货不付款怎么办 京东商品店家待出库不发货怎么办 微信二维码付款多付了怎么办 微信二维码付款付错了怎么办 身份证被移动公司拉黑了怎么办 微店申请退款卖家不同意怎么办 淘宝退货快递把我名字填错了怎么办 刚申请淘宝店信用为零怎么办 淘宝买家已付款卖家不做皮单怎么办 淘宝店铺被屏蔽7天后该怎么办 香信得登录密码忘了怎么办 苹果手机迅雷下载不了的资源怎么办 快手官方私信你的作品违规了怎么办 顺丰生鲜速配食物坏了怎么办 半年汽车没有年检 交警抓到怎么办 没年检的车子被交警抓到怎么办 去年检的路上被交警抓了怎么办 微信聊天界面群聊删除找不到怎么办 微博抽奖的奖品没发货怎么办 两个微信号绑了一个手机号怎么办 欧月玫瑰花朵叶子上有白粉怎么办 进对方空间被挡不想让他知道怎么办 qq上买东西给钱了对方没给怎么办 微信钱包手势密码忘记了怎么办 买家一起拍了两件宝贝怎么办 宿雾航空付款无法显示验证码怎么办 不小心把购物车的东西删了怎么办 微信在别人电脑登录忘退出怎么办 微信电脑版忘了退出怎么办 给微商交了定金不给退怎么办 方舟手游飞龙驯服时间不够怎么办 淘宝上买了假货找不到商家怎么办 魅蓝手机一直在开机画面怎么办 在实体店买的手机想退怎么办 淘宝买了东西发货了不想要了怎么办 快递已经发货了不想要了怎么办 锤子手机买了不到十天碎屏了怎么办 唯品会新人专享优惠卷过期了怎么办 我微信被系统说赌博登陆不起怎么办