Android下自己开发APP实现HID的连接

转载请标明出处:http://blog.csdn.net/lansefeiyang08/article/details/76609900

从15年6月到现在已经两年没有写过博客了,看了一下自己有将近15万的访问量,觉得自己以前写过的东西,以前做过的东西对大家还是很有帮助的。

所以后面我打算继续写一些技术博客,来帮助大家解决一些实际开发中遇到的问题。

今天我们就来讲讲蓝牙HID如何自己写个APP就可以实现和系统设置一样的连接控制功能。

做过系统蓝牙的人,对于HFP、HID和BLE应该会比较熟悉,HFP和HID在Settings里的连接实现也可能有一些了解,但是如果某些功能需要在自己APP来实现HFP或者HID设备的连接和断开,有些人可能就会比较纠结了。

为什么会纠结呢?

因为自己HID的接口没有,找不到HID的类呀。

那么现在我就来告诉大家一个小技巧,来实现以前只有在系统源码才能完成的事情(此方法通用于其他类似情况)。

如果以前想开发Android Bluetooth HID的人,都知道自己开发APP会找不到一个BluetoothInputDevice的类,所以无法获得BluetoothHID的相关信息,那么我们就要解决第一个问题,如何先找到这个类。

在Android系统开发中,会生成很多的中间静态jar,这些jar包很多人不关心也不会使用到,但是今天我们就会使用到这里的东西。

首先你需要有一套Android源码,编译成功后到out/target/common/obj/JAVA_LIBRARIES/路径下,我们要用的包就是在这个里面,找到framework_intermediates这个文件夹,你会发现在文件夹里有一个classes.jar ,恭喜你,你已经找到你要用的最关键的一个东西。把整个framework_intermediates拷贝出来,作为一个额外jar包,加到你的应用中。

既然是技术贴,那顺便讲讲这个jar包,这个jar包是android系统大部分功能的API,其中就包含不对APP开发者开发的API。所以你加入会发现,classes.jar的API怎么和自己SDK

中的android.jar的接口差不多呢,你这么细心很难得,确实差不多,而且比android.jar多。(如果大家对这块感兴趣呢,可以留言,我会肯根据人数多少写一篇关于Android自己生成SDK API介绍的帖子来满足大家)。

讲到这里,其实你应该就应该可以想到Android系统的Settings其实就是调用了这里的Bluetooth HID接口。

大家可能又第二个问题,系统Settings会有很多的权限,并且BluetoothInputDevice是隐藏类,里面的方法我们怎么用呀?

其实大家别疑惑,蓝牙用的权限其实就那么几个,所以权限不是问题,隐藏类我们刚才通过加入jar包解决了,那么就剩下里面的方法怎么用了。

其实找到隐藏类,只要不是hide接口,都是可以正常调用的,如果有hide,大家可以通过反射来实现即可。

下面我贴一下BluetoothInputDevice都有啥,能不能满足大家的功能实现:

