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