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 static android.Manifest.permission.BLUETOOTH_CONNECT; 20 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; 21 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; 22 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_UNKNOWN; 23 import static android.bluetooth.BluetoothProfile.STATE_CONNECTED; 24 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED; 25 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTING; 26 27 import static java.util.Objects.requireNonNull; 28 29 import android.bluetooth.BluetoothDevice; 30 import android.bluetooth.BluetoothHidHost; 31 import android.bluetooth.BluetoothProfile; 32 import android.bluetooth.BluetoothProtoEnums; 33 import android.bluetooth.BluetoothUuid; 34 import android.content.Intent; 35 import android.os.Bundle; 36 import android.os.Handler; 37 import android.os.Message; 38 import android.os.ParcelUuid; 39 import android.os.UserHandle; 40 import android.sysprop.BluetoothProperties; 41 import android.util.Log; 42 43 import androidx.annotation.VisibleForTesting; 44 45 import com.android.bluetooth.Utils; 46 import com.android.bluetooth.btservice.AdapterService; 47 import com.android.bluetooth.btservice.MetricsLogger; 48 import com.android.bluetooth.btservice.ProfileService; 49 import com.android.bluetooth.btservice.storage.DatabaseManager; 50 import com.android.bluetooth.flags.Flags; 51 52 import java.util.Collections; 53 import java.util.HashMap; 54 import java.util.List; 55 import java.util.Map; 56 import java.util.stream.Collectors; 57 import java.util.stream.IntStream; 58 59 /** Provides Bluetooth Hid Host profile, as a service in the Bluetooth application. */ 60 public class HidHostService extends ProfileService { 61 private static final String TAG = HidHostService.class.getSimpleName(); 62 63 public static final String ANDROID_HEADTRACKER_UUID_STR = 64 "109b862f-50e3-45cc-8ea1-ac62de4846d1"; 65 66 public static final ParcelUuid ANDROID_HEADTRACKER_UUID = 67 ParcelUuid.fromString(ANDROID_HEADTRACKER_UUID_STR); 68 69 private static class InputDevice { 70 int mSelectedTransport = BluetoothDevice.TRANSPORT_AUTO; 71 private int mHidState = STATE_DISCONNECTED; 72 private int mHogpState = STATE_DISCONNECTED; 73 getState(int transport)74 int getState(int transport) { 75 return (transport == BluetoothDevice.TRANSPORT_LE) ? mHogpState : mHidState; 76 } 77 getState()78 int getState() { 79 return getState(mSelectedTransport); 80 } 81 setState(int transport, int state)82 void setState(int transport, int state) { 83 if (transport == BluetoothDevice.TRANSPORT_LE) { 84 mHogpState = state; 85 } else { 86 mHidState = state; 87 } 88 } 89 90 @Override toString()91 public String toString() { 92 return ("Selected transport=" + mSelectedTransport) 93 + (" HID connection state=" + mHidState) 94 + (" HOGP connection state=" + mHogpState); 95 } 96 } 97 98 private static HidHostService sHidHostService; 99 100 private final Map<BluetoothDevice, InputDevice> mInputDevices = 101 Collections.synchronizedMap(new HashMap<>()); 102 103 private final AdapterService mAdapterService; 104 private final DatabaseManager mDatabaseManager; 105 private final HidHostNativeInterface mNativeInterface; 106 107 private static final int MESSAGE_CONNECT = 1; 108 private static final int MESSAGE_DISCONNECT = 2; 109 private static final int MESSAGE_CONNECT_STATE_CHANGED = 3; 110 private static final int MESSAGE_GET_PROTOCOL_MODE = 4; 111 private static final int MESSAGE_VIRTUAL_UNPLUG = 5; 112 private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6; 113 private static final int MESSAGE_SET_PROTOCOL_MODE = 7; 114 private static final int MESSAGE_GET_REPORT = 8; 115 private static final int MESSAGE_ON_GET_REPORT = 9; 116 private static final int MESSAGE_SET_REPORT = 10; 117 private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12; 118 private static final int MESSAGE_ON_HANDSHAKE = 13; 119 private static final int MESSAGE_GET_IDLE_TIME = 14; 120 private static final int MESSAGE_ON_GET_IDLE_TIME = 15; 121 private static final int MESSAGE_SET_IDLE_TIME = 16; 122 private static final int MESSAGE_SET_PREFERRED_TRANSPORT = 17; 123 private static final int MESSAGE_SEND_DATA = 18; 124 125 public static final int STATE_ACCEPTING = STATE_DISCONNECTING + 1; 126 HidHostService(AdapterService adapterService)127 public HidHostService(AdapterService adapterService) { 128 super(adapterService); 129 130 mAdapterService = requireNonNull(adapterService); 131 mDatabaseManager = requireNonNull(mAdapterService.getDatabase()); 132 mNativeInterface = requireNonNull(HidHostNativeInterface.getInstance()); 133 134 mNativeInterface.init(this); 135 setHidHostService(this); 136 } 137 isEnabled()138 public static boolean isEnabled() { 139 return BluetoothProperties.isProfileHidHostEnabled().orElse(false); 140 } 141 142 @Override initBinder()143 public IProfileServiceBinder initBinder() { 144 return new HidHostServiceBinder(this); 145 } 146 147 @Override cleanup()148 public void cleanup() { 149 Log.i(TAG, "Cleanup HidHost Service"); 150 151 mNativeInterface.cleanup(); 152 153 if (mInputDevices != null) { 154 for (BluetoothDevice device : mInputDevices.keySet()) { 155 // Set both HID and HOGP connection states to disconnected 156 updateConnectionState(device, BluetoothDevice.TRANSPORT_LE, STATE_DISCONNECTED); 157 updateConnectionState(device, BluetoothDevice.TRANSPORT_BREDR, STATE_DISCONNECTED); 158 } 159 mInputDevices.clear(); 160 } 161 // TODO(b/72948646): this should be moved to stop() 162 setHidHostService(null); 163 } 164 getByteAddress(BluetoothDevice device, int transport)165 private byte[] getByteAddress(BluetoothDevice device, int transport) { 166 final ParcelUuid[] uuids = mAdapterService.getRemoteUuids(device); 167 168 if (transport == BluetoothDevice.TRANSPORT_LE) { 169 // Use pseudo address when HOGP is to be used 170 return Utils.getByteAddress(device); 171 } else if (transport == BluetoothDevice.TRANSPORT_BREDR) { 172 // Use BR/EDR address if HID is to be used 173 return Utils.getByteBrEdrAddress(mAdapterService, device); 174 } else { // BluetoothDevice.TRANSPORT_AUTO 175 boolean hidSupported = Utils.arrayContains(uuids, BluetoothUuid.HID); 176 // Prefer HID over HOGP 177 if (hidSupported) { 178 // Use BR/EDR address if HID is available 179 return Utils.getByteBrEdrAddress(mAdapterService, device); 180 } else { 181 // Otherwise use pseudo address 182 return Utils.getByteAddress(device); 183 } 184 } 185 } 186 getByteAddress(BluetoothDevice device)187 private byte[] getByteAddress(BluetoothDevice device) { 188 return getByteAddress(device, getTransport(device)); 189 } 190 191 /** 192 * Retrieves device address type 193 * 194 * @param device remote device 195 * @return address type 196 */ getAddressType(BluetoothDevice device)197 private static int getAddressType(BluetoothDevice device) { 198 return device.getAddressType(); 199 } 200 201 /** 202 * Retrieves preferred transport for the device 203 * 204 * @param device remote device 205 * @return transport 206 */ getTransport(BluetoothDevice device)207 private int getTransport(BluetoothDevice device) { 208 InputDevice inputDevice = mInputDevices.get(device); 209 if (inputDevice != null) { 210 return inputDevice.mSelectedTransport; 211 } 212 213 return BluetoothDevice.TRANSPORT_AUTO; 214 } 215 216 /** 217 * Saves the preferred transport for the input device. Adds an input device entry if not present 218 * 219 * @param device remote device 220 * @param transport preferred transport 221 */ setTransport(BluetoothDevice device, int transport)222 private void setTransport(BluetoothDevice device, int transport) { 223 InputDevice inputDevice = getOrCreateInputDevice(device); 224 if (inputDevice.mSelectedTransport != transport) { 225 inputDevice.mSelectedTransport = transport; 226 } 227 } 228 229 /** 230 * Retrieves the input device object. Creates a new one if it does not exist 231 * 232 * @param device remote device 233 * @return input device object 234 */ getOrCreateInputDevice(BluetoothDevice device)235 private InputDevice getOrCreateInputDevice(BluetoothDevice device) { 236 return mInputDevices.computeIfAbsent(device, k -> new InputDevice()); 237 } 238 239 /** 240 * Retrieves the connection state 241 * 242 * @param device remote device 243 * @param transport transport 244 * @return connection state 245 */ getState(BluetoothDevice device, int transport)246 private int getState(BluetoothDevice device, int transport) { 247 InputDevice inputDevice = mInputDevices.get(device); 248 if (inputDevice != null) { 249 return inputDevice.getState(transport); 250 } 251 252 return STATE_DISCONNECTED; 253 } 254 getHidHostService()255 public static synchronized HidHostService getHidHostService() { 256 if (sHidHostService == null) { 257 Log.w(TAG, "getHidHostService(): service is null"); 258 return null; 259 } 260 if (!sHidHostService.isAvailable()) { 261 Log.w(TAG, "getHidHostService(): service is not available "); 262 return null; 263 } 264 return sHidHostService; 265 } 266 setHidHostService(HidHostService instance)267 private static synchronized void setHidHostService(HidHostService instance) { 268 Log.d(TAG, "setHidHostService(): set to: " + instance); 269 sHidHostService = instance; 270 } 271 272 /** 273 * Requests the native stack to start HID connection 274 * 275 * @param device remote device 276 * @param transport transport to be used 277 * @return true if successfully requested, else false 278 */ nativeConnect(BluetoothDevice device, int transport)279 private boolean nativeConnect(BluetoothDevice device, int transport) { 280 if (!mNativeInterface.connectHid( 281 getByteAddress(device, transport), getAddressType(device), transport)) { 282 Log.w( 283 TAG, 284 "nativeConnect: Connection attempt failed." 285 + (" device=" + device) 286 + (" transport=" + transport)); 287 return false; 288 } 289 return true; 290 } 291 292 /** 293 * Requests the native stack to start HID disconnection 294 * 295 * @param device remote device 296 * @param transport transport 297 * @param reconnectAllowed true if remote device is allowed to initiate reconnections, else 298 * false 299 * @return true if successfully requested, else false 300 */ nativeDisconnect( BluetoothDevice device, int transport, boolean reconnectAllowed)301 private boolean nativeDisconnect( 302 BluetoothDevice device, int transport, boolean reconnectAllowed) { 303 if (!mNativeInterface.disconnectHid( 304 getByteAddress(device, transport), 305 getAddressType(device), 306 transport, 307 reconnectAllowed)) { 308 Log.w( 309 TAG, 310 "nativeDisconnect: Disconnection attempt failed." 311 + (" device=" + device) 312 + (" transport=" + transport)); 313 return false; 314 } 315 return true; 316 } 317 318 private final Handler mHandler = 319 new Handler() { 320 @Override 321 public void handleMessage(Message msg) { 322 Log.v(TAG, "handleMessage(): msg.what=" + msg.what); 323 324 switch (msg.what) { 325 case MESSAGE_CONNECT: 326 handleMessageConnect(msg); 327 break; 328 case MESSAGE_DISCONNECT: 329 handleMessageDisconnect(msg); 330 break; 331 case MESSAGE_CONNECT_STATE_CHANGED: 332 handleMessageConnectStateChanged(msg); 333 break; 334 case MESSAGE_GET_PROTOCOL_MODE: 335 handleMessageGetProtocolMode(msg); 336 break; 337 case MESSAGE_ON_GET_PROTOCOL_MODE: 338 handleMessageOnGetProtocolMode(msg); 339 break; 340 case MESSAGE_VIRTUAL_UNPLUG: 341 handleMessageVirtualUnplug(msg); 342 break; 343 case MESSAGE_SET_PROTOCOL_MODE: 344 handleMessageSetProtocolMode(msg); 345 break; 346 case MESSAGE_GET_REPORT: 347 handleMessageGetReport(msg); 348 break; 349 case MESSAGE_ON_GET_REPORT: 350 handleMessageOnGetReport(msg); 351 break; 352 case MESSAGE_ON_HANDSHAKE: 353 handleMessageOnHandshake(msg); 354 break; 355 case MESSAGE_SET_REPORT: 356 handleMessageSetReport(msg); 357 break; 358 case MESSAGE_ON_VIRTUAL_UNPLUG: 359 handleMessageOnVirtualUnplug(msg); 360 break; 361 case MESSAGE_GET_IDLE_TIME: 362 handleMessageGetIdleTime(msg); 363 break; 364 case MESSAGE_ON_GET_IDLE_TIME: 365 handleMessageOnGetIdleTime(msg); 366 break; 367 case MESSAGE_SET_IDLE_TIME: 368 handleMessageSetIdleTime(msg); 369 break; 370 case MESSAGE_SET_PREFERRED_TRANSPORT: 371 handleMessageSetPreferredTransport(msg); 372 break; 373 case MESSAGE_SEND_DATA: 374 handleMessageSendData(msg); 375 break; 376 } 377 } 378 }; 379 handleMessageSendData(Message msg)380 private void handleMessageSendData(Message msg) { 381 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 382 383 Bundle data = msg.getData(); 384 String report = data.getString(BluetoothHidHost.EXTRA_REPORT); 385 386 if (!mNativeInterface.sendData( 387 getByteAddress(device), getAddressType(device), getTransport(device), report)) { 388 Log.e(TAG, "handleMessageSendData: Failed to send data"); 389 } 390 } 391 handleMessageSetPreferredTransport(Message msg)392 private void handleMessageSetPreferredTransport(Message msg) { 393 BluetoothDevice device = (BluetoothDevice) msg.obj; 394 int transport = msg.arg1; 395 396 int prevTransport = getTransport(device); 397 Log.i( 398 TAG, 399 "handleMessageSetPreferredTransport: Transport changed" 400 + (" device=" + device) 401 + (" transport: prev=" + prevTransport + " -> new=" + transport)); 402 403 InputDevice inputDevice = getOrCreateInputDevice(device); 404 if (!Flags.ignoreUnselectedHidTransportStates()) { 405 inputDevice.mSelectedTransport = transport; 406 } 407 408 /* If connections are allowed, ensure that the previous transport is disconnected and the 409 new transport is connected */ 410 if (getConnectionPolicy(device) == CONNECTION_POLICY_ALLOWED) { 411 if (prevTransport != transport) { 412 Log.i( 413 TAG, 414 "handleMessageSetPreferredTransport: Connection switch" 415 + (" device=" + device) 416 + (" transport: prev=" + prevTransport + " -> new=" + transport)); 417 // Disconnect the other transport and disallow reconnections 418 nativeDisconnect(device, prevTransport, false); 419 if (Flags.ignoreUnselectedHidTransportStates()) { 420 // Immediately update the connection state to disconnected. From now on, 421 // the connection state will be updated only for the selected transport. 422 updateConnectionState(device, prevTransport, STATE_DISCONNECTED); 423 } 424 // Request to connect the preferred transport 425 nativeConnect(device, transport); 426 } 427 } 428 429 if (Flags.ignoreUnselectedHidTransportStates()) { 430 // Save the preferred transport 431 inputDevice.mSelectedTransport = transport; 432 } 433 } 434 handleMessageSetIdleTime(Message msg)435 private void handleMessageSetIdleTime(Message msg) { 436 BluetoothDevice device = (BluetoothDevice) msg.obj; 437 Bundle data = msg.getData(); 438 byte idleTime = data.getByte(BluetoothHidHost.EXTRA_IDLE_TIME); 439 if (!mNativeInterface.setIdleTime( 440 getByteAddress(device), getAddressType(device), getTransport(device), idleTime)) { 441 Log.e(TAG, "Error: get idle time native returns false"); 442 } 443 } 444 handleMessageOnGetIdleTime(Message msg)445 private void handleMessageOnGetIdleTime(Message msg) { 446 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 447 int transport = msg.arg1; 448 449 if (!checkTransport(device, transport, msg.what)) { 450 return; 451 } 452 453 int idleTime = msg.arg2; 454 broadcastIdleTime(device, idleTime); 455 } 456 handleMessageGetIdleTime(Message msg)457 private void handleMessageGetIdleTime(Message msg) { 458 BluetoothDevice device = (BluetoothDevice) msg.obj; 459 if (!mNativeInterface.getIdleTime( 460 getByteAddress(device), getAddressType(device), getTransport(device))) { 461 Log.e(TAG, "Error: get idle time native returns false"); 462 } 463 } 464 handleMessageOnVirtualUnplug(Message msg)465 private void handleMessageOnVirtualUnplug(Message msg) { 466 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 467 468 updateConnectionState(device, getTransport(device), STATE_DISCONNECTED); 469 mInputDevices.remove(device); 470 471 int status = msg.arg2; 472 broadcastVirtualUnplugStatus(device, status); 473 } 474 handleMessageSetReport(Message msg)475 private void handleMessageSetReport(Message msg) { 476 BluetoothDevice device = (BluetoothDevice) msg.obj; 477 Bundle data = msg.getData(); 478 byte reportType = data.getByte(BluetoothHidHost.EXTRA_REPORT_TYPE); 479 String report = data.getString(BluetoothHidHost.EXTRA_REPORT); 480 if (!mNativeInterface.setReport( 481 getByteAddress(device), 482 getAddressType(device), 483 getTransport(device), 484 reportType, 485 report)) { 486 Log.e(TAG, "Error: set report native returns false"); 487 } 488 } 489 handleMessageOnHandshake(Message msg)490 private void handleMessageOnHandshake(Message msg) { 491 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 492 int transport = msg.arg1; 493 if (!checkTransport(device, transport, msg.what)) { 494 return; 495 } 496 497 int status = msg.arg2; 498 broadcastHandshake(device, status); 499 } 500 handleMessageOnGetReport(Message msg)501 private void handleMessageOnGetReport(Message msg) { 502 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 503 int transport = msg.arg1; 504 if (!checkTransport(device, transport, msg.what)) { 505 return; 506 } 507 508 Bundle data = msg.getData(); 509 byte[] report = data.getByteArray(BluetoothHidHost.EXTRA_REPORT); 510 int bufferSize = data.getInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE); 511 broadcastReport(device, report, bufferSize); 512 } 513 handleMessageGetReport(Message msg)514 private void handleMessageGetReport(Message msg) { 515 BluetoothDevice device = (BluetoothDevice) msg.obj; 516 Bundle data = msg.getData(); 517 byte reportType = data.getByte(BluetoothHidHost.EXTRA_REPORT_TYPE); 518 byte reportId = data.getByte(BluetoothHidHost.EXTRA_REPORT_ID); 519 int bufferSize = data.getInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE); 520 if (!mNativeInterface.getReport( 521 getByteAddress(device), 522 getAddressType(device), 523 getTransport(device), 524 reportType, 525 reportId, 526 bufferSize)) { 527 Log.e(TAG, "Error: get report native returns false"); 528 } 529 } 530 handleMessageSetProtocolMode(Message msg)531 private void handleMessageSetProtocolMode(Message msg) { 532 BluetoothDevice device = (BluetoothDevice) msg.obj; 533 byte protocolMode = (byte) msg.arg1; 534 Log.d(TAG, "sending set protocol mode(" + protocolMode + ")"); 535 if (!mNativeInterface.setProtocolMode( 536 getByteAddress(device), 537 getAddressType(device), 538 getTransport(device), 539 protocolMode)) { 540 Log.e(TAG, "Error: set protocol mode native returns false"); 541 } 542 } 543 handleMessageVirtualUnplug(Message msg)544 private void handleMessageVirtualUnplug(Message msg) { 545 BluetoothDevice device = (BluetoothDevice) msg.obj; 546 if (!mNativeInterface.virtualUnPlug( 547 getByteAddress(device), getAddressType(device), getTransport(device))) { 548 Log.e(TAG, "Error: virtual unplug native returns false"); 549 } 550 } 551 handleMessageOnGetProtocolMode(Message msg)552 private void handleMessageOnGetProtocolMode(Message msg) { 553 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 554 int transport = msg.arg1; 555 int protocolMode = msg.arg2; 556 557 if (!checkTransport(device, transport, msg.what)) { 558 return; 559 } 560 561 broadcastProtocolMode(device, protocolMode); 562 } 563 handleMessageGetProtocolMode(Message msg)564 private void handleMessageGetProtocolMode(Message msg) { 565 BluetoothDevice device = (BluetoothDevice) msg.obj; 566 if (!mNativeInterface.getProtocolMode( 567 getByteAddress(device), getAddressType(device), getTransport(device))) { 568 Log.e(TAG, "Error: get protocol mode native returns false"); 569 } 570 } 571 handleMessageConnectStateChanged(Message msg)572 private void handleMessageConnectStateChanged(Message msg) { 573 BluetoothDevice device = mAdapterService.getDeviceFromByte((byte[]) msg.obj); 574 int transport = msg.arg1; 575 int state = msg.arg2; 576 int prevState = getState(device, transport); 577 578 InputDevice inputDevice = mInputDevices.get(device); 579 if (inputDevice != null) { 580 // Update transport if it was not resolved already 581 if (inputDevice.mSelectedTransport == BluetoothDevice.TRANSPORT_AUTO) { 582 inputDevice.mSelectedTransport = transport; 583 setTransport(device, transport); 584 } 585 } else { 586 // ACCEPTING state for unknown device indicates that this device 587 // was loaded from storage. Add it in the record. 588 if (state == STATE_ACCEPTING) { 589 setTransport(device, transport); 590 } else { 591 Log.e( 592 TAG, 593 "handleMessageConnectStateChanged: Disconnect and unknown inputDevice" 594 + (" device=" + device) 595 + (" state=" + state)); 596 nativeDisconnect(device, transport, false); 597 return; 598 } 599 } 600 601 if (transport != getTransport(device)) { 602 Log.w( 603 TAG, 604 "handleMessageConnectStateChanged: Not preferred transport in message" 605 + (" device=" + device) 606 + (" transport=" + transport) 607 + (" newState=" + state) 608 + (" prevState=" + prevState)); 609 if (Flags.ignoreUnselectedHidTransportStates()) { 610 return; 611 } 612 } 613 614 Log.d( 615 TAG, 616 "handleMessageConnectStateChanged:" 617 + (" device=" + device) 618 + (" transport=" + transport) 619 + (" newState=" + state) 620 + (" prevState=" + prevState)); 621 622 // Process connection 623 if (prevState == STATE_DISCONNECTED && state == STATE_CONNECTED) { 624 processConnection(device, transport); 625 } 626 627 // ACCEPTING state has to be treated as DISCONNECTED state 628 int reportedState = state; 629 if (state == STATE_ACCEPTING) { 630 reportedState = STATE_DISCONNECTED; 631 } 632 updateConnectionState(device, transport, reportedState); 633 } 634 handleMessageDisconnect(Message msg)635 private void handleMessageDisconnect(Message msg) { 636 BluetoothDevice device = (BluetoothDevice) msg.obj; 637 int connectionPolicy = msg.arg1; 638 639 boolean reconnectAllowed = true; 640 if (connectionPolicy != CONNECTION_POLICY_ALLOWED) { 641 reconnectAllowed = false; 642 } 643 nativeDisconnect(device, getTransport(device), reconnectAllowed); 644 } 645 handleMessageConnect(Message msg)646 private void handleMessageConnect(Message msg) { 647 BluetoothDevice device = (BluetoothDevice) msg.obj; 648 InputDevice inputDevice = getOrCreateInputDevice(device); 649 650 int connectionPolicy = getConnectionPolicy(device); 651 if (connectionPolicy != CONNECTION_POLICY_ALLOWED) { 652 Log.e( 653 TAG, 654 "handleMessageConnect: Connection not allowed." 655 + (" device=" + device) 656 + (" connectionPolicy=" + connectionPolicy)); 657 658 return; 659 } 660 nativeConnect(device, inputDevice.mSelectedTransport); 661 } 662 663 /** 664 * Checks if the reported transport does not match the selected transport 665 * 666 * @param device remote device 667 * @param transport reported transport 668 * @param message message ID for logging purpose 669 * @return true if transport matches, otherwise false 670 */ checkTransport(BluetoothDevice device, int transport, int message)671 private boolean checkTransport(BluetoothDevice device, int transport, int message) { 672 if (getTransport(device) != transport) { 673 Log.w( 674 TAG, 675 "checkTransport:" 676 + (" message= " + message) 677 + (" reported transport(" + transport + ")") 678 + (" doesn't match selected transport(" + getTransport(device) + ")")); 679 return false; 680 } 681 return true; 682 } 683 684 /** 685 * Handles connection complete 686 * 687 * @param device remote device 688 * @return true if the connection is being retained, otherwise false 689 */ processConnection(BluetoothDevice device, int transport)690 private boolean processConnection(BluetoothDevice device, int transport) { 691 if (!okToConnect(device)) { 692 Log.w( 693 TAG, 694 "processConnection: Incoming HID connection rejected." 695 + (" device=" + device) 696 + (" connectionPolicy=" + getConnectionPolicy(device))); 697 698 nativeDisconnect(device, transport, false); 699 return false; 700 } 701 return true; 702 } 703 704 // APIs 705 706 /** 707 * Connects the hid host profile for the passed in device 708 * 709 * @param device is the device with which to connect the hid host profile 710 * @return true if connection request is passed down to mHandler. 711 */ connect(BluetoothDevice device)712 public boolean connect(BluetoothDevice device) { 713 Log.d(TAG, "connect: device=" + device); 714 int state = getConnectionState(device); 715 if (state != STATE_DISCONNECTED) { 716 Log.e(TAG, "Device " + device + " not disconnected. state=" + state); 717 return false; 718 } 719 if (getConnectionPolicy(device) == CONNECTION_POLICY_FORBIDDEN) { 720 Log.e(TAG, "Device " + device + " CONNECTION_POLICY_FORBIDDEN"); 721 return false; 722 } 723 724 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device); 725 mHandler.sendMessage(msg); 726 return true; 727 } 728 729 /** 730 * Disconnects the hid host profile from the passed in device 731 * 732 * @param device is the device with which to disconnect the hid host profile 733 * @return true 734 */ disconnect(BluetoothDevice device, int connectionPolicy)735 private boolean disconnect(BluetoothDevice device, int connectionPolicy) { 736 Log.d(TAG, "disconnect: device=" + device + " connectionPolicy=" + connectionPolicy); 737 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT, device); 738 msg.arg1 = connectionPolicy; 739 mHandler.sendMessage(msg); 740 return true; 741 } 742 743 /** 744 * Disconnects the hid host profile from the passed in device 745 * 746 * @param device is the device with which to disconnect the hid host profile 747 * @return true 748 */ disconnect(BluetoothDevice device)749 public boolean disconnect(BluetoothDevice device) { 750 disconnect(device, getConnectionPolicy(device)); 751 return true; 752 } 753 754 /** 755 * Get the current connection state of the profile 756 * 757 * @param device is the remote bluetooth device 758 * @return {@link BluetoothProfile#STATE_DISCONNECTED} if this profile is disconnected, {@link 759 * BluetoothProfile#STATE_CONNECTING} if this profile is being connected, {@link 760 * BluetoothProfile#STATE_CONNECTED} if this profile is connected, or {@link 761 * BluetoothProfile#STATE_DISCONNECTING} if this profile is being disconnected 762 */ getConnectionState(BluetoothDevice device)763 public int getConnectionState(BluetoothDevice device) { 764 Log.d(TAG, "getConnectionState: device=" + device); 765 InputDevice inputDevice = mInputDevices.get(device); 766 if (inputDevice != null) { 767 return inputDevice.getState(); 768 } 769 return STATE_DISCONNECTED; 770 } 771 getDevicesMatchingConnectionStates(int[] states)772 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 773 Log.d(TAG, "getDevicesMatchingConnectionStates()"); 774 return mInputDevices.entrySet().stream() 775 .filter(e -> IntStream.of(states).anyMatch(x -> x == e.getValue().getState())) 776 .map(Map.Entry::getKey) 777 .collect(Collectors.toList()); 778 } 779 780 /** 781 * Set connection policy of the profile and connects it if connectionPolicy is {@link 782 * BluetoothProfile#CONNECTION_POLICY_ALLOWED} or disconnects if connectionPolicy is {@link 783 * BluetoothProfile#CONNECTION_POLICY_FORBIDDEN} 784 * 785 * <p>The device should already be paired. Connection policy can be one of: {@link 786 * BluetoothProfile#CONNECTION_POLICY_ALLOWED}, {@link 787 * BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, {@link 788 * BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 789 * 790 * @param device Paired bluetooth device 791 * @param connectionPolicy is the connection policy to set to for this profile 792 * @return true if connectionPolicy is set, false on error 793 */ setConnectionPolicy(BluetoothDevice device, int connectionPolicy)794 public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { 795 Log.d(TAG, "setConnectionPolicy: device=" + device); 796 797 if (!mDatabaseManager.setProfileConnectionPolicy( 798 device, BluetoothProfile.HID_HOST, connectionPolicy)) { 799 return false; 800 } 801 Log.d(TAG, "Saved connectionPolicy=" + connectionPolicy + " for device=" + device); 802 if (connectionPolicy == CONNECTION_POLICY_ALLOWED) { 803 connect(device); 804 } else if (connectionPolicy == CONNECTION_POLICY_FORBIDDEN) { 805 disconnect(device, CONNECTION_POLICY_FORBIDDEN); 806 MetricsLogger.getInstance() 807 .count(BluetoothProtoEnums.HIDH_COUNT_CONNECTION_POLICY_DISABLED, 1); 808 } 809 return true; 810 } 811 812 /** 813 * @see BluetoothHidHost#setPreferredTransport 814 */ setPreferredTransport(BluetoothDevice device, int transport)815 boolean setPreferredTransport(BluetoothDevice device, int transport) { 816 Log.i(TAG, "setPreferredTransport: device=" + device + " transport=" + transport); 817 818 if (mAdapterService.getBondState(device) != BluetoothDevice.BOND_BONDED) { 819 Log.w(TAG, "Device " + device + " not bonded"); 820 return false; 821 } 822 823 final ParcelUuid[] uuids = mAdapterService.getRemoteUuids(device); 824 boolean hidSupported = Utils.arrayContains(uuids, BluetoothUuid.HID); 825 boolean hogpSupported = Utils.arrayContains(uuids, BluetoothUuid.HOGP); 826 boolean headtrackerSupported = 827 Utils.arrayContains(uuids, HidHostService.ANDROID_HEADTRACKER_UUID); 828 if (transport == BluetoothDevice.TRANSPORT_BREDR && !hidSupported) { 829 Log.w(TAG, "device " + device + " does not support HID"); 830 return false; 831 } else if (transport == BluetoothDevice.TRANSPORT_LE 832 && !(hogpSupported || headtrackerSupported)) { 833 Log.w(TAG, "device " + device + " does not support HOGP"); 834 return false; 835 } 836 837 Message msg = mHandler.obtainMessage(MESSAGE_SET_PREFERRED_TRANSPORT, device); 838 msg.arg1 = transport; 839 mHandler.sendMessage(msg); 840 841 return true; 842 } 843 844 /** 845 * Get the connection policy of the profile. 846 * 847 * <p>The connection policy can be any of: {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}, 848 * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}, {@link 849 * BluetoothProfile#CONNECTION_POLICY_UNKNOWN} 850 * 851 * @param device Bluetooth device 852 * @return connection policy of the device 853 */ getConnectionPolicy(BluetoothDevice device)854 public int getConnectionPolicy(BluetoothDevice device) { 855 Log.d(TAG, "getConnectionPolicy: device=" + device); 856 return mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HID_HOST); 857 } 858 859 /** 860 * @see BluetoothHidHost#getPreferredTransport 861 */ getPreferredTransport(BluetoothDevice device)862 int getPreferredTransport(BluetoothDevice device) { 863 Log.d(TAG, "getPreferredTransport: device=" + device); 864 865 // TODO: Access to mInputDevices should be protected in binder thread 866 return getTransport(device); 867 } 868 869 /* The following APIs regarding test app for compliance */ getProtocolMode(BluetoothDevice device)870 boolean getProtocolMode(BluetoothDevice device) { 871 Log.d(TAG, "getProtocolMode: device=" + device); 872 int state = this.getConnectionState(device); 873 if (state != STATE_CONNECTED) { 874 return false; 875 } 876 Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE, device); 877 mHandler.sendMessage(msg); 878 return true; 879 } 880 virtualUnplug(BluetoothDevice device)881 boolean virtualUnplug(BluetoothDevice device) { 882 Log.d(TAG, "virtualUnplug: device=" + device); 883 int state = this.getConnectionState(device); 884 if (state != STATE_CONNECTED) { 885 return false; 886 } 887 Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG, device); 888 mHandler.sendMessage(msg); 889 return true; 890 } 891 setProtocolMode(BluetoothDevice device, int protocolMode)892 boolean setProtocolMode(BluetoothDevice device, int protocolMode) { 893 Log.d(TAG, "setProtocolMode: device=" + device); 894 int state = this.getConnectionState(device); 895 if (state != STATE_CONNECTED) { 896 return false; 897 } 898 Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE); 899 msg.obj = device; 900 msg.arg1 = protocolMode; 901 mHandler.sendMessage(msg); 902 return true; 903 } 904 getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize)905 boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) { 906 Log.d(TAG, "getReport: device=" + device); 907 int state = this.getConnectionState(device); 908 if (state != STATE_CONNECTED) { 909 return false; 910 } 911 Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT); 912 msg.obj = device; 913 Bundle data = new Bundle(); 914 data.putByte(BluetoothHidHost.EXTRA_REPORT_TYPE, reportType); 915 data.putByte(BluetoothHidHost.EXTRA_REPORT_ID, reportId); 916 data.putInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE, bufferSize); 917 msg.setData(data); 918 mHandler.sendMessage(msg); 919 return true; 920 } 921 setReport(BluetoothDevice device, byte reportType, String report)922 boolean setReport(BluetoothDevice device, byte reportType, String report) { 923 Log.d(TAG, "setReport: device=" + device); 924 int state = this.getConnectionState(device); 925 if (state != STATE_CONNECTED) { 926 return false; 927 } 928 Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT); 929 msg.obj = device; 930 Bundle data = new Bundle(); 931 data.putByte(BluetoothHidHost.EXTRA_REPORT_TYPE, reportType); 932 data.putString(BluetoothHidHost.EXTRA_REPORT, report); 933 msg.setData(data); 934 mHandler.sendMessage(msg); 935 return true; 936 } 937 sendData(BluetoothDevice device, String report)938 boolean sendData(BluetoothDevice device, String report) { 939 Log.d(TAG, "sendData: device=" + device); 940 int state = this.getConnectionState(device); 941 if (state != STATE_CONNECTED) { 942 return false; 943 } 944 945 Message msg = mHandler.obtainMessage(MESSAGE_SEND_DATA, device); 946 Bundle data = new Bundle(); 947 data.putString(BluetoothHidHost.EXTRA_REPORT, report); 948 msg.setData(data); 949 mHandler.sendMessage(msg); 950 return true; 951 } 952 getIdleTime(BluetoothDevice device)953 boolean getIdleTime(BluetoothDevice device) { 954 Log.d(TAG, "getIdleTime: device=" + device); 955 int state = this.getConnectionState(device); 956 if (state != STATE_CONNECTED) { 957 return false; 958 } 959 Message msg = mHandler.obtainMessage(MESSAGE_GET_IDLE_TIME, device); 960 mHandler.sendMessage(msg); 961 return true; 962 } 963 setIdleTime(BluetoothDevice device, byte idleTime)964 boolean setIdleTime(BluetoothDevice device, byte idleTime) { 965 Log.d(TAG, "setIdleTime: device=" + device); 966 int state = this.getConnectionState(device); 967 if (state != STATE_CONNECTED) { 968 return false; 969 } 970 Message msg = mHandler.obtainMessage(MESSAGE_SET_IDLE_TIME); 971 msg.obj = device; 972 Bundle data = new Bundle(); 973 data.putByte(BluetoothHidHost.EXTRA_IDLE_TIME, idleTime); 974 msg.setData(data); 975 mHandler.sendMessage(msg); 976 return true; 977 } 978 onGetProtocolMode(byte[] address, int addressType, int transport, int mode)979 void onGetProtocolMode(byte[] address, int addressType, int transport, int mode) { 980 Log.d(TAG, "onGetProtocolMode()"); 981 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE); 982 msg.obj = address; 983 msg.arg1 = transport; 984 msg.arg2 = mode; 985 mHandler.sendMessage(msg); 986 } 987 onGetIdleTime(byte[] address, int addressType, int transport, int idleTime)988 void onGetIdleTime(byte[] address, int addressType, int transport, int idleTime) { 989 Log.d(TAG, "onGetIdleTime()"); 990 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_IDLE_TIME); 991 msg.obj = address; 992 msg.arg1 = transport; 993 msg.arg2 = idleTime; 994 mHandler.sendMessage(msg); 995 } 996 onGetReport(byte[] address, int addressType, int transport, byte[] report, int rptSize)997 void onGetReport(byte[] address, int addressType, int transport, byte[] report, int rptSize) { 998 Log.d(TAG, "onGetReport()"); 999 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_REPORT); 1000 msg.obj = address; 1001 msg.arg1 = transport; 1002 Bundle data = new Bundle(); 1003 data.putByteArray(BluetoothHidHost.EXTRA_REPORT, report); 1004 data.putInt(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE, rptSize); 1005 msg.setData(data); 1006 mHandler.sendMessage(msg); 1007 } 1008 onHandshake(byte[] address, int addressType, int transport, int status)1009 void onHandshake(byte[] address, int addressType, int transport, int status) { 1010 Log.d(TAG, "onHandshake: status=" + status); 1011 Message msg = mHandler.obtainMessage(MESSAGE_ON_HANDSHAKE); 1012 msg.obj = address; 1013 msg.arg1 = transport; 1014 msg.arg2 = status; 1015 mHandler.sendMessage(msg); 1016 } 1017 onVirtualUnplug(byte[] address, int addressType, int transport, int status)1018 void onVirtualUnplug(byte[] address, int addressType, int transport, int status) { 1019 Log.d(TAG, "onVirtualUnplug: status=" + status); 1020 Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG); 1021 msg.obj = address; 1022 msg.arg1 = transport; 1023 msg.arg2 = status; 1024 mHandler.sendMessage(msg); 1025 } 1026 onConnectStateChanged(byte[] address, int addressType, int transport, int state)1027 void onConnectStateChanged(byte[] address, int addressType, int transport, int state) { 1028 Log.d(TAG, "onConnectStateChanged: state=" + state); 1029 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED, address); 1030 msg.arg1 = transport; 1031 msg.arg2 = state; 1032 mHandler.sendMessage(msg); 1033 } 1034 1035 /** 1036 * Saves new connection state. Broadcasts any change from previous state 1037 * 1038 * @param device remote device 1039 * @param transport transport 1040 * @param newState new connection state 1041 */ updateConnectionState(BluetoothDevice device, int transport, int newState)1042 private void updateConnectionState(BluetoothDevice device, int transport, int newState) { 1043 InputDevice inputDevice = mInputDevices.get(device); 1044 1045 if (inputDevice == null) { 1046 Log.w( 1047 TAG, 1048 "updateConnectionState: requested on unknown inputDevice" 1049 + (" device=" + device) 1050 + (" newState=" + newState) 1051 + (" transport=" + transport)); 1052 return; 1053 } 1054 1055 if (transport == BluetoothDevice.TRANSPORT_AUTO) { 1056 Log.w( 1057 TAG, 1058 "updateConnectionState: requested with AUTO transport" 1059 + (" device=" + device) 1060 + (" newState=" + newState)); 1061 return; 1062 } 1063 1064 int prevState = inputDevice.getState(transport); 1065 inputDevice.setState(transport, newState); 1066 1067 if (prevState == newState) { 1068 Log.d( 1069 TAG, 1070 "updateConnectionState: No state change for" 1071 + (" device=" + device) 1072 + (" newState=" + newState) 1073 + (" transport=" + transport)); 1074 return; 1075 } 1076 1077 mInputDevices.put(device, inputDevice); 1078 1079 broadcastConnectionState(device, transport, prevState, newState); 1080 } 1081 1082 // This method does not check for error condition (newState == prevState) broadcastConnectionState( BluetoothDevice device, int transport, int prevState, int newState)1083 private void broadcastConnectionState( 1084 BluetoothDevice device, int transport, int prevState, int newState) { 1085 // Notifying the connection state change of the profile before sending the intent for 1086 // connection state change, as it was causing a race condition, with the UI not being 1087 // updated with the correct connection state. 1088 Log.i( 1089 TAG, 1090 "broadcastConnectionState:" 1091 + (" device= " + device) 1092 + (" transport= " + transport) 1093 + (" prevState=" + prevState + " -> newState=" + newState)); 1094 1095 mAdapterService.updateProfileConnectionAdapterProperties( 1096 device, BluetoothProfile.HID_HOST, newState, prevState); 1097 1098 Intent intent = new Intent(BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED); 1099 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 1100 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 1101 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1102 intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, transport); 1103 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1104 sendBroadcastAsUser( 1105 intent, 1106 UserHandle.ALL, 1107 BLUETOOTH_CONNECT, 1108 Utils.getTempBroadcastOptions().toBundle()); 1109 } 1110 broadcastHandshake(BluetoothDevice device, int status)1111 private void broadcastHandshake(BluetoothDevice device, int status) { 1112 Intent intent = new Intent(BluetoothHidHost.ACTION_HANDSHAKE); 1113 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1114 intent.putExtra(BluetoothHidHost.EXTRA_STATUS, status); 1115 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1116 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1117 } 1118 broadcastProtocolMode(BluetoothDevice device, int protocolMode)1119 private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) { 1120 Intent intent = new Intent(BluetoothHidHost.ACTION_PROTOCOL_MODE_CHANGED); 1121 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1122 intent.putExtra(BluetoothHidHost.EXTRA_PROTOCOL_MODE, protocolMode); 1123 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1124 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1125 Log.d(TAG, "broadcastProtocolMode: device=" + device + " protocolMode=" + protocolMode); 1126 } 1127 broadcastReport(BluetoothDevice device, byte[] report, int rptSize)1128 private void broadcastReport(BluetoothDevice device, byte[] report, int rptSize) { 1129 Intent intent = new Intent(BluetoothHidHost.ACTION_REPORT); 1130 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1131 intent.putExtra(BluetoothHidHost.EXTRA_REPORT, report); 1132 intent.putExtra(BluetoothHidHost.EXTRA_REPORT_BUFFER_SIZE, rptSize); 1133 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1134 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1135 } 1136 broadcastVirtualUnplugStatus(BluetoothDevice device, int status)1137 private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) { 1138 Intent intent = new Intent(BluetoothHidHost.ACTION_VIRTUAL_UNPLUG_STATUS); 1139 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1140 intent.putExtra(BluetoothHidHost.EXTRA_VIRTUAL_UNPLUG_STATUS, status); 1141 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1142 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1143 } 1144 broadcastIdleTime(BluetoothDevice device, int idleTime)1145 private void broadcastIdleTime(BluetoothDevice device, int idleTime) { 1146 Intent intent = new Intent(BluetoothHidHost.ACTION_IDLE_TIME_CHANGED); 1147 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 1148 intent.putExtra(BluetoothHidHost.EXTRA_IDLE_TIME, idleTime); 1149 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1150 sendBroadcast(intent, BLUETOOTH_CONNECT, Utils.getTempBroadcastOptions().toBundle()); 1151 Log.d(TAG, "broadcastIdleTime: device=" + device + " idleTime=" + idleTime); 1152 } 1153 1154 /** 1155 * Check whether can connect to a peer device. The check considers a number of factors during 1156 * the evaluation. 1157 * 1158 * @param device the peer device to connect to 1159 * @return true if connection is allowed, otherwise false 1160 */ 1161 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) okToConnect(BluetoothDevice device)1162 public boolean okToConnect(BluetoothDevice device) { 1163 // Check if this is an incoming connection in Quiet mode. 1164 if (mAdapterService.isQuietModeEnabled()) { 1165 Log.w(TAG, "okToConnect: return false because of quiet mode enabled. device=" + device); 1166 return false; 1167 } 1168 // Check connection policy and accept or reject the connection. 1169 int connectionPolicy = getConnectionPolicy(device); 1170 if (!Flags.donotValidateBondStateFromProfiles()) { 1171 int bondState = mAdapterService.getBondState(device); 1172 // Allow this connection only if the device is bonded. Any attempt to connect 1173 // while bonding would potentially lead to an unauthorized connection. 1174 if (bondState != BluetoothDevice.BOND_BONDED) { 1175 Log.w( 1176 TAG, 1177 "okToConnect: return false, device=" + device + " bondState=" + bondState); 1178 return false; 1179 } 1180 } 1181 if (connectionPolicy != CONNECTION_POLICY_UNKNOWN 1182 && connectionPolicy != CONNECTION_POLICY_ALLOWED) { 1183 // Otherwise, reject the connection if connectionPolicy is not valid. 1184 Log.w( 1185 TAG, 1186 "okToConnect: return false," 1187 + (" device=" + device) 1188 + (" connectionPolicy=" + connectionPolicy)); 1189 return false; 1190 } 1191 return true; 1192 } 1193 1194 @Override dump(StringBuilder sb)1195 public void dump(StringBuilder sb) { 1196 super.dump(sb); 1197 println(sb, "mInputDevices:"); 1198 mInputDevices.forEach( 1199 (k, v) -> sb.append(" ").append(k).append(" : ").append(v).append("\n")); 1200 } 1201 } 1202