HidService.java revision eb7b90f5b93db1230a5b64caa3d8d05a642e33a6
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.bluetooth.hid; 18 19import android.bluetooth.BluetoothDevice; 20import android.bluetooth.BluetoothInputDevice; 21import android.bluetooth.BluetoothProfile; 22import android.bluetooth.IBluetoothInputDevice; 23import android.content.Intent; 24import android.os.Bundle; 25import android.os.Handler; 26import android.os.Message; 27import android.provider.Settings; 28import android.util.Log; 29 30import com.android.bluetooth.btservice.AdapterService; 31import com.android.bluetooth.btservice.ProfileService; 32import com.android.bluetooth.Utils; 33 34import java.util.ArrayList; 35import java.util.Collections; 36import java.util.HashMap; 37import java.util.List; 38import java.util.Map; 39 40/** 41 * Provides Bluetooth Hid Host profile, as a service in 42 * the Bluetooth application. 43 * @hide 44 */ 45public class HidService extends ProfileService { 46 private static final boolean DBG = true; 47 private static final String TAG = "HidService"; 48 49 private Map<BluetoothDevice, Integer> mInputDevices; 50 private boolean mNativeAvailable; 51 private static HidService sHidService; 52 private BluetoothDevice mTargetDevice = null; 53 54 private static final int MESSAGE_CONNECT = 1; 55 private static final int MESSAGE_DISCONNECT = 2; 56 private static final int MESSAGE_CONNECT_STATE_CHANGED = 3; 57 private static final int MESSAGE_GET_PROTOCOL_MODE = 4; 58 private static final int MESSAGE_VIRTUAL_UNPLUG = 5; 59 private static final int MESSAGE_ON_GET_PROTOCOL_MODE = 6; 60 private static final int MESSAGE_SET_PROTOCOL_MODE = 7; 61 private static final int MESSAGE_GET_REPORT = 8; 62 private static final int MESSAGE_ON_GET_REPORT = 9; 63 private static final int MESSAGE_SET_REPORT = 10; 64 private static final int MESSAGE_SEND_DATA = 11; 65 private static final int MESSAGE_ON_VIRTUAL_UNPLUG = 12; 66 private static final int MESSAGE_ON_HANDSHAKE = 13; 67 68 static { 69 classInitNative(); 70 } 71 72 public String getName() { 73 return TAG; 74 } 75 76 public IProfileServiceBinder initBinder() { 77 return new BluetoothInputDeviceBinder(this); 78 } 79 80 protected boolean start() { 81 mInputDevices = Collections.synchronizedMap(new HashMap<BluetoothDevice, Integer>()); 82 initializeNative(); 83 mNativeAvailable=true; 84 setHidService(this); 85 return true; 86 } 87 88 protected boolean stop() { 89 if (DBG) log("Stopping Bluetooth HidService"); 90 return true; 91 } 92 93 protected boolean cleanup() { 94 if (mNativeAvailable) { 95 cleanupNative(); 96 mNativeAvailable=false; 97 } 98 99 if(mInputDevices != null) { 100 mInputDevices.clear(); 101 } 102 clearHidService(); 103 return true; 104 } 105 106 public static synchronized HidService getHidService(){ 107 if (sHidService != null && sHidService.isAvailable()) { 108 if (DBG) Log.d(TAG, "getHidService(): returning " + sHidService); 109 return sHidService; 110 } 111 if (DBG) { 112 if (sHidService == null) { 113 Log.d(TAG, "getHidService(): service is NULL"); 114 } else if (!(sHidService.isAvailable())) { 115 Log.d(TAG,"getHidService(): service is not available"); 116 } 117 } 118 return null; 119 } 120 121 private static synchronized void setHidService(HidService instance) { 122 if (instance != null && instance.isAvailable()) { 123 if (DBG) Log.d(TAG, "setHidService(): set to: " + sHidService); 124 sHidService = instance; 125 } else { 126 if (DBG) { 127 if (sHidService == null) { 128 Log.d(TAG, "setHidService(): service not available"); 129 } else if (!sHidService.isAvailable()) { 130 Log.d(TAG,"setHidService(): service is cleaning up"); 131 } 132 } 133 } 134 } 135 136 private static synchronized void clearHidService() { 137 sHidService = null; 138 } 139 140 141 private final Handler mHandler = new Handler() { 142 143 @Override 144 public void handleMessage(Message msg) { 145 switch (msg.what) { 146 case MESSAGE_CONNECT: 147 { 148 BluetoothDevice device = (BluetoothDevice) msg.obj; 149 if (!connectHidNative(Utils.getByteAddress(device)) ) { 150 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); 151 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 152 break; 153 } 154 mTargetDevice = device; 155 } 156 break; 157 case MESSAGE_DISCONNECT: 158 { 159 BluetoothDevice device = (BluetoothDevice) msg.obj; 160 if (!disconnectHidNative(Utils.getByteAddress(device)) ) { 161 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); 162 broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); 163 break; 164 } 165 } 166 break; 167 case MESSAGE_CONNECT_STATE_CHANGED: 168 { 169 BluetoothDevice device = getDevice((byte[]) msg.obj); 170 int halState = msg.arg1; 171 Integer prevStateInteger = mInputDevices.get(device); 172 int prevState = (prevStateInteger == null) ? 173 BluetoothInputDevice.STATE_DISCONNECTED :prevStateInteger; 174 if(DBG) Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:"+ 175 convertHalState(halState)+", prevState:"+prevState); 176 if(halState == CONN_STATE_CONNECTED && 177 prevState == BluetoothInputDevice.STATE_DISCONNECTED && 178 (!okToConnect(device))) { 179 if (DBG) Log.d(TAG,"Incoming HID connection rejected"); 180 disconnectHidNative(Utils.getByteAddress(device)); 181 } else { 182 broadcastConnectionState(device, convertHalState(halState)); 183 } 184 if (halState == CONN_STATE_CONNECTED && 185 (mTargetDevice != null && mTargetDevice.equals(device))) { 186 mTargetDevice = null; 187 // local device originated connection to hid device, move out 188 // of quiet mode 189 AdapterService adapterService = AdapterService.getAdapterService(); 190 adapterService.enable(false); 191 } 192 } 193 break; 194 case MESSAGE_GET_PROTOCOL_MODE: 195 { 196 BluetoothDevice device = (BluetoothDevice) msg.obj; 197 if(!getProtocolModeNative(Utils.getByteAddress(device)) ) { 198 Log.e(TAG, "Error: get protocol mode native returns false"); 199 } 200 } 201 break; 202 203 case MESSAGE_ON_GET_PROTOCOL_MODE: 204 { 205 BluetoothDevice device = getDevice((byte[]) msg.obj); 206 int protocolMode = msg.arg1; 207 broadcastProtocolMode(device, protocolMode); 208 } 209 break; 210 case MESSAGE_VIRTUAL_UNPLUG: 211 { 212 BluetoothDevice device = (BluetoothDevice) msg.obj; 213 if(!virtualUnPlugNative(Utils.getByteAddress(device))) { 214 Log.e(TAG, "Error: virtual unplug native returns false"); 215 } 216 } 217 break; 218 case MESSAGE_SET_PROTOCOL_MODE: 219 { 220 BluetoothDevice device = (BluetoothDevice) msg.obj; 221 byte protocolMode = (byte) msg.arg1; 222 log("sending set protocol mode(" + protocolMode + ")"); 223 if(!setProtocolModeNative(Utils.getByteAddress(device), protocolMode)) { 224 Log.e(TAG, "Error: set protocol mode native returns false"); 225 } 226 } 227 break; 228 case MESSAGE_GET_REPORT: 229 { 230 BluetoothDevice device = (BluetoothDevice) msg.obj; 231 Bundle data = msg.getData(); 232 byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE); 233 byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID); 234 int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE); 235 if(!getReportNative(Utils.getByteAddress(device), reportType, reportId, bufferSize)) { 236 Log.e(TAG, "Error: get report native returns false"); 237 } 238 } 239 break; 240 case MESSAGE_ON_GET_REPORT: 241 { 242 BluetoothDevice device = getDevice((byte[])msg.obj); 243 Bundle data = msg.getData(); 244 byte[] report = data.getByteArray(BluetoothInputDevice.EXTRA_REPORT); 245 int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE); 246 broadcastReport(device, report, bufferSize); 247 } 248 break; 249 case MESSAGE_ON_HANDSHAKE: 250 { 251 BluetoothDevice device = getDevice((byte[])msg.obj); 252 int status = msg.arg1; 253 broadcastHandshake(device, status); 254 } 255 break; 256 case MESSAGE_SET_REPORT: 257 { 258 BluetoothDevice device = (BluetoothDevice) msg.obj; 259 Bundle data = msg.getData(); 260 byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE); 261 String report = data.getString(BluetoothInputDevice.EXTRA_REPORT); 262 if(!setReportNative(Utils.getByteAddress(device), reportType, report)) { 263 Log.e(TAG, "Error: set report native returns false"); 264 } 265 } 266 break; 267 case MESSAGE_SEND_DATA: 268 { 269 BluetoothDevice device = (BluetoothDevice) msg.obj; 270 Bundle data = msg.getData(); 271 String report = data.getString(BluetoothInputDevice.EXTRA_REPORT); 272 if(!sendDataNative(Utils.getByteAddress(device), report)) { 273 Log.e(TAG, "Error: send data native returns false"); 274 } 275 } 276 break; 277 case MESSAGE_ON_VIRTUAL_UNPLUG: 278 { 279 BluetoothDevice device = getDevice((byte[]) msg.obj); 280 int status = msg.arg1; 281 broadcastVirtualUnplugStatus(device, status); 282 } 283 break; 284 } 285 } 286 }; 287 288 /** 289 * Handlers for incoming service calls 290 */ 291 private static class BluetoothInputDeviceBinder extends IBluetoothInputDevice.Stub implements IProfileServiceBinder{ 292 private HidService mService; 293 public BluetoothInputDeviceBinder(HidService svc) { 294 mService = svc; 295 } 296 297 public boolean cleanup() { 298 mService = null; 299 return true; 300 } 301 302 private HidService getService() { 303 if (!Utils.checkCaller()) { 304 Log.w(TAG,"InputDevice call not allowed for non-active user"); 305 return null; 306 } 307 308 if (mService != null && mService.isAvailable()) { 309 return mService; 310 } 311 return null; 312 } 313 314 public boolean connect(BluetoothDevice device) { 315 HidService service = getService(); 316 if (service == null) return false; 317 return service.connect(device); 318 } 319 320 public boolean disconnect(BluetoothDevice device) { 321 HidService service = getService(); 322 if (service == null) return false; 323 return service.disconnect(device); 324 } 325 326 public int getConnectionState(BluetoothDevice device) { 327 HidService service = getService(); 328 if (service == null) return BluetoothInputDevice.STATE_DISCONNECTED; 329 return service.getConnectionState(device); 330 } 331 332 public List<BluetoothDevice> getConnectedDevices() { 333 return getDevicesMatchingConnectionStates( 334 new int[] {BluetoothProfile.STATE_CONNECTED}); 335 } 336 337 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 338 HidService service = getService(); 339 if (service == null) return new ArrayList<BluetoothDevice>(0); 340 return service.getDevicesMatchingConnectionStates(states); 341 } 342 343 public boolean setPriority(BluetoothDevice device, int priority) { 344 HidService service = getService(); 345 if (service == null) return false; 346 return service.setPriority(device, priority); 347 } 348 349 public int getPriority(BluetoothDevice device) { 350 HidService service = getService(); 351 if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; 352 return service.getPriority(device); 353 } 354 355 /* The following APIs regarding test app for compliance */ 356 public boolean getProtocolMode(BluetoothDevice device) { 357 HidService service = getService(); 358 if (service == null) return false; 359 return service.getProtocolMode(device); 360 } 361 362 public boolean virtualUnplug(BluetoothDevice device) { 363 HidService service = getService(); 364 if (service == null) return false; 365 return service.virtualUnplug(device); 366 } 367 368 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) { 369 HidService service = getService(); 370 if (service == null) return false; 371 return service.setProtocolMode(device, protocolMode); 372 } 373 374 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) { 375 HidService service = getService(); 376 if (service == null) return false; 377 return service.getReport(device, reportType, reportId, bufferSize) ; 378 } 379 380 public boolean setReport(BluetoothDevice device, byte reportType, String report) { 381 HidService service = getService(); 382 if (service == null) return false; 383 return service.setReport(device, reportType, report); 384 } 385 386 public boolean sendData(BluetoothDevice device, String report) { 387 HidService service = getService(); 388 if (service == null) return false; 389 return service.sendData(device, report); 390 } 391 }; 392 393 //APIs 394 boolean connect(BluetoothDevice device) { 395 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 396 if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) { 397 Log.e(TAG, "Hid Device not disconnected: " + device); 398 return false; 399 } 400 if (getPriority(device) == BluetoothInputDevice.PRIORITY_OFF) { 401 Log.e(TAG, "Hid Device PRIORITY_OFF: " + device); 402 return false; 403 } 404 405 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device); 406 mHandler.sendMessage(msg); 407 return true; 408 } 409 410 boolean disconnect(BluetoothDevice device) { 411 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 412 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device); 413 mHandler.sendMessage(msg); 414 return true; 415 } 416 417 int getConnectionState(BluetoothDevice device) { 418 if (mInputDevices.get(device) == null) { 419 return BluetoothInputDevice.STATE_DISCONNECTED; 420 } 421 return mInputDevices.get(device); 422 } 423 424 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 425 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 426 List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>(); 427 428 for (BluetoothDevice device: mInputDevices.keySet()) { 429 int inputDeviceState = getConnectionState(device); 430 for (int state : states) { 431 if (state == inputDeviceState) { 432 inputDevices.add(device); 433 break; 434 } 435 } 436 } 437 return inputDevices; 438 } 439 440 public boolean setPriority(BluetoothDevice device, int priority) { 441 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 442 "Need BLUETOOTH_ADMIN permission"); 443 Settings.Global.putInt(getContentResolver(), 444 Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()), 445 priority); 446 if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority); 447 return true; 448 } 449 450 public int getPriority(BluetoothDevice device) { 451 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 452 "Need BLUETOOTH_ADMIN permission"); 453 int priority = Settings.Global.getInt(getContentResolver(), 454 Settings.Global.getBluetoothInputDevicePriorityKey(device.getAddress()), 455 BluetoothProfile.PRIORITY_UNDEFINED); 456 return priority; 457 } 458 459 /* The following APIs regarding test app for compliance */ 460 boolean getProtocolMode(BluetoothDevice device) { 461 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 462 "Need BLUETOOTH_ADMIN permission"); 463 int state = this.getConnectionState(device); 464 if (state != BluetoothInputDevice.STATE_CONNECTED) { 465 return false; 466 } 467 Message msg = mHandler.obtainMessage(MESSAGE_GET_PROTOCOL_MODE,device); 468 mHandler.sendMessage(msg); 469 return true; 470 /* String objectPath = getObjectPathFromAddress(device.getAddress()); 471 return getProtocolModeInputDeviceNative(objectPath);*/ 472 } 473 474 boolean virtualUnplug(BluetoothDevice device) { 475 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 476 "Need BLUETOOTH_ADMIN permission"); 477 int state = this.getConnectionState(device); 478 if (state != BluetoothInputDevice.STATE_CONNECTED) { 479 return false; 480 } 481 Message msg = mHandler.obtainMessage(MESSAGE_VIRTUAL_UNPLUG,device); 482 mHandler.sendMessage(msg); 483 return true; 484 } 485 486 boolean setProtocolMode(BluetoothDevice device, int protocolMode) { 487 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 488 "Need BLUETOOTH_ADMIN permission"); 489 int state = this.getConnectionState(device); 490 if (state != BluetoothInputDevice.STATE_CONNECTED) { 491 return false; 492 } 493 Message msg = mHandler.obtainMessage(MESSAGE_SET_PROTOCOL_MODE); 494 msg.obj = device; 495 msg.arg1 = protocolMode; 496 mHandler.sendMessage(msg); 497 return true ; 498 } 499 500 boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) { 501 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 502 "Need BLUETOOTH_ADMIN permission"); 503 int state = this.getConnectionState(device); 504 if (state != BluetoothInputDevice.STATE_CONNECTED) { 505 return false; 506 } 507 Message msg = mHandler.obtainMessage(MESSAGE_GET_REPORT); 508 msg.obj = device; 509 Bundle data = new Bundle(); 510 data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType); 511 data.putByte(BluetoothInputDevice.EXTRA_REPORT_ID, reportId); 512 data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, bufferSize); 513 msg.setData(data); 514 mHandler.sendMessage(msg); 515 return true ; 516 } 517 518 boolean setReport(BluetoothDevice device, byte reportType, String report) { 519 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 520 "Need BLUETOOTH_ADMIN permission"); 521 int state = this.getConnectionState(device); 522 if (state != BluetoothInputDevice.STATE_CONNECTED) { 523 return false; 524 } 525 Message msg = mHandler.obtainMessage(MESSAGE_SET_REPORT); 526 msg.obj = device; 527 Bundle data = new Bundle(); 528 data.putByte(BluetoothInputDevice.EXTRA_REPORT_TYPE, reportType); 529 data.putString(BluetoothInputDevice.EXTRA_REPORT, report); 530 msg.setData(data); 531 mHandler.sendMessage(msg); 532 return true ; 533 534 } 535 536 boolean sendData(BluetoothDevice device, String report) { 537 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 538 "Need BLUETOOTH_ADMIN permission"); 539 int state = this.getConnectionState(device); 540 if (state != BluetoothInputDevice.STATE_CONNECTED) { 541 return false; 542 } 543 544 return sendDataNative(Utils.getByteAddress(device), report); 545 } 546 547 private void onGetProtocolMode(byte[] address, int mode) { 548 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_PROTOCOL_MODE); 549 msg.obj = address; 550 msg.arg1 = mode; 551 mHandler.sendMessage(msg); 552 } 553 554 private void onGetReport(byte[] address, byte[] report, int rpt_size) { 555 Message msg = mHandler.obtainMessage(MESSAGE_ON_GET_REPORT); 556 msg.obj = address; 557 Bundle data = new Bundle(); 558 data.putByteArray(BluetoothInputDevice.EXTRA_REPORT, report); 559 data.putInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size); 560 msg.setData(data); 561 mHandler.sendMessage(msg); 562 } 563 564 private void onHandshake(byte[] address, int status) { 565 Message msg = mHandler.obtainMessage(MESSAGE_ON_HANDSHAKE); 566 msg.obj = address; 567 msg.arg1 = status; 568 mHandler.sendMessage(msg); 569 } 570 571 private void onVirtualUnplug(byte[] address, int status) { 572 Message msg = mHandler.obtainMessage(MESSAGE_ON_VIRTUAL_UNPLUG); 573 msg.obj = address; 574 msg.arg1 = status; 575 mHandler.sendMessage(msg); 576 } 577 578 private void onConnectStateChanged(byte[] address, int state) { 579 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 580 msg.obj = address; 581 msg.arg1 = state; 582 mHandler.sendMessage(msg); 583 } 584 585 // This method does not check for error conditon (newState == prevState) 586 private void broadcastConnectionState(BluetoothDevice device, int newState) { 587 Integer prevStateInteger = mInputDevices.get(device); 588 int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED : 589 prevStateInteger; 590 if (prevState == newState) { 591 Log.w(TAG, "no state change: " + newState); 592 return; 593 } 594 mInputDevices.put(device, newState); 595 596 /* Notifying the connection state change of the profile before sending the intent for 597 connection state change, as it was causing a race condition, with the UI not being 598 updated with the correct connection state. */ 599 log("Connection state " + device + ": " + prevState + "->" + newState); 600 notifyProfileConnectionStateChanged(device, BluetoothProfile.INPUT_DEVICE, 601 newState, prevState); 602 Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); 603 intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); 604 intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); 605 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 606 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 607 sendBroadcast(intent, BLUETOOTH_PERM); 608 } 609 610 private void broadcastHandshake(BluetoothDevice device, int status) { 611 Intent intent = new Intent(BluetoothInputDevice.ACTION_HANDSHAKE); 612 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 613 intent.putExtra(BluetoothInputDevice.EXTRA_STATUS, status); 614 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 615 sendBroadcast(intent, BLUETOOTH_PERM); 616 } 617 618 private void broadcastProtocolMode(BluetoothDevice device, int protocolMode) { 619 Intent intent = new Intent(BluetoothInputDevice.ACTION_PROTOCOL_MODE_CHANGED); 620 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 621 intent.putExtra(BluetoothInputDevice.EXTRA_PROTOCOL_MODE, protocolMode); 622 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 623 sendBroadcast(intent, BLUETOOTH_PERM); 624 if (DBG) log("Protocol Mode (" + device + "): " + protocolMode); 625 } 626 627 private void broadcastReport(BluetoothDevice device, byte[] report, int rpt_size) { 628 Intent intent = new Intent(BluetoothInputDevice.ACTION_REPORT); 629 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 630 intent.putExtra(BluetoothInputDevice.EXTRA_REPORT, report); 631 intent.putExtra(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size); 632 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 633 sendBroadcast(intent, BLUETOOTH_PERM); 634 } 635 636 private void broadcastVirtualUnplugStatus(BluetoothDevice device, int status) { 637 Intent intent = new Intent(BluetoothInputDevice.ACTION_VIRTUAL_UNPLUG_STATUS); 638 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 639 intent.putExtra(BluetoothInputDevice.EXTRA_VIRTUAL_UNPLUG_STATUS, status); 640 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 641 sendBroadcast(intent, BLUETOOTH_PERM); 642 } 643 644 private boolean okToConnect(BluetoothDevice device) { 645 AdapterService adapterService = AdapterService.getAdapterService(); 646 //check if it is inbound connection in Quiet mode, priority and Bond status 647 //to decide if its ok to allow this connection 648 if((adapterService == null)|| 649 ((adapterService.isQuietModeEnabled()) &&(mTargetDevice == null)) || 650 (BluetoothProfile.PRIORITY_OFF == getPriority(device)) || 651 (device.getBondState() == BluetoothDevice.BOND_NONE)) 652 return false; 653 654 return true; 655 } 656 private static int convertHalState(int halState) { 657 switch (halState) { 658 case CONN_STATE_CONNECTED: 659 return BluetoothProfile.STATE_CONNECTED; 660 case CONN_STATE_CONNECTING: 661 return BluetoothProfile.STATE_CONNECTING; 662 case CONN_STATE_DISCONNECTED: 663 return BluetoothProfile.STATE_DISCONNECTED; 664 case CONN_STATE_DISCONNECTING: 665 return BluetoothProfile.STATE_DISCONNECTING; 666 default: 667 Log.e(TAG, "bad hid connection state: " + halState); 668 return BluetoothProfile.STATE_DISCONNECTED; 669 } 670 } 671 672 @Override 673 public void dump(StringBuilder sb) { 674 super.dump(sb); 675 println(sb, "mTargetDevice: " + mTargetDevice); 676 println(sb, "mInputDevices:"); 677 for (BluetoothDevice device : mInputDevices.keySet()) { 678 println(sb, " " + device + " : " + mInputDevices.get(device)); 679 } 680 } 681 682 // Constants matching Hal header file bt_hh.h 683 // bthh_connection_state_t 684 private final static int CONN_STATE_CONNECTED = 0; 685 private final static int CONN_STATE_CONNECTING = 1; 686 private final static int CONN_STATE_DISCONNECTED = 2; 687 private final static int CONN_STATE_DISCONNECTING = 3; 688 689 private native static void classInitNative(); 690 private native void initializeNative(); 691 private native void cleanupNative(); 692 private native boolean connectHidNative(byte[] btAddress); 693 private native boolean disconnectHidNative(byte[] btAddress); 694 private native boolean getProtocolModeNative(byte[] btAddress); 695 private native boolean virtualUnPlugNative(byte[] btAddress); 696 private native boolean setProtocolModeNative(byte[] btAddress, byte protocolMode); 697 private native boolean getReportNative(byte[]btAddress, byte reportType, byte reportId, int bufferSize); 698 private native boolean setReportNative(byte[] btAddress, byte reportType, String report); 699 private native boolean sendDataNative(byte[] btAddress, String report); 700} 701