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