Android Bluetooth HID實現詳解

Android 關於藍牙的部分使用的是BlueZ協議棧。可是直到目前2.3.3都沒有擴展HID的profile,只是實現了最基本的Handset和d2dp的profile,因此咱們的工做涉及到從應用到jni三層的修改,具體修改文件如圖所示,綠色表示新建的類,橙色表示修改的類。 java

120804170056241.gif 
一. 本地層
路徑: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接口。
主要實現如下兩個方法函數: android

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
staticjboolean connectSinkNative(JNIEnv *env, jobject object, jstring path) { 
   
#ifdef HAVE_BLUETOOTH  
   
    LOGV(__FUNCTION__); 
   
    if(nat) { 
   
        constchar*c_path = env->GetStringUTFChars(path, NULL); 
   
    
   
        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, 
   
                                    c_path,"org.bluez.Input","Connect", 
   
                                    DBUS_TYPE_INVALID); 
   
    
   
        env->ReleaseStringUTFChars(path, c_path); 
   
        returnret ? JNI_TRUE : JNI_FALSE; 
   
    } 
   
#endif  
   
    returnJNI_FALSE; 
   
   
    
   
staticjboolean disconnectSinkNative(JNIEnv *env, jobject object, 
   
                                     jstring path) { 
   
#ifdef HAVE_BLUETOOTH  
   
    LOGV(__FUNCTION__); 
   
    if(nat) { 
   
        constchar*c_path = env->GetStringUTFChars(path, NULL); 
   
    
   
        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat, 
   
                                    c_path,"org.bluez.Input","Disconnect", 
   
                                    DBUS_TYPE_INVALID); 
   
    
   
        env->ReleaseStringUTFChars(path, c_path); 
   
        returnret ? JNI_TRUE : JNI_FALSE; 
   
    } 
   
#endif  
   
    returnJNI_FALSE; 
   
}


這裏要注意將該文件添加到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文件。 框架

01
02
03
04
05
06
07
08
09
10
11
12
13
interfaceIBluetoothHid { 
   
    booleanconnect(in BluetoothDevice device); 
   
    booleandisconnect(in BluetoothDevice device); 
   
    intgetState(in BluetoothDevice device); 
   
    booleansetPriority(in BluetoothDevice device,intpriority); 
   
    intgetPriority(in BluetoothDevice device); 
   
}

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中先彈出一個隨機數,而後在鍵盤中敲入相同的隨機數即配對成功,具體實現以下: dom

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Private view createView(){  
    
if(mType == BluetoothDevice.PAIRING_VARIANT_PIN) {  
    
……  
    
                 // HID   
    
                            if(isDeviceKeyboard(mDevice)) {  
    
                                     String pin = String.format("%06d", Long.valueOf(Math  
    
                                                        .abs(newRandom().nextLong() % 1000000L)));  
    
                                     mPairingView.setVisibility(View.GONE);  
    
                                     messageView.setText(getString(  
    
                                                        R.string.bluetooth_enter_keyboard_pin_msg, pin, name));  
    
     
    
                                     byte[] bytePin = BluetoothDevice.convertPinToBytes(pin);  
    
                                     if(bytePin !=null) {  
    
                                               mDevice.setPin(bytePin);  
    
                                     }  
    
                            }  
    
……  
    
}


以上爲Android中實現藍牙鍵盤的具體步驟。 async

相關文章
相關標籤/搜索