33/**
34 * This class provides the public APIs to control the Bluetooth Input
35 * Device Profile.
36 *
37 *

BluetoothInputDevice is a proxy object for controlling the Bluetooth 38 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get 39 * the BluetoothInputDevice proxy object. 40 * 41 *

Each method is protected with its appropriate permission. 42 *@hide 43 */ 44public final class BluetoothInputDevice implements BluetoothProfile { 45 private static final String TAG = "BluetoothInputDevice"; 46 private static final boolean DBG = true; 47 private static final boolean VDBG = false; 48 49 /** 50 * Intent used to broadcast the change in connection state of the Input 51 * Device profile. 52 * 53 *

This intent will have 3 extras: 54 *

    55 *
  • {@link #EXTRA_STATE} - The current state of the profile.
  • 56 *
  • {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
  • 57 *
  • {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
  • 58 *
59 * 60 *

{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of 61 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, 62 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}. 63 * 64 *

Requires {@link android.Manifest.permission#BLUETOOTH} permission to 65 * receive. 66 */ 67 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 68 public static final String ACTION_CONNECTION_STATE_CHANGED = 69 "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; 70 71 /** 72 * @hide 73 */ 74 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 75 public static final String ACTION_PROTOCOL_MODE_CHANGED = 76 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED"; 77 78 /** 79 * @hide 80 */ 81 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 82 public static final String ACTION_HANDSHAKE = 83 "android.bluetooth.input.profile.action.HANDSHAKE"; 84 85 /** 86 * @hide 87 */ 88 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 89 public static final String ACTION_REPORT = 90 "android.bluetooth.input.profile.action.REPORT"; 91 92 /** 93 * @hide 94 */ 95 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 96 public static final String ACTION_VIRTUAL_UNPLUG_STATUS = 97 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS"; 98 99 /** 100 * @hide 101 */ 102 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 103 public static final String ACTION_IDLE_TIME_CHANGED = 104 "codeaurora.bluetooth.input.profile.action.IDLE_TIME_CHANGED"; 105 106 /** 107 * Return codes for the connect and disconnect Bluez / Dbus calls. 108 * @hide 109 */ 110 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000; 111 112 /** 113 * @hide 114 */ 115 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001; 116 117 /** 118 * @hide 119 */ 120 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002; 121 122 /** 123 * @hide 124 */ 125 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003; 126 127 /** 128 * @hide 129 */ 130 public static final int INPUT_OPERATION_SUCCESS = 5004; 131 132 /** 133 * @hide 134 */ 135 public static final int PROTOCOL_REPORT_MODE = 0; 136 137 /** 138 * @hide 139 */ 140 public static final int PROTOCOL_BOOT_MODE = 1; 141 142 /** 143 * @hide 144 */ 145 public static final int PROTOCOL_UNSUPPORTED_MODE = 255; 146 147 /* int reportType, int reportType, int bufferSize */ 148 /** 149 * @hide 150 */ 151 public static final byte REPORT_TYPE_INPUT = 1; 152 153 /** 154 * @hide 155 */ 156 public static final byte REPORT_TYPE_OUTPUT = 2; 157 158 /** 159 * @hide 160 */ 161 public static final byte REPORT_TYPE_FEATURE = 3; 162 163 /** 164 * @hide 165 */ 166 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0; 167 168 /** 169 * @hide 170 */ 171 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1; 172 173 /** 174 * @hide 175 */ 176 public static final String EXTRA_PROTOCOL_MODE = "android.bluetooth.BluetoothInputDevice.extra.PROTOCOL_MODE"; 177 178 /** 179 * @hide 180 */ 181 public static final String EXTRA_REPORT_TYPE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_TYPE"; 182 183 /** 184 * @hide 185 */ 186 public static final String EXTRA_REPORT_ID = "android.bluetooth.BluetoothInputDevice.extra.REPORT_ID"; 187 188 /** 189 * @hide 190 */ 191 public static final String EXTRA_REPORT_BUFFER_SIZE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_BUFFER_SIZE"; 192 193 /** 194 * @hide 195 */ 196 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothInputDevice.extra.REPORT"; 197 198 /** 199 * @hide 200 */ 201 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS"; 202 203 /** 204 * @hide 205 */ 206 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS"; 207 208 /** 209 * @hide 210 */ 211 public static final String EXTRA_IDLE_TIME = "codeaurora.bluetooth.BluetoothInputDevice.extra.IDLE_TIME"; 212 213 private Context mContext; 214 private ServiceListener mServiceListener; 215 private BluetoothAdapter mAdapter; 216 private IBluetoothInputDevice mService; 217 218 final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback = 219 new IBluetoothStateChangeCallback.Stub() { 220 public void onBluetoothStateChange(boolean up) { 221 if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up); 222 if (!up) { 223 if (VDBG) Log.d(TAG,"Unbinding service..."); 224 synchronized (mConnection) { 225 try { 226 mService = null; 227 mContext.unbindService(mConnection); 228 } catch (Exception re) { 229 Log.e(TAG,"",re); 230 } 231 } 232 } else { 233 synchronized (mConnection) { 234 try { 235 if (mService == null) { 236 if (VDBG) Log.d(TAG,"Binding service..."); 237 doBind(); 238 } 239 } catch (Exception re) { 240 Log.e(TAG,"",re); 241 } 242 } 243 } 244 } 245 }; 246 247 /** 248 * Create a BluetoothInputDevice proxy object for interacting with the local 249 * Bluetooth Service which handles the InputDevice profile 250 * 251 */ 252 /*package*/ BluetoothInputDevice(Context context, ServiceListener l) { 253 mContext = context; 254 mServiceListener = l; 255 mAdapter = BluetoothAdapter.getDefaultAdapter(); 256 257 IBluetoothManager mgr = mAdapter.getBluetoothManager(); 258 if (mgr != null) { 259 try { 260 mgr.registerStateChangeCallback(mBluetoothStateChangeCallback); 261 } catch (RemoteException e) { 262 Log.e(TAG,"",e); 263 } 264 } 265 266 doBind(); 267 } 268 269 boolean doBind() 280 281 /*package*/ void close() 304 305 /** 306 * Initiate connection to a profile of the remote bluetooth device. 307 * 308 *

The system supports connection to multiple input devices. 309 * 310 *

This API returns false in scenarios like the profile on the 311 * device is already connected or Bluetooth is not turned on. 312 * When this API returns true, it is guaranteed that 313 * connection state intent for the profile will be broadcasted with 314 * the state. Users can get the connection state of the profile 315 * from this intent. 316 * 317 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 318 * permission. 319 * 320 * @param device Remote Bluetooth Device 321 * @return false on immediate error, 322 * true otherwise 323 * @hide 324 */ 325 public boolean connect(BluetoothDevice device) 338 339 /** 340 * Initiate disconnection from a profile 341 * 342 *

This API will return false in scenarios like the profile on the 343 * Bluetooth device is not in connected state etc. When this API returns, 344 * true, it is guaranteed that the connection state change 345 * intent will be broadcasted with the state. Users can get the 346 * disconnection state of the profile from this intent. 347 * 348 *

If the disconnection is initiated by a remote device, the state 349 * will transition from {@link #STATE_CONNECTED} to 350 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the 351 * host (local) device the state will transition from 352 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to 353 * state {@link #STATE_DISCONNECTED}. The transition to 354 * {@link #STATE_DISCONNECTING} can be used to distinguish between the 355 * two scenarios. 356 * 357 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 358 * permission. 359 * 360 * @param device Remote Bluetooth Device 361 * @return false on immediate error, 362 * true otherwise 363 * @hide 364 */ 365 public boolean disconnect(BluetoothDevice device) 378 379 /** 380 * {@inheritDoc} 381 */ 382 public List getConnectedDevices() 395 396 /** 397 * {@inheritDoc} 398 */ 399 public List getDevicesMatchingConnectionStates(int[] states) 412 413 /** 414 * {@inheritDoc} 415 */ 416 public int getConnectionState(BluetoothDevice device) 429 430 /** 431 * Set priority of the profile 432 * 433 *

The device should already be paired. 434 * Priority can be one of {@link #PRIORITY_ON} or 435 * {@link #PRIORITY_OFF}, 436 * 437 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} 438 * permission. 439 * 440 * @param device Paired bluetooth device 441 * @param priority 442 * @return true if priority is set, false on error 443 * @hide 444 */ 445 public boolean setPriority(BluetoothDevice device, int priority) 462 463 /** 464 * Get the priority of the profile. 465 * 466 *

The priority can be any of: 467 * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF}, 468 * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED} 469 * 470 *

Requires {@link android.Manifest.permission#BLUETOOTH} permission. 471 * 472 * @param device Bluetooth device 473 * @return priority of the device 474 * @hide 475 */ 476 public int getPriority(BluetoothDevice device) 489 490 private final ServiceConnection mConnection = new ServiceConnection() 507 508 private boolean isEnabled() 519 520 521 /** 522 * Initiate virtual unplug for a HID input device. 523 * 524 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 525 * 526 * @param device Remote Bluetooth Device 527 * @return false on immediate error, 528 * true otherwise 529 * @hide 530 */ 531 public boolean virtualUnplug(BluetoothDevice device) 546 547 /** 548 * Send Get_Protocol_Mode command to the connected HID input device. 549 * 550 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 551 * 552 * @param device Remote Bluetooth Device 553 * @return false on immediate error, 554 *true otherwise 555 * @hide 556 */ 557 public boolean getProtocolMode(BluetoothDevice device) 570 571 /** 572 * Send Set_Protocol_Mode command to the connected HID input device. 573 * 574 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 575 * 576 * @param device Remote Bluetooth Device 577 * @return false on immediate error, 578 * true otherwise 579 * @hide 580 */ 581 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) 594 595 /** 596 * Send Get_Report command to the connected HID input device. 597 * 598 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 599 * 600 * @param device Remote Bluetooth Device 601 * @param reportType Report type 602 * @param reportId Report ID 603 * @param bufferSize Report receiving buffer size 604 * @return false on immediate error, 605 * true otherwise 606 * @hide 607 */ 608 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) 621 622 /** 623 * Send Set_Report command to the connected HID input device. 624 * 625 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 626 * 627 * @param device Remote Bluetooth Device 628 * @param reportType Report type 629 * @param report Report receiving buffer size 630 * @return false on immediate error, 631 * true otherwise 632 * @hide 633 */ 634 public boolean setReport(BluetoothDevice device, byte reportType, String report) 647 648 /** 649 * Send Send_Data command to the connected HID input device. 650 * 651 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 652 * 653 * @param device Remote Bluetooth Device 654 * @param report Report to send 655 * @return false on immediate error, 656 * true otherwise 657 * @hide 658 */ 659 public boolean sendData(BluetoothDevice device, String report) 672 673 /** 674 * Send Get_Idle_Time command to the connected HID input device. 675 * 676 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 677 * 678 * @param device Remote Bluetooth Device 679 * @return false on immediate error, 680 * true otherwise 681 * @hide 682 */ 683 public boolean getIdleTime(BluetoothDevice device) 697 /** 698 * Send Set_Idle_Time command to the connected HID input device. 699 * 700 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission. 701 * 702 * @param device Remote Bluetooth Device 703 * @param idleTime Idle time to be set on HID Device 704 * @return false on immediate error, 705 * true otherwise 706 * @hide 707 */ 708 public boolean setIdleTime(BluetoothDevice device, byte idleTime) }

