Home | History | Annotate | Download | only in hid
      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 
     17 package com.android.bluetooth.hid;
     18 
     19 import android.bluetooth.BluetoothDevice;
     20 import android.bluetooth.BluetoothInputDevice;
     21 import android.bluetooth.BluetoothProfile;
     22 import android.bluetooth.IBluetooth;
     23 import android.bluetooth.IBluetoothInputDevice;
     24 import android.content.Intent;
     25 import android.content.pm.PackageManager;
     26 import android.os.Bundle;
     27 import android.os.IBinder;
     28 import android.os.Handler;
     29 import android.os.Message;
     30 import android.os.RemoteException;
     31 import android.os.ServiceManager;
     32 import android.provider.Settings;
     33 import android.util.Log;
     34 import com.android.bluetooth.btservice.AdapterService;
     35 import com.android.bluetooth.btservice.ProfileService;
     36 import com.android.bluetooth.Utils;
     37 import java.util.ArrayList;
     38 import java.util.Collections;
     39 import java.util.HashMap;
     40 import java.util.List;
     41 import java.util.Map;
     42 
     43 
     44 /**
     45  * Provides Bluetooth Hid Host profile, as a service in
     46  * the Bluetooth application.
     47  * @hide
     48  */
     49 public 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                         if (DBG) 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