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