为了减少篇幅,我给大家把方法实现给裁剪了,大家可以通过方法和解释来判断一下。

那么下面来重点了,讲了这么多,我代码改怎么写呢,下面我把关键代码写一下,大家自己可以参考一下:

1.获得proxy

mBluetoothAdapter.getProfileProxy(mContext, new remoteDeviceServiceListener(), BluetoothProfile.INPUT_DEVICE);
2.获得监听且执行连接
 private final class remoteHidDeviceServiceListener implements BluetoothProfile.ServiceListener {

        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (null == mBluetoothDevice) {
                return;
            }
            List connectedDevices = proxy.getConnectedDevices();

            if (!connectedDevices.isEmpty()) {
                for (BluetoothDevice connectedDevice : connectedDevices) {
                    if (!connectedDevice.getAddress().equals(mBluetoothDevice.getAddress())) {
                        if (BluetoothProfile.INPUT_DEVICE == profile) {
                            mBluetoothInputDevice = (BluetoothInputDevice) proxy;
                            mBluetoothInputDevice.connect(mBluetoothDevice);
                         }
                    }
                }
            } else {
                if (BluetoothProfile.INPUT_DEVICE == profile) {
                    mBluetoothInputDevice = (BluetoothInputDevice) proxy;
                    mBluetoothInputDevice.connect(mBluetoothDevice);
                }
            }
        }

        @Override
        public void onServiceDisconnected(int profile) {
            
        }
    };

如果你的connect不能用,要用反射来实现。

我只写了关键代码,其他的大家可以根据提供的API来补充自己想做的功能。

希望写的东西对大家有用。

我的技术群是307822447,欢迎大家进群交流。

                                 

你可能感兴趣的:(android,bluetooth,Android,Bluetooth,HID)