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