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