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