HidService.java revision b5cc776c9353a203cdde97e62b25f05d9633d14c
1/* 2 * Copyright (C) 2012 Google Inc. 3 */ 4 5package com.android.bluetooth.hid; 6 7import android.app.Service; 8import android.bluetooth.BluetoothAdapter; 9import android.bluetooth.BluetoothDevice; 10import android.bluetooth.BluetoothInputDevice; 11import android.bluetooth.BluetoothProfile; 12import android.bluetooth.IBluetooth; 13import android.bluetooth.IBluetoothInputDevice; 14import android.content.Intent; 15import android.os.Bundle; 16import android.os.IBinder; 17import android.os.Handler; 18import android.os.Message; 19import android.os.RemoteException; 20import android.os.ServiceManager; 21import android.provider.Settings; 22import android.util.Log; 23import java.util.ArrayList; 24import java.util.Collections; 25import java.util.HashMap; 26import java.util.List; 27import java.util.Map; 28import com.android.bluetooth.Utils; 29import android.content.pm.PackageManager; 30import com.android.bluetooth.btservice.AdapterService; 31import com.android.bluetooth.btservice.ProfileService; 32 33/** 34 * Provides Bluetooth Hid Host profile, as a service in 35 * the Bluetooth application. 36 * @hide 37 */ 38public class HidService extends ProfileService { 39 private static final boolean DBG = true; 40 private static final String TAG = "HidService"; 41 private Map<BluetoothDevice, Integer> mInputDevices; 42 43 private static final int MESSAGE_CONNECT = 1; 44 private static final int MESSAGE_DISCONNECT = 2; 45 private static final int MESSAGE_CONNECT_STATE_CHANGED = 3; 46 private static final int MESSAGE_GET_PROTOCOL_MODE = 4; 47 private static final int MESSAGE_VIRTUAL_UNPLUG = 5; 48 private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6; 49 private static final int MESSAGE_SET_PROTOCOL_MODE = 7; 50 private static final int MESSAGE_GET_REPORT = 8; 51 private static final int MESSAGE_ON_GET_REPORT = 9; 52 private static final int MESSAGE_SET_REPORT = 10; 53 private static final int MESSAGE_SEND_DATA = 11; 54 private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12; 55 56 static { 57 classInitNative(); 58 } 59 60 public String getName() { 61 return TAG; 62 } 63 64 @Override 65 public IBinder onBind(Intent intent) { 66 log("onBind"); 67 return mBinder; 68 } 69 70 71 protected boolean start() { 72 if(mInputDevices != null) { 73 mInputDevices.clear(); 74 mInputDevices = null; 75 } 76 mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>()); 77 initializeNative(); 78 79 return true; 80 } 81 82 protected boolean stop() { 83 if (DBG) log("Stopping Bluetooth HidService"); 84 cleanupNative(); 85 86 if(mInputDevices != null) { 87 mInputDevices.clear(); 88 mInputDevices = null; 89 } 90 91 return true; 92 } 93 94 95 96 private final Handler mHandler = new Handler() { 97 98 @Override 99 public void handleMessage(Message msg) { 100 switch (msg.what) { 101 case MESSAGE_CONNECT: 102 { 103 BluetoothDevice device = (BluetoothDevice) msg.obj; 104 if (!connectHidNative(getByteAddress(device)) ) { 105 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); 106 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 107 break; 108 } 109 } 110 break; 111 case MESSAGE_DISCONNECT: 112 { 113 BluetoothDevice device = (BluetoothDevice) msg.obj; 114 if (!disconnectHidNative(getByteAddress(device)) ) { 115 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); 116 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 117 break; 118 } 119 } 120 break; 121 case MESSAGE_CONNECT_STATE_CHANGED: 122 { 123 BluetoothDevice device = getDevice((byte[]) msg.obj); 124 int halState = msg.arg1; 125 broadcastConnectionState(device, convertHalState(halState)); 126 } 127 break; 128 case MESSAGE_GET_PROTOCOL_MODE: 129 { 130 BluetoothDevice device = (BluetoothDevice) msg.obj; 131 if(!getProtocolModeNative(getByteAddress(device)) ) { 132 Log.e(TAG, "Error: get protocol mode native returns false"); 133 } 134 } 135 break; 136 137 case MESSAGE_ON_GET_PROTOCOL_MODE: 138 { 139 BluetoothDevice device = getDevice((byte[]) msg.obj); 140 int protocolMode = msg.arg1; 141 broadcastProtocolMode(device, protocolMode); 142 } 143 break; 144 case MESSAGE_VIRTUAL_UNPLUG: 145 { 146 BluetoothDevice device = (BluetoothDevice) msg.obj; 147 if(!virtualUnPlugNative(getByteAddress(device))) { 148 Log.e(TAG, "Error: virtual unplug native returns false"); 149 } 150 } 151 break; 152 case MESSAGE_SET_PROTOCOL_MODE: 153 { 154 BluetoothDevice device = (BluetoothDevice) msg.obj; 155 byte protocolMode = (byte) msg.arg1; 156 log("sending set protocol mode(" + protocolMode + ")"); 157 if(!setProtocolModeNative(getByteAddress(device), protocolMode)) { 158 Log.e(TAG, "Error: set protocol mode native returns false"); 159 } 160 } 161 break; 162 case MESSAGE_GET_REPORT: 163 { 164 BluetoothDevice device = (BluetoothDevice) msg.obj; 165 Bundle data = msg.getData(); 166 byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE); 167 byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID); 168 int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE); 169 if(!getReportNative(getByteAddress(device), reportType, reportId, bufferSize)) { 170 Log.e(TAG, "Error: get report native returns false"); 171 } 172 } 173 break; 174 case MESSAGE_SET_REPORT: 175 { 176 BluetoothDevice device = (BluetoothDevice) msg.obj; 177 Bundle data = msg.getData(); 178 byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE); 179 String report = data.getString(BluetoothInputDevice.EXTRA_REPORT); 180 if(!setReportNative(getByteAddress(device), reportType, report)) { 181 Log.e(TAG, "Error: set report native returns false"); 182 } 183 } 184 break; 185 case MESSAGE_SEND_DATA: 186 { 187 BluetoothDevice device = (BluetoothDevice) msg.obj; 188 Bundle data = msg.getData(); 189 String report = data.getString(BluetoothInputDevice.EXTRA_REPORT); 190 if(!sendDataNative(getByteAddress(device), report)) { 191 Log.e(TAG, "Error: send data native returns false"); 192 } 193 } 194 break; 195 case MESSAGE_ON_VIRTUAL_UNPLUG: 196 { 197 BluetoothDevice device = getDevice((byte[]) msg.obj); 198 int status = msg.arg1; 199 broadcastVirtualUnplugStatus(device, status); 200 } 201 break; 202 } 203 } 204 }; 205 206 /** 207 * Handlers for incoming service calls 208 */ 209 private final IBluetoothInputDevice.Stub mBinder = new IBluetoothInputDevice.Stub() { 210 public boolean connect(BluetoothDevice device) { 211 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 212 if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) { 213 Log.e(TAG, "Hid Device not disconnected: " + device); 214 return false; 215 } 216 if (getPriority(device) == BluetoothInputDevice.PRIORITY_OFF) { 217 Log.e(TAG, "Hid Device PRIORITY_OFF: " + device); 218 return false; 219 } 220 221 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT); 222 msg.obj = device; 223 mHandler.sendMessage(msg); 224 return true; 225 } 226 227 public boolean disconnect(BluetoothDevice device) { 228 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 229 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT); 230 msg.obj = device; 231 mHandler.sendMessage(msg); 232 return true; 233 } 234 235 public int getConnectionState(BluetoothDevice device) { 236 if (mInputDevices.get(device) == null) { 237 return BluetoothInputDevice.STATE_DISCONNECTED; 238 } 239 return mInputDevices.get(device); 240 } 241 242 public List<BluetoothDevice> getConnectedDevices() { 243 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 244 List<BluetoothDevice> devices = getDevicesMatchingConnectionStates( 245 new int[] {BluetoothProfile.STATE_CONNECTED}); 246 return devices; 247 } 248 249 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 250 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 251 List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); 252 253 for (BluetoothDevice device: mInputDevices.keySet()) { 254 int inputDeviceState = getConnectionState(device); 255 for (int state : states) { 256 if (state == inputDeviceState) { 257 inputDevices.add(device); 258 break; 259 } 260 } 261 } 262 return inputDevices; 263 } 264 265 public boolean setPriority(BluetoothDevice device, int priority) { 266 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 267 "Need BLUETOOTH_ADMIN permission"); 268 Settings.Secure.putInt(getContentResolver(), 269 Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()), 270 priority); 271 if (DBG) log("Saved priority " + device + " = " + priority); 272 return true; 273 } 274 275 public int getPriority(BluetoothDevice device) { 276 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 277 "Need BLUETOOTH_ADMIN permission"); 278 int priority = Settings.Secure.getInt(getContentResolver(), 279 Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()), 280 BluetoothProfile.PRIORITY_UNDEFINED); 281 return priority; 282 } 283 /* The following APIs regarding test app for compliance */ 284 public boolean getProtocolMode(BluetoothDevice device) { 285 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 286 "Need BLUETOOTH_ADMIN permission"); 287 int state = this.getConnectionState(device); 288 if (state != BluetoothInputDevice.STATE_CONNECTED) { 289 return false; 290 } 291 Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE); 292 msg.obj = device; 293 mHandler.sendMessage(msg); 294 return true; 295 /* String objectPath = getObjectPathFromAddress(device.getAddress()); 296 return getProtocolModeInputDeviceNative(objectPath);*/ 297 } 298 299 public boolean virtualUnplug(BluetoothDevice device) { 300 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 301 "Need BLUETOOTH_ADMIN permission"); 302 int state = this.getConnectionState(device); 303 if (state != BluetoothInputDevice.STATE_CONNECTED) { 304 return false; 305 } 306 Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG); 307 msg.obj = device; 308 mHandler.sendMessage(msg); 309 310 return true; 311 } 312 313 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) { 314 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 315 "Need BLUETOOTH_ADMIN permission"); 316 int state = this.getConnectionState(device); 317 if (state != BluetoothInputDevice.STATE_CONNECTED) { 318 return false; 319 } 320 Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE); 321 msg.obj = device; 322 msg.arg1 = protocolMode; 323 mHandler.sendMessage(msg); 324 return true ; 325 } 326 327 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) { 328 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 329 "Need BLUETOOTH_ADMIN permission"); 330 int state = this.getConnectionState(device); 331 if (state != BluetoothInputDevice.STATE_CONNECTED) { 332 return false; 333 } 334 Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT); 335 msg.obj = device; 336 Bundle data = new Bundle(); 337 data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType); 338 data.putByte(BluetoothInputDevice.EXTRA_REPORT_ID, reportId); 339 data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, bufferSize); 340 msg.setData(data); 341 mHandler.sendMessage(msg); 342 return true ; 343 } 344 345 public boolean setReport(BluetoothDevice device, byte reportType, String report) { 346 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 347 "Need BLUETOOTH_ADMIN permission"); 348 int state = this.getConnectionState(device); 349 if (state != BluetoothInputDevice.STATE_CONNECTED) { 350 return false; 351 } 352 Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT); 353 msg.obj = device; 354 Bundle data = new Bundle(); 355 data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType); 356 data.putString(BluetoothInputDevice.EXTRA_REPORT, report); 357 msg.setData(data); 358 mHandler.sendMessage(msg); 359 return true ; 360 361 } 362 363 public boolean sendData(BluetoothDevice device, String report) { 364 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 365 "Need BLUETOOTH_ADMIN permission"); 366 int state = this.getConnectionState(device); 367 if (state != BluetoothInputDevice.STATE_CONNECTED) { 368 return false; 369 } 370 371 return sendDataNative(getByteAddress(device), report); 372 /*Message msg = mHandler.obtainMessage(MESSAGE_SEND_DATA); 373 msg.obj = device; 374 Bundle data = new Bundle(); 375 data.putString(BluetoothInputDevice.EXTRA_REPORT, report); 376 msg.setData(data); 377 mHandler.sendMessage(msg); 378 return true ;*/ 379 } 380 }; 381 382 private void onGetProtocolMode(byte[] address, int mode) { 383 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE); 384 msg.obj = address; 385 msg.arg1 = mode; 386 mHandler.sendMessage(msg); 387 } 388 389 private void onVirtualUnplug(byte[] address, int status) { 390 Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG); 391 msg.obj = address; 392 msg.arg1 = status; 393 mHandler.sendMessage(msg); 394 } 395 396 private void onConnectStateChanged(byte[] address, int state) { 397 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 398 msg.obj = address; 399 msg.arg1 = state; 400 mHandler.sendMessage(msg); 401 } 402 403 // This method does not check for error conditon (newState == prevState) 404 private void broadcastConnectionState(BluetoothDevice device, int newState) { 405 Integer prevStateInteger = mInputDevices.get(device); 406 int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED : 407 prevStateInteger; 408 if (prevState == newState) { 409 Log.w(TAG, "no state change: " + newState); 410 return; 411 } 412 mInputDevices.put(device, newState); 413 414 Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); 415 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 416 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 417 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 418 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 419 sendBroadcast(intent, BLUETOOTH_PERM); 420 if (DBG) log("Connection state " + device + ": " + prevState + "->" + newState); 421 AdapterService svc = AdapterService.getAdapterService(); 422 if (svc != null) { 423 svc.onProfileConnectionStateChanged(device, BluetoothProfile.INPUT_DEVICE, newState, prevState); 424 } 425 } 426 427 private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) { 428 Intent intent = new Intent(BluetoothInputDevice.ACTION_PROTOCOL_MODE_CHANGED); 429 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 430 intent.putExtra(BluetoothInputDevice.EXTRA_PROTOCOL_MODE, protocolMode); 431 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 432 sendBroadcast(intent, BLUETOOTH_PERM); 433 if (DBG) log("Protocol Mode (" + device + "): " + protocolMode); 434 } 435 436 private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) { 437 Intent intent = new Intent(BluetoothInputDevice.ACTION_VIRTUAL_UNPLUG_STATUS); 438 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 439 intent.putExtra(BluetoothInputDevice.EXTRA_VIRTUAL_UNPLUG_STATUS, status); 440 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 441 sendBroadcast(intent, BLUETOOTH_PERM); 442 } 443 444 private BluetoothDevice getDevice(byte[] address) { 445 return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 446 } 447 448 private byte[] getByteAddress(BluetoothDevice device) { 449 return Utils.getBytesFromAddress(device.getAddress()); 450 } 451 452 private int convertHalState(int halState) { 453 switch (halState) { 454 case CONN_STATE_CONNECTED: 455 return BluetoothProfile.STATE_CONNECTED; 456 case CONN_STATE_CONNECTING: 457 return BluetoothProfile.STATE_CONNECTING; 458 case CONN_STATE_DISCONNECTED: 459 return BluetoothProfile.STATE_DISCONNECTED; 460 case CONN_STATE_DISCONNECTING: 461 return BluetoothProfile.STATE_DISCONNECTING; 462 default: 463 Log.e(TAG, "bad hid connection state: " + halState); 464 return BluetoothProfile.STATE_DISCONNECTED; 465 } 466 } 467 468 469 // Constants matching Hal header file bt_hh.h 470 // bthh_connection_state_t 471 private final static int CONN_STATE_CONNECTED = 0; 472 private final static int CONN_STATE_CONNECTING = 1; 473 private final static int CONN_STATE_DISCONNECTED = 2; 474 private final static int CONN_STATE_DISCONNECTING = 3; 475 476 private native static void classInitNative(); 477 private native void initializeNative(); 478 private native void cleanupNative(); 479 private native boolean connectHidNative(byte[] btAddress); 480 private native boolean disconnectHidNative(byte[] btAddress); 481 private native boolean getProtocolModeNative(byte[] btAddress); 482 private native boolean virtualUnPlugNative(byte[] btAddress); 483 private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode); 484 private native boolean getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize); 485 private native boolean setReportNative(byte[] btAddress, byte reportType, String report); 486 private native boolean sendDataNative(byte[] btAddress, String report); 487} 488