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