1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.hid; 18 19 import android.app.ActivityManager; 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothHidDevice; 22 import android.bluetooth.BluetoothHidDeviceAppQosSettings; 23 import android.bluetooth.BluetoothHidDeviceAppSdpSettings; 24 import android.bluetooth.BluetoothProfile; 25 import android.bluetooth.IBluetoothHidDevice; 26 import android.bluetooth.IBluetoothHidDeviceCallback; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.os.Binder; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Message; 33 import android.os.Process; 34 import android.os.RemoteException; 35 import android.util.Log; 36 37 import com.android.bluetooth.BluetoothMetricsProto; 38 import com.android.bluetooth.Utils; 39 import com.android.bluetooth.btservice.MetricsLogger; 40 import com.android.bluetooth.btservice.ProfileService; 41 import com.android.internal.annotations.VisibleForTesting; 42 43 import java.nio.ByteBuffer; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.List; 47 import java.util.NoSuchElementException; 48 49 /** @hide */ 50 public class HidDeviceService extends ProfileService { 51 private static final boolean DBG = false; 52 private static final String TAG = HidDeviceService.class.getSimpleName(); 53 54 private static final int MESSAGE_APPLICATION_STATE_CHANGED = 1; 55 private static final int MESSAGE_CONNECT_STATE_CHANGED = 2; 56 private static final int MESSAGE_GET_REPORT = 3; 57 private static final int MESSAGE_SET_REPORT = 4; 58 private static final int MESSAGE_SET_PROTOCOL = 5; 59 private static final int MESSAGE_INTR_DATA = 6; 60 private static final int MESSAGE_VC_UNPLUG = 7; 61 private static final int MESSAGE_IMPORTANCE_CHANGE = 8; 62 63 private static final int FOREGROUND_IMPORTANCE_CUTOFF = 64 ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; 65 66 private static HidDeviceService sHidDeviceService; 67 68 private HidDeviceNativeInterface mHidDeviceNativeInterface; 69 70 private boolean mNativeAvailable = false; 71 private BluetoothDevice mHidDevice; 72 private int mHidDeviceState = BluetoothHidDevice.STATE_DISCONNECTED; 73 private int mUserUid = 0; 74 private IBluetoothHidDeviceCallback mCallback; 75 private BluetoothHidDeviceDeathRecipient mDeathRcpt; 76 private ActivityManager mActivityManager; 77 78 private HidDeviceServiceHandler mHandler; 79 80 private class HidDeviceServiceHandler extends Handler { 81 @Override handleMessage(Message msg)82 public void handleMessage(Message msg) { 83 if (DBG) { 84 Log.d(TAG, "handleMessage(): msg.what=" + msg.what); 85 } 86 87 switch (msg.what) { 88 case MESSAGE_APPLICATION_STATE_CHANGED: { 89 BluetoothDevice device = msg.obj != null ? (BluetoothDevice) msg.obj : null; 90 boolean success = (msg.arg1 != 0); 91 92 if (success) { 93 Log.d(TAG, "App registered, set device to: " + device); 94 mHidDevice = device; 95 } else { 96 mHidDevice = null; 97 } 98 99 try { 100 if (mCallback != null) { 101 mCallback.onAppStatusChanged(device, success); 102 } else { 103 break; 104 } 105 } catch (RemoteException e) { 106 Log.e(TAG, "e=" + e.toString()); 107 e.printStackTrace(); 108 } 109 110 if (success) { 111 mDeathRcpt = new BluetoothHidDeviceDeathRecipient(HidDeviceService.this); 112 if (mCallback != null) { 113 IBinder binder = mCallback.asBinder(); 114 try { 115 binder.linkToDeath(mDeathRcpt, 0); 116 Log.i(TAG, "IBinder.linkToDeath() ok"); 117 } catch (RemoteException e) { 118 e.printStackTrace(); 119 } 120 } 121 } else if (mDeathRcpt != null) { 122 if (mCallback != null) { 123 IBinder binder = mCallback.asBinder(); 124 try { 125 binder.unlinkToDeath(mDeathRcpt, 0); 126 Log.i(TAG, "IBinder.unlinkToDeath() ok"); 127 } catch (NoSuchElementException e) { 128 e.printStackTrace(); 129 } 130 mDeathRcpt.cleanup(); 131 mDeathRcpt = null; 132 } 133 } 134 135 if (!success) { 136 mCallback = null; 137 } 138 139 break; 140 } 141 142 case MESSAGE_CONNECT_STATE_CHANGED: { 143 BluetoothDevice device = (BluetoothDevice) msg.obj; 144 int halState = msg.arg1; 145 int state = convertHalState(halState); 146 147 if (state != BluetoothHidDevice.STATE_DISCONNECTED) { 148 mHidDevice = device; 149 } 150 151 setAndBroadcastConnectionState(device, state); 152 153 try { 154 if (mCallback != null) { 155 mCallback.onConnectionStateChanged(device, state); 156 } 157 } catch (RemoteException e) { 158 e.printStackTrace(); 159 } 160 break; 161 } 162 163 case MESSAGE_GET_REPORT: 164 byte type = (byte) msg.arg1; 165 byte id = (byte) msg.arg2; 166 int bufferSize = msg.obj == null ? 0 : ((Integer) msg.obj).intValue(); 167 168 try { 169 if (mCallback != null) { 170 mCallback.onGetReport(mHidDevice, type, id, bufferSize); 171 } 172 } catch (RemoteException e) { 173 e.printStackTrace(); 174 } 175 break; 176 177 case MESSAGE_SET_REPORT: { 178 byte reportType = (byte) msg.arg1; 179 byte reportId = (byte) msg.arg2; 180 byte[] data = ((ByteBuffer) msg.obj).array(); 181 182 try { 183 if (mCallback != null) { 184 mCallback.onSetReport(mHidDevice, reportType, reportId, data); 185 } 186 } catch (RemoteException e) { 187 e.printStackTrace(); 188 } 189 break; 190 } 191 192 case MESSAGE_SET_PROTOCOL: 193 byte protocol = (byte) msg.arg1; 194 195 try { 196 if (mCallback != null) { 197 mCallback.onSetProtocol(mHidDevice, protocol); 198 } 199 } catch (RemoteException e) { 200 e.printStackTrace(); 201 } 202 break; 203 204 case MESSAGE_INTR_DATA: 205 byte reportId = (byte) msg.arg1; 206 byte[] data = ((ByteBuffer) msg.obj).array(); 207 208 try { 209 if (mCallback != null) { 210 mCallback.onInterruptData(mHidDevice, reportId, data); 211 } 212 } catch (RemoteException e) { 213 e.printStackTrace(); 214 } 215 break; 216 217 case MESSAGE_VC_UNPLUG: 218 try { 219 if (mCallback != null) { 220 mCallback.onVirtualCableUnplug(mHidDevice); 221 } 222 } catch (RemoteException e) { 223 e.printStackTrace(); 224 } 225 mHidDevice = null; 226 break; 227 228 case MESSAGE_IMPORTANCE_CHANGE: 229 int importance = msg.arg1; 230 int uid = msg.arg2; 231 if (importance > FOREGROUND_IMPORTANCE_CUTOFF 232 && uid >= Process.FIRST_APPLICATION_UID) { 233 unregisterAppUid(uid); 234 } 235 break; 236 } 237 } 238 } 239 240 private static class BluetoothHidDeviceDeathRecipient implements IBinder.DeathRecipient { 241 private HidDeviceService mService; 242 BluetoothHidDeviceDeathRecipient(HidDeviceService service)243 BluetoothHidDeviceDeathRecipient(HidDeviceService service) { 244 mService = service; 245 } 246 247 @Override binderDied()248 public void binderDied() { 249 Log.w(TAG, "Binder died, need to unregister app :("); 250 mService.unregisterApp(); 251 } 252 cleanup()253 public void cleanup() { 254 mService = null; 255 } 256 } 257 258 private ActivityManager.OnUidImportanceListener mUidImportanceListener = 259 new ActivityManager.OnUidImportanceListener() { 260 @Override 261 public void onUidImportance(final int uid, final int importance) { 262 Message message = mHandler.obtainMessage(MESSAGE_IMPORTANCE_CHANGE); 263 message.arg1 = importance; 264 message.arg2 = uid; 265 mHandler.sendMessage(message); 266 } 267 }; 268 269 @VisibleForTesting 270 static class BluetoothHidDeviceBinder extends IBluetoothHidDevice.Stub 271 implements IProfileServiceBinder { 272 273 private static final String TAG = BluetoothHidDeviceBinder.class.getSimpleName(); 274 275 private HidDeviceService mService; 276 BluetoothHidDeviceBinder(HidDeviceService service)277 BluetoothHidDeviceBinder(HidDeviceService service) { 278 mService = service; 279 } 280 281 @VisibleForTesting getServiceForTesting()282 HidDeviceService getServiceForTesting() { 283 if (mService != null && mService.isAvailable()) { 284 return mService; 285 } 286 return null; 287 } 288 289 @Override cleanup()290 public void cleanup() { 291 mService = null; 292 } 293 getService()294 private HidDeviceService getService() { 295 if (!Utils.checkCaller()) { 296 Log.w(TAG, "HidDevice call not allowed for non-active user"); 297 return null; 298 } 299 300 if (mService != null && mService.isAvailable()) { 301 return mService; 302 } 303 304 return null; 305 } 306 307 @Override registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)308 public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp, 309 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, 310 IBluetoothHidDeviceCallback callback) { 311 if (DBG) { 312 Log.d(TAG, "registerApp()"); 313 } 314 315 HidDeviceService service = getService(); 316 if (service == null) { 317 return false; 318 } 319 320 return service.registerApp(sdp, inQos, outQos, callback); 321 } 322 323 @Override unregisterApp()324 public boolean unregisterApp() { 325 if (DBG) { 326 Log.d(TAG, "unregisterApp()"); 327 } 328 329 HidDeviceService service = getService(); 330 if (service == null) { 331 return false; 332 } 333 334 return service.unregisterApp(); 335 } 336 337 @Override sendReport(BluetoothDevice device, int id, byte[] data)338 public boolean sendReport(BluetoothDevice device, int id, byte[] data) { 339 if (DBG) { 340 Log.d(TAG, "sendReport(): device=" + device + " id=" + id); 341 } 342 343 HidDeviceService service = getService(); 344 if (service == null) { 345 return false; 346 } 347 348 return service.sendReport(device, id, data); 349 } 350 351 @Override replyReport(BluetoothDevice device, byte type, byte id, byte[] data)352 public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { 353 if (DBG) { 354 Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); 355 } 356 357 HidDeviceService service = getService(); 358 if (service == null) { 359 return false; 360 } 361 362 return service.replyReport(device, type, id, data); 363 } 364 365 @Override unplug(BluetoothDevice device)366 public boolean unplug(BluetoothDevice device) { 367 if (DBG) { 368 Log.d(TAG, "unplug(): device=" + device); 369 } 370 371 HidDeviceService service = getService(); 372 if (service == null) { 373 return false; 374 } 375 376 return service.unplug(device); 377 } 378 379 @Override connect(BluetoothDevice device)380 public boolean connect(BluetoothDevice device) { 381 if (DBG) { 382 Log.d(TAG, "connect(): device=" + device); 383 } 384 385 HidDeviceService service = getService(); 386 if (service == null) { 387 return false; 388 } 389 390 return service.connect(device); 391 } 392 393 @Override disconnect(BluetoothDevice device)394 public boolean disconnect(BluetoothDevice device) { 395 if (DBG) { 396 Log.d(TAG, "disconnect(): device=" + device); 397 } 398 399 HidDeviceService service = getService(); 400 if (service == null) { 401 return false; 402 } 403 404 return service.disconnect(device); 405 } 406 407 @Override reportError(BluetoothDevice device, byte error)408 public boolean reportError(BluetoothDevice device, byte error) { 409 if (DBG) { 410 Log.d(TAG, "reportError(): device=" + device + " error=" + error); 411 } 412 413 HidDeviceService service = getService(); 414 if (service == null) { 415 return false; 416 } 417 418 return service.reportError(device, error); 419 } 420 421 @Override getConnectionState(BluetoothDevice device)422 public int getConnectionState(BluetoothDevice device) { 423 if (DBG) { 424 Log.d(TAG, "getConnectionState(): device=" + device); 425 } 426 427 HidDeviceService service = getService(); 428 if (service == null) { 429 return BluetoothHidDevice.STATE_DISCONNECTED; 430 } 431 432 return service.getConnectionState(device); 433 } 434 435 @Override getConnectedDevices()436 public List<BluetoothDevice> getConnectedDevices() { 437 if (DBG) { 438 Log.d(TAG, "getConnectedDevices()"); 439 } 440 441 return getDevicesMatchingConnectionStates(new int[]{BluetoothProfile.STATE_CONNECTED}); 442 } 443 444 @Override getDevicesMatchingConnectionStates(int[] states)445 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 446 if (DBG) { 447 Log.d(TAG, 448 "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states)); 449 } 450 451 HidDeviceService service = getService(); 452 if (service == null) { 453 return new ArrayList<BluetoothDevice>(0); 454 } 455 456 return service.getDevicesMatchingConnectionStates(states); 457 } 458 459 @Override getUserAppName()460 public String getUserAppName() { 461 HidDeviceService service = getService(); 462 if (service == null) { 463 return ""; 464 } 465 return service.getUserAppName(); 466 } 467 } 468 469 @Override initBinder()470 protected IProfileServiceBinder initBinder() { 471 return new BluetoothHidDeviceBinder(this); 472 } 473 checkDevice(BluetoothDevice device)474 private boolean checkDevice(BluetoothDevice device) { 475 if (mHidDevice == null || !mHidDevice.equals(device)) { 476 Log.w(TAG, "Unknown device: " + device); 477 return false; 478 } 479 return true; 480 } 481 checkCallingUid()482 private boolean checkCallingUid() { 483 int callingUid = Binder.getCallingUid(); 484 if (callingUid != mUserUid) { 485 Log.w(TAG, "checkCallingUid(): caller UID doesn't match registered user UID"); 486 return false; 487 } 488 return true; 489 } 490 registerApp(BluetoothHidDeviceAppSdpSettings sdp, BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, IBluetoothHidDeviceCallback callback)491 synchronized boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp, 492 BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, 493 IBluetoothHidDeviceCallback callback) { 494 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 495 if (mUserUid != 0) { 496 Log.w(TAG, "registerApp(): failed because another app is registered"); 497 return false; 498 } 499 500 int callingUid = Binder.getCallingUid(); 501 if (DBG) { 502 Log.d(TAG, "registerApp(): calling uid=" + callingUid); 503 } 504 if (callingUid >= Process.FIRST_APPLICATION_UID 505 && mActivityManager.getUidImportance(callingUid) > FOREGROUND_IMPORTANCE_CUTOFF) { 506 Log.w(TAG, "registerApp(): failed because the app is not foreground"); 507 return false; 508 } 509 mUserUid = callingUid; 510 mCallback = callback; 511 512 return mHidDeviceNativeInterface.registerApp( 513 sdp.getName(), 514 sdp.getDescription(), 515 sdp.getProvider(), 516 sdp.getSubclass(), 517 sdp.getDescriptors(), 518 inQos == null 519 ? null 520 : new int[] { 521 inQos.getServiceType(), 522 inQos.getTokenRate(), 523 inQos.getTokenBucketSize(), 524 inQos.getPeakBandwidth(), 525 inQos.getLatency(), 526 inQos.getDelayVariation() 527 }, 528 outQos == null 529 ? null 530 : new int[] { 531 outQos.getServiceType(), 532 outQos.getTokenRate(), 533 outQos.getTokenBucketSize(), 534 outQos.getPeakBandwidth(), 535 outQos.getLatency(), 536 outQos.getDelayVariation() 537 }); 538 } 539 unregisterApp()540 synchronized boolean unregisterApp() { 541 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 542 if (DBG) { 543 Log.d(TAG, "unregisterApp()"); 544 } 545 546 int callingUid = Binder.getCallingUid(); 547 return unregisterAppUid(callingUid); 548 } 549 unregisterAppUid(int uid)550 private synchronized boolean unregisterAppUid(int uid) { 551 if (DBG) { 552 Log.d(TAG, "unregisterAppUid(): uid=" + uid); 553 } 554 555 if (mUserUid != 0 && (uid == mUserUid || uid < Process.FIRST_APPLICATION_UID)) { 556 mUserUid = 0; 557 return mHidDeviceNativeInterface.unregisterApp(); 558 } 559 if (DBG) { 560 Log.d(TAG, "unregisterAppUid(): caller UID doesn't match user UID"); 561 } 562 return false; 563 } 564 sendReport(BluetoothDevice device, int id, byte[] data)565 synchronized boolean sendReport(BluetoothDevice device, int id, byte[] data) { 566 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 567 if (DBG) { 568 Log.d(TAG, "sendReport(): device=" + device + " id=" + id); 569 } 570 571 return checkDevice(device) && checkCallingUid() 572 && mHidDeviceNativeInterface.sendReport(id, data); 573 } 574 replyReport(BluetoothDevice device, byte type, byte id, byte[] data)575 synchronized boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { 576 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 577 if (DBG) { 578 Log.d(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); 579 } 580 581 return checkDevice(device) && checkCallingUid() 582 && mHidDeviceNativeInterface.replyReport(type, id, data); 583 } 584 unplug(BluetoothDevice device)585 synchronized boolean unplug(BluetoothDevice device) { 586 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 587 if (DBG) { 588 Log.d(TAG, "unplug(): device=" + device); 589 } 590 591 return checkDevice(device) && checkCallingUid() 592 && mHidDeviceNativeInterface.unplug(); 593 } 594 connect(BluetoothDevice device)595 synchronized boolean connect(BluetoothDevice device) { 596 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 597 if (DBG) { 598 Log.d(TAG, "connect(): device=" + device); 599 } 600 601 return checkCallingUid() && mHidDeviceNativeInterface.connect(device); 602 } 603 disconnect(BluetoothDevice device)604 synchronized boolean disconnect(BluetoothDevice device) { 605 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 606 if (DBG) { 607 Log.d(TAG, "disconnect(): device=" + device); 608 } 609 610 int callingUid = Binder.getCallingUid(); 611 if (callingUid != mUserUid && callingUid >= Process.FIRST_APPLICATION_UID) { 612 Log.w(TAG, "disconnect(): caller UID doesn't match user UID"); 613 return false; 614 } 615 return checkDevice(device) && mHidDeviceNativeInterface.disconnect(); 616 } 617 reportError(BluetoothDevice device, byte error)618 synchronized boolean reportError(BluetoothDevice device, byte error) { 619 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); 620 if (DBG) { 621 Log.d(TAG, "reportError(): device=" + device + " error=" + error); 622 } 623 624 return checkDevice(device) && checkCallingUid() 625 && mHidDeviceNativeInterface.reportError(error); 626 } 627 getUserAppName()628 synchronized String getUserAppName() { 629 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 630 if (mUserUid < Process.FIRST_APPLICATION_UID) { 631 return ""; 632 } 633 String appName = getPackageManager().getNameForUid(mUserUid); 634 return appName != null ? appName : ""; 635 } 636 637 @Override start()638 protected boolean start() { 639 if (DBG) { 640 Log.d(TAG, "start()"); 641 } 642 643 mHandler = new HidDeviceServiceHandler(); 644 mHidDeviceNativeInterface = HidDeviceNativeInterface.getInstance(); 645 mHidDeviceNativeInterface.init(); 646 mNativeAvailable = true; 647 mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 648 mActivityManager.addOnUidImportanceListener(mUidImportanceListener, 649 FOREGROUND_IMPORTANCE_CUTOFF); 650 setHidDeviceService(this); 651 return true; 652 } 653 654 @Override stop()655 protected boolean stop() { 656 if (DBG) { 657 Log.d(TAG, "stop()"); 658 } 659 660 if (sHidDeviceService == null) { 661 Log.w(TAG, "stop() called before start()"); 662 return true; 663 } 664 665 setHidDeviceService(null); 666 if (mNativeAvailable) { 667 mHidDeviceNativeInterface.cleanup(); 668 mNativeAvailable = false; 669 } 670 mActivityManager.removeOnUidImportanceListener(mUidImportanceListener); 671 return true; 672 } 673 674 @Override onUnbind(Intent intent)675 public boolean onUnbind(Intent intent) { 676 Log.d(TAG, "Need to unregister app"); 677 unregisterApp(); 678 return super.onUnbind(intent); 679 } 680 681 /** 682 * Get the HID Device Service instance 683 * @return HID Device Service instance 684 */ getHidDeviceService()685 public static synchronized HidDeviceService getHidDeviceService() { 686 if (sHidDeviceService == null) { 687 Log.d(TAG, "getHidDeviceService(): service is NULL"); 688 return null; 689 } 690 if (!sHidDeviceService.isAvailable()) { 691 Log.d(TAG, "getHidDeviceService(): service is not available"); 692 return null; 693 } 694 return sHidDeviceService; 695 } 696 setHidDeviceService(HidDeviceService instance)697 private static synchronized void setHidDeviceService(HidDeviceService instance) { 698 if (DBG) { 699 Log.d(TAG, "setHidDeviceService(): set to: " + instance); 700 } 701 sHidDeviceService = instance; 702 } 703 getConnectionState(BluetoothDevice device)704 int getConnectionState(BluetoothDevice device) { 705 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 706 if (mHidDevice != null && mHidDevice.equals(device)) { 707 return mHidDeviceState; 708 } 709 return BluetoothHidDevice.STATE_DISCONNECTED; 710 } 711 getDevicesMatchingConnectionStates(int[] states)712 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 713 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 714 List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); 715 716 if (mHidDevice != null) { 717 for (int state : states) { 718 if (state == mHidDeviceState) { 719 inputDevices.add(mHidDevice); 720 break; 721 } 722 } 723 } 724 return inputDevices; 725 } 726 onApplicationStateChangedFromNative(BluetoothDevice device, boolean registered)727 synchronized void onApplicationStateChangedFromNative(BluetoothDevice device, 728 boolean registered) { 729 if (DBG) { 730 Log.d(TAG, "onApplicationStateChanged(): registered=" + registered); 731 } 732 733 Message msg = mHandler.obtainMessage(MESSAGE_APPLICATION_STATE_CHANGED); 734 msg.obj = device; 735 msg.arg1 = registered ? 1 : 0; 736 mHandler.sendMessage(msg); 737 } 738 onConnectStateChangedFromNative(BluetoothDevice device, int state)739 synchronized void onConnectStateChangedFromNative(BluetoothDevice device, int state) { 740 if (DBG) { 741 Log.d(TAG, "onConnectStateChanged(): device=" 742 + device + " state=" + state); 743 } 744 745 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 746 msg.obj = device; 747 msg.arg1 = state; 748 mHandler.sendMessage(msg); 749 } 750 onGetReportFromNative(byte type, byte id, short bufferSize)751 synchronized void onGetReportFromNative(byte type, byte id, short bufferSize) { 752 if (DBG) { 753 Log.d(TAG, "onGetReport(): type=" + type + " id=" + id + " bufferSize=" + bufferSize); 754 } 755 756 Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT); 757 msg.obj = bufferSize > 0 ? new Integer(bufferSize) : null; 758 msg.arg1 = type; 759 msg.arg2 = id; 760 mHandler.sendMessage(msg); 761 } 762 onSetReportFromNative(byte reportType, byte reportId, byte[] data)763 synchronized void onSetReportFromNative(byte reportType, byte reportId, byte[] data) { 764 if (DBG) { 765 Log.d(TAG, "onSetReport(): reportType=" + reportType + " reportId=" + reportId); 766 } 767 768 ByteBuffer bb = ByteBuffer.wrap(data); 769 770 Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT); 771 msg.arg1 = reportType; 772 msg.arg2 = reportId; 773 msg.obj = bb; 774 mHandler.sendMessage(msg); 775 } 776 onSetProtocolFromNative(byte protocol)777 synchronized void onSetProtocolFromNative(byte protocol) { 778 if (DBG) { 779 Log.d(TAG, "onSetProtocol(): protocol=" + protocol); 780 } 781 782 Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL); 783 msg.arg1 = protocol; 784 mHandler.sendMessage(msg); 785 } 786 onInterruptDataFromNative(byte reportId, byte[] data)787 synchronized void onInterruptDataFromNative(byte reportId, byte[] data) { 788 if (DBG) { 789 Log.d(TAG, "onInterruptData(): reportId=" + reportId); 790 } 791 792 ByteBuffer bb = ByteBuffer.wrap(data); 793 794 Message msg = mHandler.obtainMessage(MESSAGE_INTR_DATA); 795 msg.arg1 = reportId; 796 msg.obj = bb; 797 mHandler.sendMessage(msg); 798 } 799 onVirtualCableUnplugFromNative()800 synchronized void onVirtualCableUnplugFromNative() { 801 if (DBG) { 802 Log.d(TAG, "onVirtualCableUnplug()"); 803 } 804 805 Message msg = mHandler.obtainMessage(MESSAGE_VC_UNPLUG); 806 mHandler.sendMessage(msg); 807 } 808 setAndBroadcastConnectionState(BluetoothDevice device, int newState)809 private void setAndBroadcastConnectionState(BluetoothDevice device, int newState) { 810 if (DBG) { 811 Log.d(TAG, "setAndBroadcastConnectionState(): device=" + device.getAddress() 812 + " oldState=" + mHidDeviceState + " newState=" + newState); 813 } 814 815 if (mHidDevice != null && !mHidDevice.equals(device)) { 816 Log.w(TAG, "Connection state changed for unknown device, ignoring"); 817 return; 818 } 819 820 int prevState = mHidDeviceState; 821 mHidDeviceState = newState; 822 823 if (prevState == newState) { 824 Log.w(TAG, "Connection state is unchanged, ignoring"); 825 return; 826 } 827 828 if (newState == BluetoothProfile.STATE_CONNECTED) { 829 MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HID_DEVICE); 830 } 831 832 Intent intent = new Intent(BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED); 833 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 834 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 835 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 836 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 837 sendBroadcast(intent, BLUETOOTH_PERM); 838 } 839 convertHalState(int halState)840 private static int convertHalState(int halState) { 841 switch (halState) { 842 case HAL_CONN_STATE_CONNECTED: 843 return BluetoothProfile.STATE_CONNECTED; 844 case HAL_CONN_STATE_CONNECTING: 845 return BluetoothProfile.STATE_CONNECTING; 846 case HAL_CONN_STATE_DISCONNECTED: 847 return BluetoothProfile.STATE_DISCONNECTED; 848 case HAL_CONN_STATE_DISCONNECTING: 849 return BluetoothProfile.STATE_DISCONNECTING; 850 default: 851 return BluetoothProfile.STATE_DISCONNECTED; 852 } 853 } 854 855 static final int HAL_CONN_STATE_CONNECTED = 0; 856 static final int HAL_CONN_STATE_CONNECTING = 1; 857 static final int HAL_CONN_STATE_DISCONNECTED = 2; 858 static final int HAL_CONN_STATE_DISCONNECTING = 3; 859 } 860