1 /* 2 * Copyright (C) 2011 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 android.bluetooth; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SdkConstant; 23 import android.annotation.SdkConstant.SdkConstantType; 24 import android.bluetooth.annotations.RequiresBluetoothConnectPermission; 25 import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission; 26 import android.bluetooth.annotations.RequiresLegacyBluetoothPermission; 27 import android.annotation.SuppressLint; 28 import android.annotation.SystemApi; 29 import android.content.Attributable; 30 import android.content.AttributionSource; 31 import android.content.Context; 32 import android.os.Binder; 33 import android.os.IBinder; 34 import android.os.RemoteException; 35 import android.util.Log; 36 37 import java.util.ArrayList; 38 import java.util.List; 39 40 41 /** 42 * This class provides the public APIs to control the Bluetooth Input 43 * Device Profile. 44 * 45 * <p>BluetoothHidHost is a proxy object for controlling the Bluetooth 46 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get 47 * the BluetoothHidHost proxy object. 48 * 49 * <p>Each method is protected with its appropriate permission. 50 * 51 * @hide 52 */ 53 @SystemApi 54 public final class BluetoothHidHost implements BluetoothProfile { 55 private static final String TAG = "BluetoothHidHost"; 56 private static final boolean DBG = true; 57 private static final boolean VDBG = false; 58 59 /** 60 * Intent used to broadcast the change in connection state of the Input 61 * Device profile. 62 * 63 * <p>This intent will have 3 extras: 64 * <ul> 65 * <li> {@link #EXTRA_STATE} - The current state of the profile. </li> 66 * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li> 67 * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li> 68 * </ul> 69 * 70 * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of 71 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, 72 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. 73 */ 74 @SuppressLint("ActionValue") 75 @RequiresLegacyBluetoothPermission 76 @RequiresBluetoothConnectPermission 77 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 78 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 79 public static final String ACTION_CONNECTION_STATE_CHANGED = 80 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; 81 82 /** 83 * @hide 84 */ 85 @RequiresBluetoothConnectPermission 86 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 87 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 88 public static final String ACTION_PROTOCOL_MODE_CHANGED = 89 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED"; 90 91 /** 92 * @hide 93 */ 94 @RequiresBluetoothConnectPermission 95 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 96 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 97 public static final String ACTION_HANDSHAKE = 98 "android.bluetooth.input.profile.action.HANDSHAKE"; 99 100 /** 101 * @hide 102 */ 103 @RequiresBluetoothConnectPermission 104 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 105 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 106 public static final String ACTION_REPORT = 107 "android.bluetooth.input.profile.action.REPORT"; 108 109 /** 110 * @hide 111 */ 112 @RequiresBluetoothConnectPermission 113 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 114 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 115 public static final String ACTION_VIRTUAL_UNPLUG_STATUS = 116 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS"; 117 118 /** 119 * @hide 120 */ 121 @RequiresBluetoothConnectPermission 122 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) 123 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 124 public static final String ACTION_IDLE_TIME_CHANGED = 125 "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED"; 126 127 /** 128 * Return codes for the connect and disconnect Bluez / Dbus calls. 129 * 130 * @hide 131 */ 132 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000; 133 134 /** 135 * @hide 136 */ 137 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001; 138 139 /** 140 * @hide 141 */ 142 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002; 143 144 /** 145 * @hide 146 */ 147 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003; 148 149 /** 150 * @hide 151 */ 152 public static final int INPUT_OPERATION_SUCCESS = 5004; 153 154 /** 155 * @hide 156 */ 157 public static final int PROTOCOL_REPORT_MODE = 0; 158 159 /** 160 * @hide 161 */ 162 public static final int PROTOCOL_BOOT_MODE = 1; 163 164 /** 165 * @hide 166 */ 167 public static final int PROTOCOL_UNSUPPORTED_MODE = 255; 168 169 /* int reportType, int reportType, int bufferSize */ 170 /** 171 * @hide 172 */ 173 public static final byte REPORT_TYPE_INPUT = 1; 174 175 /** 176 * @hide 177 */ 178 public static final byte REPORT_TYPE_OUTPUT = 2; 179 180 /** 181 * @hide 182 */ 183 public static final byte REPORT_TYPE_FEATURE = 3; 184 185 /** 186 * @hide 187 */ 188 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0; 189 190 /** 191 * @hide 192 */ 193 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1; 194 195 /** 196 * @hide 197 */ 198 public static final String EXTRA_PROTOCOL_MODE = 199 "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE"; 200 201 /** 202 * @hide 203 */ 204 public static final String EXTRA_REPORT_TYPE = 205 "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE"; 206 207 /** 208 * @hide 209 */ 210 public static final String EXTRA_REPORT_ID = 211 "android.bluetooth.BluetoothHidHost.extra.REPORT_ID"; 212 213 /** 214 * @hide 215 */ 216 public static final String EXTRA_REPORT_BUFFER_SIZE = 217 "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE"; 218 219 /** 220 * @hide 221 */ 222 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT"; 223 224 /** 225 * @hide 226 */ 227 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS"; 228 229 /** 230 * @hide 231 */ 232 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = 233 "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS"; 234 235 /** 236 * @hide 237 */ 238 public static final String EXTRA_IDLE_TIME = 239 "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME"; 240 241 private final BluetoothAdapter mAdapter; 242 private final AttributionSource mAttributionSource; 243 private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector = 244 new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST, 245 "BluetoothHidHost", IBluetoothHidHost.class.getName()) { 246 @Override 247 public IBluetoothHidHost getServiceInterface(IBinder service) { 248 return IBluetoothHidHost.Stub.asInterface(Binder.allowBlocking(service)); 249 } 250 }; 251 252 /** 253 * Create a BluetoothHidHost proxy object for interacting with the local 254 * Bluetooth Service which handles the InputDevice profile 255 */ BluetoothHidHost(Context context, ServiceListener listener, BluetoothAdapter adapter)256 /* package */ BluetoothHidHost(Context context, ServiceListener listener, 257 BluetoothAdapter adapter) { 258 mAdapter = adapter; 259 mAttributionSource = adapter.getAttributionSource(); 260 mProfileConnector.connect(context, listener); 261 } 262 close()263 /*package*/ void close() { 264 if (VDBG) log("close()"); 265 mProfileConnector.disconnect(); 266 } 267 getService()268 private IBluetoothHidHost getService() { 269 return mProfileConnector.getService(); 270 } 271 272 /** 273 * Initiate connection to a profile of the remote bluetooth device. 274 * 275 * <p> The system supports connection to multiple input devices. 276 * 277 * <p> This API returns false in scenarios like the profile on the 278 * device is already connected or Bluetooth is not turned on. 279 * When this API returns true, it is guaranteed that 280 * connection state intent for the profile will be broadcasted with 281 * the state. Users can get the connection state of the profile 282 * from this intent. 283 * 284 * @param device Remote Bluetooth Device 285 * @return false on immediate error, true otherwise 286 * @hide 287 */ 288 @RequiresBluetoothConnectPermission 289 @RequiresPermission(allOf = { 290 android.Manifest.permission.BLUETOOTH_CONNECT, 291 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 292 }) connect(BluetoothDevice device)293 public boolean connect(BluetoothDevice device) { 294 if (DBG) log("connect(" + device + ")"); 295 final IBluetoothHidHost service = getService(); 296 if (service != null && isEnabled() && isValidDevice(device)) { 297 try { 298 return service.connect(device, mAttributionSource); 299 } catch (RemoteException e) { 300 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 301 return false; 302 } 303 } 304 if (service == null) Log.w(TAG, "Proxy not attached to service"); 305 return false; 306 } 307 308 /** 309 * Initiate disconnection from a profile 310 * 311 * <p> This API will return false in scenarios like the profile on the 312 * Bluetooth device is not in connected state etc. When this API returns, 313 * true, it is guaranteed that the connection state change 314 * intent will be broadcasted with the state. Users can get the 315 * disconnection state of the profile from this intent. 316 * 317 * <p> If the disconnection is initiated by a remote device, the state 318 * will transition from {@link #STATE_CONNECTED} to 319 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the 320 * host (local) device the state will transition from 321 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to 322 * state {@link #STATE_DISCONNECTED}. The transition to 323 * {@link #STATE_DISCONNECTING} can be used to distinguish between the 324 * two scenarios. 325 * 326 * @param device Remote Bluetooth Device 327 * @return false on immediate error, true otherwise 328 * @hide 329 */ 330 @RequiresBluetoothConnectPermission 331 @RequiresPermission(allOf = { 332 android.Manifest.permission.BLUETOOTH_CONNECT, 333 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 334 }) disconnect(BluetoothDevice device)335 public boolean disconnect(BluetoothDevice device) { 336 if (DBG) log("disconnect(" + device + ")"); 337 final IBluetoothHidHost service = getService(); 338 if (service != null && isEnabled() && isValidDevice(device)) { 339 try { 340 return service.disconnect(device, mAttributionSource); 341 } catch (RemoteException e) { 342 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 343 return false; 344 } 345 } 346 if (service == null) Log.w(TAG, "Proxy not attached to service"); 347 return false; 348 } 349 350 /** 351 * {@inheritDoc} 352 * 353 * @hide 354 */ 355 @SystemApi 356 @Override 357 @RequiresBluetoothConnectPermission 358 @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) getConnectedDevices()359 public @NonNull List<BluetoothDevice> getConnectedDevices() { 360 if (VDBG) log("getConnectedDevices()"); 361 final IBluetoothHidHost service = getService(); 362 if (service != null && isEnabled()) { 363 try { 364 return Attributable.setAttributionSource( 365 service.getConnectedDevices(mAttributionSource), mAttributionSource); 366 } catch (RemoteException e) { 367 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 368 return new ArrayList<BluetoothDevice>(); 369 } 370 } 371 if (service == null) Log.w(TAG, "Proxy not attached to service"); 372 return new ArrayList<BluetoothDevice>(); 373 } 374 375 /** 376 * {@inheritDoc} 377 * 378 * @hide 379 */ 380 @Override 381 @RequiresBluetoothConnectPermission 382 @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) getDevicesMatchingConnectionStates(int[] states)383 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 384 if (VDBG) log("getDevicesMatchingStates()"); 385 final IBluetoothHidHost service = getService(); 386 if (service != null && isEnabled()) { 387 try { 388 return Attributable.setAttributionSource( 389 service.getDevicesMatchingConnectionStates(states, mAttributionSource), 390 mAttributionSource); 391 } catch (RemoteException e) { 392 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 393 return new ArrayList<BluetoothDevice>(); 394 } 395 } 396 if (service == null) Log.w(TAG, "Proxy not attached to service"); 397 return new ArrayList<BluetoothDevice>(); 398 } 399 400 /** 401 * {@inheritDoc} 402 * 403 * @hide 404 */ 405 @SystemApi 406 @Override 407 @RequiresBluetoothConnectPermission 408 @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT) getConnectionState(@onNull BluetoothDevice device)409 public int getConnectionState(@NonNull BluetoothDevice device) { 410 if (VDBG) log("getState(" + device + ")"); 411 if (device == null) { 412 throw new IllegalArgumentException("device must not be null"); 413 } 414 final IBluetoothHidHost service = getService(); 415 if (service != null && isEnabled() && isValidDevice(device)) { 416 try { 417 return service.getConnectionState(device, mAttributionSource); 418 } catch (RemoteException e) { 419 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 420 return BluetoothProfile.STATE_DISCONNECTED; 421 } 422 } 423 if (service == null) Log.w(TAG, "Proxy not attached to service"); 424 return BluetoothProfile.STATE_DISCONNECTED; 425 } 426 427 /** 428 * Set priority of the profile 429 * 430 * <p> The device should already be paired. 431 * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}, 432 * 433 * @param device Paired bluetooth device 434 * @param priority 435 * @return true if priority is set, false on error 436 * @hide 437 */ 438 @RequiresBluetoothConnectPermission 439 @RequiresPermission(allOf = { 440 android.Manifest.permission.BLUETOOTH_CONNECT, 441 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 442 }) setPriority(BluetoothDevice device, int priority)443 public boolean setPriority(BluetoothDevice device, int priority) { 444 if (DBG) log("setPriority(" + device + ", " + priority + ")"); 445 return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority)); 446 } 447 448 /** 449 * Set connection policy of the profile 450 * 451 * <p> The device should already be paired. 452 * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED}, 453 * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN} 454 * 455 * @param device Paired bluetooth device 456 * @param connectionPolicy is the connection policy to set to for this profile 457 * @return true if connectionPolicy is set, false on error 458 * @hide 459 */ 460 @SystemApi 461 @RequiresBluetoothConnectPermission 462 @RequiresPermission(allOf = { 463 android.Manifest.permission.BLUETOOTH_CONNECT, 464 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 465 }) setConnectionPolicy(@onNull BluetoothDevice device, @ConnectionPolicy int connectionPolicy)466 public boolean setConnectionPolicy(@NonNull BluetoothDevice device, 467 @ConnectionPolicy int connectionPolicy) { 468 if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); 469 if (device == null) { 470 throw new IllegalArgumentException("device must not be null"); 471 } 472 final IBluetoothHidHost service = getService(); 473 if (service != null && isEnabled() && isValidDevice(device)) { 474 if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN 475 && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) { 476 return false; 477 } 478 try { 479 return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource); 480 } catch (RemoteException e) { 481 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 482 return false; 483 } 484 } 485 if (service == null) Log.w(TAG, "Proxy not attached to service"); 486 return false; 487 } 488 489 /** 490 * Get the priority of the profile. 491 * 492 * <p> The priority can be any of: 493 * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} 494 * 495 * @param device Bluetooth device 496 * @return priority of the device 497 * @hide 498 */ 499 @RequiresBluetoothConnectPermission 500 @RequiresPermission(allOf = { 501 android.Manifest.permission.BLUETOOTH_CONNECT, 502 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 503 }) getPriority(BluetoothDevice device)504 public int getPriority(BluetoothDevice device) { 505 if (VDBG) log("getPriority(" + device + ")"); 506 return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device)); 507 } 508 509 /** 510 * Get the connection policy of the profile. 511 * 512 * <p> The connection policy can be any of: 513 * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN}, 514 * {@link #CONNECTION_POLICY_UNKNOWN} 515 * 516 * @param device Bluetooth device 517 * @return connection policy of the device 518 * @hide 519 */ 520 @SystemApi 521 @RequiresBluetoothConnectPermission 522 @RequiresPermission(allOf = { 523 android.Manifest.permission.BLUETOOTH_CONNECT, 524 android.Manifest.permission.BLUETOOTH_PRIVILEGED, 525 }) getConnectionPolicy(@onNull BluetoothDevice device)526 public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) { 527 if (VDBG) log("getConnectionPolicy(" + device + ")"); 528 if (device == null) { 529 throw new IllegalArgumentException("device must not be null"); 530 } 531 final IBluetoothHidHost service = getService(); 532 if (service != null && isEnabled() && isValidDevice(device)) { 533 try { 534 return service.getConnectionPolicy(device, mAttributionSource); 535 } catch (RemoteException e) { 536 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 537 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; 538 } 539 } 540 if (service == null) Log.w(TAG, "Proxy not attached to service"); 541 return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; 542 } 543 isEnabled()544 private boolean isEnabled() { 545 return mAdapter.getState() == BluetoothAdapter.STATE_ON; 546 } 547 isValidDevice(BluetoothDevice device)548 private static boolean isValidDevice(BluetoothDevice device) { 549 return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress()); 550 } 551 552 /** 553 * Initiate virtual unplug for a HID input device. 554 * 555 * @param device Remote Bluetooth Device 556 * @return false on immediate error, true otherwise 557 * @hide 558 */ 559 @RequiresLegacyBluetoothAdminPermission 560 @RequiresBluetoothConnectPermission 561 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) virtualUnplug(BluetoothDevice device)562 public boolean virtualUnplug(BluetoothDevice device) { 563 if (DBG) log("virtualUnplug(" + device + ")"); 564 final IBluetoothHidHost service = getService(); 565 if (service != null && isEnabled() && isValidDevice(device)) { 566 try { 567 return service.virtualUnplug(device, mAttributionSource); 568 } catch (RemoteException e) { 569 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 570 return false; 571 } 572 } 573 574 if (service == null) Log.w(TAG, "Proxy not attached to service"); 575 return false; 576 577 } 578 579 /** 580 * Send Get_Protocol_Mode command to the connected HID input device. 581 * 582 * @param device Remote Bluetooth Device 583 * @return false on immediate error, true otherwise 584 * @hide 585 */ 586 @RequiresLegacyBluetoothAdminPermission 587 @RequiresBluetoothConnectPermission 588 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getProtocolMode(BluetoothDevice device)589 public boolean getProtocolMode(BluetoothDevice device) { 590 if (VDBG) log("getProtocolMode(" + device + ")"); 591 final IBluetoothHidHost service = getService(); 592 if (service != null && isEnabled() && isValidDevice(device)) { 593 try { 594 return service.getProtocolMode(device, mAttributionSource); 595 } catch (RemoteException e) { 596 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 597 return false; 598 } 599 } 600 if (service == null) Log.w(TAG, "Proxy not attached to service"); 601 return false; 602 } 603 604 /** 605 * Send Set_Protocol_Mode command to the connected HID input device. 606 * 607 * @param device Remote Bluetooth Device 608 * @return false on immediate error, true otherwise 609 * @hide 610 */ 611 @RequiresLegacyBluetoothAdminPermission 612 @RequiresBluetoothConnectPermission 613 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setProtocolMode(BluetoothDevice device, int protocolMode)614 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) { 615 if (DBG) log("setProtocolMode(" + device + ")"); 616 final IBluetoothHidHost service = getService(); 617 if (service != null && isEnabled() && isValidDevice(device)) { 618 try { 619 return service.setProtocolMode(device, protocolMode, mAttributionSource); 620 } catch (RemoteException e) { 621 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 622 return false; 623 } 624 } 625 if (service == null) Log.w(TAG, "Proxy not attached to service"); 626 return false; 627 } 628 629 /** 630 * Send Get_Report command to the connected HID input device. 631 * 632 * @param device Remote Bluetooth Device 633 * @param reportType Report type 634 * @param reportId Report ID 635 * @param bufferSize Report receiving buffer size 636 * @return false on immediate error, true otherwise 637 * @hide 638 */ 639 @RequiresLegacyBluetoothAdminPermission 640 @RequiresBluetoothConnectPermission 641 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize)642 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, 643 int bufferSize) { 644 if (VDBG) { 645 log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId 646 + "bufferSize=" + bufferSize); 647 } 648 final IBluetoothHidHost service = getService(); 649 if (service != null && isEnabled() && isValidDevice(device)) { 650 try { 651 return service.getReport(device, reportType, reportId, bufferSize, 652 mAttributionSource); 653 } catch (RemoteException e) { 654 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 655 return false; 656 } 657 } 658 if (service == null) Log.w(TAG, "Proxy not attached to service"); 659 return false; 660 } 661 662 /** 663 * Send Set_Report command to the connected HID input device. 664 * 665 * @param device Remote Bluetooth Device 666 * @param reportType Report type 667 * @param report Report receiving buffer size 668 * @return false on immediate error, true otherwise 669 * @hide 670 */ 671 @RequiresLegacyBluetoothAdminPermission 672 @RequiresBluetoothConnectPermission 673 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setReport(BluetoothDevice device, byte reportType, String report)674 public boolean setReport(BluetoothDevice device, byte reportType, String report) { 675 if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report); 676 final IBluetoothHidHost service = getService(); 677 if (service != null && isEnabled() && isValidDevice(device)) { 678 try { 679 return service.setReport(device, reportType, report, mAttributionSource); 680 } catch (RemoteException e) { 681 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 682 return false; 683 } 684 } 685 if (service == null) Log.w(TAG, "Proxy not attached to service"); 686 return false; 687 } 688 689 /** 690 * Send Send_Data command to the connected HID input device. 691 * 692 * @param device Remote Bluetooth Device 693 * @param report Report to send 694 * @return false on immediate error, true otherwise 695 * @hide 696 */ 697 @RequiresLegacyBluetoothAdminPermission 698 @RequiresBluetoothConnectPermission 699 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) sendData(BluetoothDevice device, String report)700 public boolean sendData(BluetoothDevice device, String report) { 701 if (DBG) log("sendData(" + device + "), report=" + report); 702 final IBluetoothHidHost service = getService(); 703 if (service != null && isEnabled() && isValidDevice(device)) { 704 try { 705 return service.sendData(device, report, mAttributionSource); 706 } catch (RemoteException e) { 707 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 708 return false; 709 } 710 } 711 if (service == null) Log.w(TAG, "Proxy not attached to service"); 712 return false; 713 } 714 715 /** 716 * Send Get_Idle_Time command to the connected HID input device. 717 * 718 * @param device Remote Bluetooth Device 719 * @return false on immediate error, true otherwise 720 * @hide 721 */ 722 @RequiresLegacyBluetoothAdminPermission 723 @RequiresBluetoothConnectPermission 724 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) getIdleTime(BluetoothDevice device)725 public boolean getIdleTime(BluetoothDevice device) { 726 if (DBG) log("getIdletime(" + device + ")"); 727 final IBluetoothHidHost service = getService(); 728 if (service != null && isEnabled() && isValidDevice(device)) { 729 try { 730 return service.getIdleTime(device, mAttributionSource); 731 } catch (RemoteException e) { 732 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 733 return false; 734 } 735 } 736 if (service == null) Log.w(TAG, "Proxy not attached to service"); 737 return false; 738 } 739 740 /** 741 * Send Set_Idle_Time command to the connected HID input device. 742 * 743 * @param device Remote Bluetooth Device 744 * @param idleTime Idle time to be set on HID Device 745 * @return false on immediate error, true otherwise 746 * @hide 747 */ 748 @RequiresLegacyBluetoothAdminPermission 749 @RequiresBluetoothConnectPermission 750 @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) setIdleTime(BluetoothDevice device, byte idleTime)751 public boolean setIdleTime(BluetoothDevice device, byte idleTime) { 752 if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime); 753 final IBluetoothHidHost service = getService(); 754 if (service != null && isEnabled() && isValidDevice(device)) { 755 try { 756 return service.setIdleTime(device, idleTime, mAttributionSource); 757 } catch (RemoteException e) { 758 Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); 759 return false; 760 } 761 } 762 if (service == null) Log.w(TAG, "Proxy not attached to service"); 763 return false; 764 } 765 log(String msg)766 private static void log(String msg) { 767 Log.d(TAG, msg); 768 } 769 } 770