Android Bluetooth開発(三)Bluetooth Hid開発


最近のお客様のニーズでは、androidシステムのデバイスが、スキャンガン(Bluetoothキーボードのようなhidプロトコルのみをサポート)に接続し、データを受信して入力ボックスに記入することができます.androidデバイスに接続するためのBluetoothマウスを借りました.
                                                                                                                                                                                         
1 Hid概要
HIDデバイス(Hunman Interface Device Profile)、すなわちヒューマンマシンインタラクティブデバイス、よく見られるのはマウス、キーボード、ゲームハンドルなどです.一般的な有線方式は、USBケーブルで機器に接続され、ユーザ入力機器として使用される.Bluetoothテクノロジーでは、HIDデバイスのアクセスはワイヤレスです.
ネット上で資料を調べてhidはandroidから4.0からサポート(おそらくusb hid)を開始しますが、Bluetooth hidはandroid 4から開始する必要があります.2次の図のようにサポートを開始します.
android4.1.2のBluetoothアプリケーションにはhidの関連コードはないがandroid 4.2ソースコードのBluetoothアプリケーションにhidのコードがあります.
   
                                                                                                                                                                                     
2主なコード
hidデバイスの接続手順:
  • Bluetooth
  • をオンにします.
  • inputDeviceprofile
  • を取得
  • スキャン
  • ペア
  • 接続
  • 2.1 Bluetoothをオンにし、ブロードキャスト受信者によってBluetooth関連ステータスをリスニングします.
    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 inputDeviceprofileを入手する
    //4.2以上でHID対応
    if (Build.VERSION.SDK_INT >= 17) {
        mHidUtil = HidUtil.getInstance(this);
    }
    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()関数を使用して、プロキシBluetooth入力デバイスプロキシオブジェクトを取得します.
    パラメータmListenerはBluetoothProfileを実装する必要があります.ServiceListener().エージェントオブジェクトの取得に成功したか失敗したかは、Listenerにコールバックされます.
    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、BluetoothA 2 dpオブジェクトを取得してもこのコールバック関数を使用するため、パラメータタイプはBluetoothInputDevice、BluetoothHeadset、BluetoothA 2 dpの親に設定されている.ここでは、BluetoothInputDeviceタイプ(BluetoothInputDeviceはBluetoothProfileのサブクラス)に変換することができます.入力デバイスのエージェントオブジェクトを取得すると、接続操作が可能になります.
    2.3スキャン(接続ボタンをクリックしてBluetoothデバイスのスキャンを開始)
    mBluetoothAdapter.startDiscovery();

    2.4ペア
    ブロードキャスト受信者は、Bluetoothデバイスをスキャンし、必要なBluetoothデバイスをフィルタしてペアリングし、前にペアリングした場合は直接接続します.
    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();
        }
    
    }

    2.5接続(ペアリング成功後)
    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での接続方法
    /**
     *     
     * @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接続状態の傍受
    ブロードキャスト受信者によって接続ステータスをリスニングします.
    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接続解除
    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();
        }
    }

    携帯電話の端末が切断された後、再接続すると「マウスのみが再接続要求を開始します.マウスを使用して再接続してください」というメッセージが表示されます.
                                                                                                                                                                                             
    3受信データ
    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"
    これは、Bluetoothマウスが入力デバイスになったことを示します.
    左クリック:
    /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
    03-13 12:09:48.147 I/MainActivity(23670): dispatchKeyEvent event:KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x0, hwFlags=0x0, repeatCount=0, eventTime=16859701, downTime=16859701, deviceId=39, source=0x2002 } 03-13 12:09:48.147 I/MainActivity(23670): onKeyDown keyCode=4 03-13 12:09:48.308 I/InputDispatcher(  996): touch process [23670], send to pg 03-13 12:09:48.327 I/MainActivity(23670): dispatchKeyEvent event:KeyEvent { action=ACTION_UP, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x0, hwFlags=0x0, repeatCount=0, eventTime=16859870, downTime=16859870, deviceId=39, source=0x2002 } 03-13 12:09:48.327 I/MainActivity(23670): onKeyUp keyCode=4 03-13 12:09:48.337 I/MainActivity(23670): onBackPressed
    戻るボタンをクリックすると、プログラムが終了します.
    マウスを動かすと、画面上の小さなカーソルが移動し、マウスをスライドさせるとイベントがトリガーされます.
                                                                                                                                                                                           
    4その他
    現在、ほとんどの携帯電話はhidをサポートしており、この機能も開いている.
    システム開発を行う場合は、Bluetoothのhidスイッチをオンにすることに注意してください.
    ソースコードのpackages/apps/Bluetooth/res/values/config.xmlのprofile_supported_hidをtrueに変更します.
    true
    demoダウンロードアドレス:http://download.csdn.net/detail/vnanyesheshou/9815127.
    私の微信の公衆番号に注目してください.