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