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