HidService.java revision ede67c26e7b2564ea35db6d9b3027a269c150e13
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.bluetooth.hid;
18
19import android.bluetooth.BluetoothDevice;
20import android.bluetooth.BluetoothInputDevice;
21import android.bluetooth.BluetoothProfile;
22import android.bluetooth.IBluetooth;
23import android.bluetooth.IBluetoothInputDevice;
24import android.content.Intent;
25import android.content.pm.PackageManager;
26import android.os.Bundle;
27import android.os.IBinder;
28import android.os.Handler;
29import android.os.Message;
30import android.os.RemoteException;
31import android.os.ServiceManager;
32import android.provider.Settings;
33import android.util.Log;
34import com.android.bluetooth.btservice.AdapterService;
35import com.android.bluetooth.btservice.ProfileService;
36import com.android.bluetooth.Utils;
37import java.util.ArrayList;
38import java.util.Collections;
39import java.util.HashMap;
40import java.util.List;
41import java.util.Map;
42
43
44/**
45 * Provides Bluetooth Hid Host profile, as a service in
46 * the Bluetooth application.
47 * @hide
48 */
49public class HidService extends ProfileService {
50    private static final boolean DBG = false;
51    private static final String TAG = "HidService";
52
53    private Map<BluetoothDevice, Integer> mInputDevices;
54    private boolean mNativeAvailable;
55    private static HidService sHidService;
56    private BluetoothDevice mTargetDevice = null;
57
58    private static final int MESSAGE_CONNECT = 1;
59    private static final int MESSAGE_DISCONNECT = 2;
60    private static final int MESSAGE_CONNECT_STATE_CHANGED = 3;
61    private static final int MESSAGE_GET_PROTOCOL_MODE = 4;
62    private static final int MESSAGE_VIRTUAL_UNPLUG = 5;
63    private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6;
64    private static final int MESSAGE_SET_PROTOCOL_MODE = 7;
65    private static final int MESSAGE_GET_REPORT = 8;
66    private static final int MESSAGE_ON_GET_REPORT = 9;
67    private static final int MESSAGE_SET_REPORT = 10;
68    private static final int MESSAGE_SEND_DATA = 11;
69    private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12;
70
71    static {
72        classInitNative();
73    }
74
75    public String getName() {
76        return TAG;
77    }
78
79    public IProfileServiceBinder initBinder() {
80        return new BluetoothInputDeviceBinder(this);
81    }
82
83    protected boolean start() {
84        mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>());
85        initializeNative();
86        mNativeAvailable=true;
87        setHidService(this);
88        return true;
89    }
90
91    protected boolean stop() {
92        if (DBG) log("Stopping Bluetooth HidService");
93        return true;
94    }
95
96    protected boolean cleanup() {
97        if (mNativeAvailable) {
98            cleanupNative();
99            mNativeAvailable=false;
100        }
101
102        if(mInputDevices != null) {
103            mInputDevices.clear();
104        }
105        clearHidService();
106        return true;
107    }
108
109    public static synchronized HidService getHidService(){
110        if (sHidService != null && sHidService.isAvailable()) {
111            if (DBG) Log.d(TAG, "getHidService(): returning " + sHidService);
112            return sHidService;
113        }
114        if (DBG)  {
115            if (sHidService == null) {
116                Log.d(TAG, "getHidService(): service is NULL");
117            } else if (!(sHidService.isAvailable())) {
118                Log.d(TAG,"getHidService(): service is not available");
119            }
120        }
121        return null;
122    }
123
124    private static synchronized void setHidService(HidService instance) {
125        if (instance != null && instance.isAvailable()) {
126            if (DBG) Log.d(TAG, "setHidService(): set to: " + sHidService);
127            sHidService = instance;
128        } else {
129            if (DBG)  {
130                if (sHidService == null) {
131                    Log.d(TAG, "setHidService(): service not available");
132                } else if (!sHidService.isAvailable()) {
133                    Log.d(TAG,"setHidService(): service is cleaning up");
134                }
135            }
136        }
137    }
138
139    private static synchronized void clearHidService() {
140        sHidService = null;
141    }
142
143
144    private final Handler mHandler = new Handler() {
145
146        @Override
147        public void handleMessage(Message msg) {
148            switch (msg.what) {
149                case MESSAGE_CONNECT:
150                {
151                    BluetoothDevice device = (BluetoothDevice) msg.obj;
152                    if (!connectHidNative(Utils.getByteAddress(device)) ) {
153                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
154                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
155                        break;
156                    }
157                    mTargetDevice = device;
158                }
159                    break;
160                case MESSAGE_DISCONNECT:
161                {
162                    BluetoothDevice device = (BluetoothDevice) msg.obj;
163                    if (!disconnectHidNative(Utils.getByteAddress(device)) ) {
164                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING);
165                        broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED);
166                        break;
167                    }
168                }
169                    break;
170                case MESSAGE_CONNECT_STATE_CHANGED:
171                {
172                    BluetoothDevice device = getDevice((byte[]) msg.obj);
173                    int halState = msg.arg1;
174                    Integer prevStateInteger = mInputDevices.get(device);
175                    int prevState = (prevStateInteger == null) ?
176                        BluetoothInputDevice.STATE_DISCONNECTED :prevStateInteger;
177                    if(DBG) Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:"+
178                        convertHalState(halState)+", prevState:"+prevState);
179                    if(halState == CONN_STATE_CONNECTED &&
180                       prevState == BluetoothInputDevice.STATE_DISCONNECTED &&
181                       (!okToConnect(device))) {
182                        Log.d(TAG,"Incoming HID connection rejected");
183                        disconnectHidNative(Utils.getByteAddress(device));
184                    } else {
185                        broadcastConnectionState(device, convertHalState(halState));
186                    }
187                    if (halState != CONN_STATE_CONNECTING) {
188                        mTargetDevice = null;
189                    }
190                    else {
191                        // CONN_STATE_CONNECTING is received only during
192                        // local initiated connection.
193                        mTargetDevice = device;
194                    }
195                }
196                    break;
197                case MESSAGE_GET_PROTOCOL_MODE:
198                {
199                    BluetoothDevice device = (BluetoothDevice) msg.obj;
200                    if(!getProtocolModeNative(Utils.getByteAddress(device)) ) {
201                        Log.e(TAG, "Error: get protocol mode native returns false");
202                    }
203                }
204                break;
205
206                case MESSAGE_ON_GET_PROTOCOL_MODE:
207                {
208                    BluetoothDevice device = getDevice((byte[]) msg.obj);
209                    int protocolMode = msg.arg1;
210                    broadcastProtocolMode(device, protocolMode);
211                }
212                break;
213                case MESSAGE_VIRTUAL_UNPLUG:
214                {
215                    BluetoothDevice device = (BluetoothDevice) msg.obj;
216                    if(!virtualUnPlugNative(Utils.getByteAddress(device))) {
217                        Log.e(TAG, "Error: virtual unplug native returns false");
218                    }
219                }
220                break;
221                case MESSAGE_SET_PROTOCOL_MODE:
222                {
223                    BluetoothDevice device = (BluetoothDevice) msg.obj;
224                    byte protocolMode = (byte) msg.arg1;
225                    log("sending set protocol mode(" + protocolMode + ")");
226                    if(!setProtocolModeNative(Utils.getByteAddress(device), protocolMode)) {
227                        Log.e(TAG, "Error: set protocol mode native returns false");
228                    }
229                }
230                break;
231                case MESSAGE_GET_REPORT:
232                {
233                    BluetoothDevice device = (BluetoothDevice) msg.obj;
234                    Bundle data = msg.getData();
235                    byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
236                    byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID);
237                    int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE);
238                    if(!getReportNative(Utils.getByteAddress(device), reportType, reportId, bufferSize)) {
239                        Log.e(TAG, "Error: get report native returns false");
240                    }
241                }
242                break;
243                case MESSAGE_SET_REPORT:
244                {
245                    BluetoothDevice device = (BluetoothDevice) msg.obj;
246                    Bundle data = msg.getData();
247                    byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE);
248                    String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
249                    if(!setReportNative(Utils.getByteAddress(device), reportType, report)) {
250                        Log.e(TAG, "Error: set report native returns false");
251                    }
252                }
253                break;
254                case MESSAGE_SEND_DATA:
255                {
256                    BluetoothDevice device = (BluetoothDevice) msg.obj;
257                    Bundle data = msg.getData();
258                    String report = data.getString(BluetoothInputDevice.EXTRA_REPORT);
259                    if(!sendDataNative(Utils.getByteAddress(device), report)) {
260                        Log.e(TAG, "Error: send data native returns false");
261                    }
262                }
263                break;
264                case MESSAGE_ON_VIRTUAL_UNPLUG:
265                {
266                    BluetoothDevice device = getDevice((byte[]) msg.obj);
267                    int status = msg.arg1;
268                    broadcastVirtualUnplugStatus(device, status);
269                }
270                break;
271            }
272        }
273    };
274
275    /**
276     * Handlers for incoming service calls
277     */
278    private static class BluetoothInputDeviceBinder extends IBluetoothInputDevice.Stub implements IProfileServiceBinder{
279        private HidService mService;
280        public BluetoothInputDeviceBinder(HidService svc) {
281            mService = svc;
282        }
283
284        public boolean cleanup() {
285            mService = null;
286            return true;
287        }
288
289        private HidService getService() {
290            if (!Utils.checkCaller()) {
291                Log.w(TAG,"InputDevice call not allowed for non-active user");
292                return null;
293            }
294
295            if (mService  != null && mService.isAvailable()) {
296                return mService;
297            }
298            return null;
299        }
300
301        public boolean connect(BluetoothDevice device) {
302            HidService service = getService();
303            if (service == null) return false;
304            return service.connect(device);
305        }
306
307        public boolean disconnect(BluetoothDevice device) {
308            HidService service = getService();
309            if (service == null) return false;
310            return service.disconnect(device);
311        }
312
313        public int getConnectionState(BluetoothDevice device) {
314            HidService service = getService();
315            if (service == null) return BluetoothInputDevice.STATE_DISCONNECTED;
316            return service.getConnectionState(device);
317        }
318
319        public List<BluetoothDevice> getConnectedDevices() {
320            return getDevicesMatchingConnectionStates(
321                    new int[] {BluetoothProfile.STATE_CONNECTED});
322        }
323
324        public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
325            HidService service = getService();
326            if (service == null) return new ArrayList<BluetoothDevice>(0);
327            return service.getDevicesMatchingConnectionStates(states);
328        }
329
330        public boolean setPriority(BluetoothDevice device, int priority) {
331            HidService service = getService();
332            if (service == null) return false;
333            return service.setPriority(device, priority);
334        }
335
336        public int getPriority(BluetoothDevice device) {
337            HidService service = getService();
338            if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED;
339            return service.getPriority(device);
340        }
341
342        /* The following APIs regarding test app for compliance */
343        public boolean getProtocolMode(BluetoothDevice device) {
344            HidService service = getService();
345            if (service == null) return false;
346            return service.getProtocolMode(device);
347        }
348
349        public boolean virtualUnplug(BluetoothDevice device) {
350            HidService service = getService();
351            if (service == null) return false;
352            return service.virtualUnplug(device);
353        }
354
355        public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
356            HidService service = getService();
357            if (service == null) return false;
358            return service.setProtocolMode(device, protocolMode);
359        }
360
361        public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
362            HidService service = getService();
363            if (service == null) return false;
364            return service.getReport(device, reportType, reportId, bufferSize) ;
365        }
366
367        public boolean setReport(BluetoothDevice device, byte reportType, String report) {
368            HidService service = getService();
369            if (service == null) return false;
370            return service.setReport(device, reportType, report);
371        }
372
373        public boolean sendData(BluetoothDevice device, String report) {
374            HidService service = getService();
375            if (service == null) return false;
376            return service.sendData(device, report);
377        }
378    };
379
380    //APIs
381    boolean connect(BluetoothDevice device) {
382        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
383        if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) {
384            Log.e(TAG, "Hid Device not disconnected: " + device);
385            return false;
386        }
387        if (getPriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
388            Log.e(TAG, "Hid Device PRIORITY_OFF: " + device);
389            return false;
390        }
391
392        Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device);
393        mHandler.sendMessage(msg);
394        return true;
395    }
396
397    boolean disconnect(BluetoothDevice device) {
398        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
399        Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device);
400        mHandler.sendMessage(msg);
401        return true;
402    }
403
404    int getConnectionState(BluetoothDevice device) {
405        if (mInputDevices.get(device) == null) {
406            return BluetoothInputDevice.STATE_DISCONNECTED;
407        }
408        return mInputDevices.get(device);
409    }
410
411    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
412        enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
413        List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
414
415        for (BluetoothDevice device: mInputDevices.keySet()) {
416            int inputDeviceState = getConnectionState(device);
417            for (int state : states) {
418                if (state == inputDeviceState) {
419                    inputDevices.add(device);
420                    break;
421                }
422            }
423        }
424        return inputDevices;
425    }
426
427    public boolean setPriority(BluetoothDevice device, int priority) {
428        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
429                                       "Need BLUETOOTH_ADMIN permission");
430        Settings.Global.putInt(getContentResolver(),
431            Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()),
432            priority);
433        if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority);
434        return true;
435    }
436
437    public  int getPriority(BluetoothDevice device) {
438        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
439                                       "Need BLUETOOTH_ADMIN permission");
440        int priority = Settings.Global.getInt(getContentResolver(),
441            Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()),
442            BluetoothProfile.PRIORITY_UNDEFINED);
443        return priority;
444    }
445
446    /* The following APIs regarding test app for compliance */
447    boolean getProtocolMode(BluetoothDevice device) {
448        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
449                                       "Need BLUETOOTH_ADMIN permission");
450        int state = this.getConnectionState(device);
451        if (state != BluetoothInputDevice.STATE_CONNECTED) {
452            return false;
453        }
454        Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE,device);
455        mHandler.sendMessage(msg);
456        return true;
457        /* String objectPath = getObjectPathFromAddress(device.getAddress());
458            return getProtocolModeInputDeviceNative(objectPath);*/
459    }
460
461    boolean virtualUnplug(BluetoothDevice device) {
462        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
463                                       "Need BLUETOOTH_ADMIN permission");
464        int state = this.getConnectionState(device);
465        if (state != BluetoothInputDevice.STATE_CONNECTED) {
466            return false;
467        }
468        Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG,device);
469        mHandler.sendMessage(msg);
470        return true;
471    }
472
473    boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
474        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
475                                       "Need BLUETOOTH_ADMIN permission");
476        int state = this.getConnectionState(device);
477        if (state != BluetoothInputDevice.STATE_CONNECTED) {
478            return false;
479        }
480        Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE);
481        msg.obj = device;
482        msg.arg1 = protocolMode;
483        mHandler.sendMessage(msg);
484        return true ;
485    }
486
487    boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) {
488        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
489                                       "Need BLUETOOTH_ADMIN permission");
490        int state = this.getConnectionState(device);
491        if (state != BluetoothInputDevice.STATE_CONNECTED) {
492            return false;
493        }
494        Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT);
495        msg.obj = device;
496        Bundle data = new Bundle();
497        data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
498        data.putByte(BluetoothInputDevice.EXTRA_REPORT_ID, reportId);
499        data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, bufferSize);
500        msg.setData(data);
501        mHandler.sendMessage(msg);
502        return true ;
503    }
504
505    boolean setReport(BluetoothDevice device, byte reportType, String report) {
506        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
507                                                   "Need BLUETOOTH_ADMIN permission");
508        int state = this.getConnectionState(device);
509        if (state != BluetoothInputDevice.STATE_CONNECTED) {
510            return false;
511        }
512        Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT);
513        msg.obj = device;
514        Bundle data = new Bundle();
515        data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType);
516        data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
517        msg.setData(data);
518        mHandler.sendMessage(msg);
519        return true ;
520
521    }
522
523    boolean sendData(BluetoothDevice device, String report) {
524        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
525                                                   "Need BLUETOOTH_ADMIN permission");
526        int state = this.getConnectionState(device);
527        if (state != BluetoothInputDevice.STATE_CONNECTED) {
528            return false;
529        }
530
531        return sendDataNative(Utils.getByteAddress(device), report);
532        /*Message msg = mHandler.obtainMessage(MESSAGE_SEND_DATA);
533        msg.obj = device;
534        Bundle data = new Bundle();
535        data.putString(BluetoothInputDevice.EXTRA_REPORT, report);
536        msg.setData(data);
537        mHandler.sendMessage(msg);
538        return true ;*/
539    }
540
541    private void onGetProtocolMode(byte[] address, int mode) {
542        Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE);
543        msg.obj = address;
544        msg.arg1 = mode;
545        mHandler.sendMessage(msg);
546    }
547
548    private void onVirtualUnplug(byte[] address, int status) {
549        Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG);
550        msg.obj = address;
551        msg.arg1 = status;
552        mHandler.sendMessage(msg);
553    }
554
555    private void onConnectStateChanged(byte[] address, int state) {
556        Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED);
557        msg.obj = address;
558        msg.arg1 = state;
559        mHandler.sendMessage(msg);
560    }
561
562    // This method does not check for error conditon (newState == prevState)
563    private void broadcastConnectionState(BluetoothDevice device, int newState) {
564        Integer prevStateInteger = mInputDevices.get(device);
565        int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED :
566                                                     prevStateInteger;
567        if (prevState == newState) {
568            Log.w(TAG, "no state change: " + newState);
569            return;
570        }
571        mInputDevices.put(device, newState);
572
573        /* Notifying the connection state change of the profile before sending the intent for
574           connection state change, as it was causing a race condition, with the UI not being
575           updated with the correct connection state. */
576        log("Connection state " + device + ": " + prevState + "->" + newState);
577        notifyProfileConnectionStateChanged(device, BluetoothProfile.INPUT_DEVICE,
578                                            newState, prevState);
579        Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
580        intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
581        intent.putExtra(BluetoothProfile.EXTRA_STATE, newState);
582        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
583        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
584        sendBroadcast(intent, BLUETOOTH_PERM);
585    }
586
587    private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) {
588        Intent intent = new Intent(BluetoothInputDevice.ACTION_PROTOCOL_MODE_CHANGED);
589        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
590        intent.putExtra(BluetoothInputDevice.EXTRA_PROTOCOL_MODE, protocolMode);
591        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
592        sendBroadcast(intent, BLUETOOTH_PERM);
593        if (DBG) log("Protocol Mode (" + device + "): " + protocolMode);
594    }
595
596    private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) {
597        Intent intent = new Intent(BluetoothInputDevice.ACTION_VIRTUAL_UNPLUG_STATUS);
598        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
599        intent.putExtra(BluetoothInputDevice.EXTRA_VIRTUAL_UNPLUG_STATUS, status);
600        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
601        sendBroadcast(intent, BLUETOOTH_PERM);
602    }
603
604    private boolean okToConnect(BluetoothDevice device) {
605        AdapterService adapterService = AdapterService.getAdapterService();
606        //check if it is inbound connection in Quiet mode, priority and Bond status
607        //to decide if its ok to allow this connection
608        if((adapterService == null)||
609           ((adapterService.isQuietModeEnabled()) &&(mTargetDevice == null)) ||
610           (BluetoothProfile.PRIORITY_OFF == getPriority(device)) ||
611           (device.getBondState() == BluetoothDevice.BOND_NONE))
612            return false;
613
614        return true;
615    }
616    private static int convertHalState(int halState) {
617        switch (halState) {
618            case CONN_STATE_CONNECTED:
619                return BluetoothProfile.STATE_CONNECTED;
620            case CONN_STATE_CONNECTING:
621                return BluetoothProfile.STATE_CONNECTING;
622            case CONN_STATE_DISCONNECTED:
623                return BluetoothProfile.STATE_DISCONNECTED;
624            case CONN_STATE_DISCONNECTING:
625                return BluetoothProfile.STATE_DISCONNECTING;
626            default:
627                Log.e(TAG, "bad hid connection state: " + halState);
628                return BluetoothProfile.STATE_DISCONNECTED;
629        }
630    }
631
632    // Constants matching Hal header file bt_hh.h
633    // bthh_connection_state_t
634    private final static int CONN_STATE_CONNECTED = 0;
635    private final static int CONN_STATE_CONNECTING = 1;
636    private final static int CONN_STATE_DISCONNECTED = 2;
637    private final static int CONN_STATE_DISCONNECTING = 3;
638
639    private native static void classInitNative();
640    private native void initializeNative();
641    private native void cleanupNative();
642    private native boolean connectHidNative(byte[] btAddress);
643    private native boolean disconnectHidNative(byte[] btAddress);
644    private native boolean getProtocolModeNative(byte[] btAddress);
645    private native boolean virtualUnPlugNative(byte[] btAddress);
646    private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode);
647    private native boolean getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize);
648    private native boolean setReportNative(byte[] btAddress, byte reportType, String report);
649    private native boolean sendDataNative(byte[] btAddress, String report);
650}
651