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