转载请标明出处: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 Input35 * Device Profile.36 *37 *

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

Each method is protected with its appropriate permission.42 *@hide43 */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;4849 /**50 * Intent used to broadcast the change in connection state of the Input51 * 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 of61 * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},62 * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.63 *64 *

Requires {@link android.Manifest.permission#BLUETOOTH} permission to65 * 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";7071 /**72 * @hide73 */74 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)75 public static final String ACTION_PROTOCOL_MODE_CHANGED =76 "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";7778 /**79 * @hide80 */81 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)82 public static final String ACTION_HANDSHAKE =83 "android.bluetooth.input.profile.action.HANDSHAKE";8485 /**86 * @hide87 */88 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)89 public static final String ACTION_REPORT =90 "android.bluetooth.input.profile.action.REPORT";9192 /**93 * @hide94 */95 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)96 public static final String ACTION_VIRTUAL_UNPLUG_STATUS =97 "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";9899 /**100 * @hide101 */102 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)103 public static final String ACTION_IDLE_TIME_CHANGED =104 "codeaurora.bluetooth.input.profile.action.IDLE_TIME_CHANGED";105106 /**107 * Return codes for the connect and disconnect Bluez / Dbus calls.108 * @hide109 */110 public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;111112 /**113 * @hide114 */115 public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;116117 /**118 * @hide119 */120 public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;121122 /**123 * @hide124 */125 public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;126127 /**128 * @hide129 */130 public static final int INPUT_OPERATION_SUCCESS = 5004;131132 /**133 * @hide134 */135 public static final int PROTOCOL_REPORT_MODE = 0;136137 /**138 * @hide139 */140 public static final int PROTOCOL_BOOT_MODE = 1;141142 /**143 * @hide144 */145 public static final int PROTOCOL_UNSUPPORTED_MODE = 255;146147 /* int reportType, int reportType, int bufferSize */148 /**149 * @hide150 */151 public static final byte REPORT_TYPE_INPUT = 1;152153 /**154 * @hide155 */156 public static final byte REPORT_TYPE_OUTPUT = 2;157158 /**159 * @hide160 */161 public static final byte REPORT_TYPE_FEATURE = 3;162163 /**164 * @hide165 */166 public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;167168 /**169 * @hide170 */171 public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;172173 /**174 * @hide175 */176 public static final String EXTRA_PROTOCOL_MODE = "android.bluetooth.BluetoothInputDevice.extra.PROTOCOL_MODE";177178 /**179 * @hide180 */181 public static final String EXTRA_REPORT_TYPE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_TYPE";182183 /**184 * @hide185 */186 public static final String EXTRA_REPORT_ID = "android.bluetooth.BluetoothInputDevice.extra.REPORT_ID";187188 /**189 * @hide190 */191 public static final String EXTRA_REPORT_BUFFER_SIZE = "android.bluetooth.BluetoothInputDevice.extra.REPORT_BUFFER_SIZE";192193 /**194 * @hide195 */196 public static final String EXTRA_REPORT = "android.bluetooth.BluetoothInputDevice.extra.REPORT";197198 /**199 * @hide200 */201 public static final String EXTRA_STATUS = "android.bluetooth.BluetoothInputDevice.extra.STATUS";202203 /**204 * @hide205 */206 public static final String EXTRA_VIRTUAL_UNPLUG_STATUS = "android.bluetooth.BluetoothInputDevice.extra.VIRTUAL_UNPLUG_STATUS";207208 /**209 * @hide210 */211 public static final String EXTRA_IDLE_TIME = "codeaurora.bluetooth.BluetoothInputDevice.extra.IDLE_TIME";212213 private Context mContext;214 private ServiceListener mServiceListener;215 private BluetoothAdapter mAdapter;216 private IBluetoothInputDevice mService;217218 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 };246247 /**248 * Create a BluetoothInputDevice proxy object for interacting with the local249 * Bluetooth Service which handles the InputDevice profile250 *251 */252 /*package*/ BluetoothInputDevice(Context context, ServiceListener l) {253 mContext = context;254 mServiceListener = l;255 mAdapter = BluetoothAdapter.getDefaultAdapter();256257 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 }265266 doBind();267 }268269 boolean doBind() 280281 /*package*/ void close() 304305 /**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 the311 * device is already connected or Bluetooth is not turned on.312 * When this API returns true, it is guaranteed that313 * connection state intent for the profile will be broadcasted with314 * the state. Users can get the connection state of the profile315 * from this intent.316 *317 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}318 * permission.319 *320 * @param device Remote Bluetooth Device321 * @return false on immediate error,322 * true otherwise323 * @hide324 */325 public boolean connect(BluetoothDevice device) 338339 /**340 * Initiate disconnection from a profile341 *342 *

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

If the disconnection is initiated by a remote device, the state349 * will transition from {@link #STATE_CONNECTED} to350 * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the351 * host (local) device the state will transition from352 * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to353 * state {@link #STATE_DISCONNECTED}. The transition to354 * {@link #STATE_DISCONNECTING} can be used to distinguish between the355 * two scenarios.356 *357 *

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}358 * permission.359 *360 * @param device Remote Bluetooth Device361 * @return false on immediate error,362 * true otherwise363 * @hide364 */365 public boolean disconnect(BluetoothDevice device) 378379 /**380 * {@inheritDoc}381 */382 public List getConnectedDevices() 395396 /**397 * {@inheritDoc}398 */399 public List getDevicesMatchingConnectionStates(int[] states) 412413 /**414 * {@inheritDoc}415 */416 public int getConnectionState(BluetoothDevice device) 429430 /**431 * Set priority of the profile432 *433 *

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

Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}438 * permission.439 *440 * @param device Paired bluetooth device441 * @param priority442 * @return true if priority is set, false on error443 * @hide444 */445 public boolean setPriority(BluetoothDevice device, int priority) 462463 /**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 device473 * @return priority of the device474 * @hide475 */476 public int getPriority(BluetoothDevice device) 489490 private final ServiceConnection mConnection = new ServiceConnection() 507508 private boolean isEnabled() 519520521 /**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 Device527 * @return false on immediate error,528 * true otherwise529 * @hide530 */531 public boolean virtualUnplug(BluetoothDevice device) 546547 /**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 Device553 * @return false on immediate error,554 *true otherwise555 * @hide556 */557 public boolean getProtocolMode(BluetoothDevice device) 570571 /**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 Device577 * @return false on immediate error,578 * true otherwise579 * @hide580 */581 public boolean setProtocolMode(BluetoothDevice device, int protocolMode) 594595 /**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 Device601 * @param reportType Report type602 * @param reportId Report ID603 * @param bufferSize Report receiving buffer size604 * @return false on immediate error,605 * true otherwise606 * @hide607 */608 public boolean getReport(BluetoothDevice device, byte reportType, byte reportId, int bufferSize) 621622 /**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 Device628 * @param reportType Report type629 * @param report Report receiving buffer size630 * @return false on immediate error,631 * true otherwise632 * @hide633 */634 public boolean setReport(BluetoothDevice device, byte reportType, String report) 647648 /**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 Device654 * @param report Report to send655 * @return false on immediate error,656 * true otherwise657 * @hide658 */659 public boolean sendData(BluetoothDevice device, String report) 672673 /**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 Device679 * @return false on immediate error,680 * true otherwise681 * @hide682 */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 Device703 * @param idleTime Idle time to be set on HID Device704 * @return false on immediate error,705 * true otherwise706 * @hide707 */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,欢迎大家进群交流。

                                 

更多相关文章

  1. Nginx系列教程(六)| 手把手教你搭建 LNMP 架构并部署天空网络电影
  2. Android(安卓)app如何正确读写系统sys设备节点
  3. Android(安卓)系统启动流程解析-从开机到Dalvik VM
  4. 蒸蒸日上的智能手机,国产手机却迎来寒冬,因为手机操作系统android
  5. Android(安卓)再爆新漏洞,9.0 以下所有手机全部中招!
  6. Android亮屏和熄屏控制
  7. android 编译系统阅读与分析(1)-envsetup.sh (editing....)
  8. Android(安卓)应用崩溃后重启的机制
  9. Android核心分析之一:分析方法论探讨之设计意图

随机推荐

  1. Android studio使用教程
  2. Android 根文件系统启动分析
  3. 让一个小图片重复出现,形成一张大图片
  4. Android在Button按钮上同时显示文字和图
  5. android之CheckBox
  6. android 自定义checkbox
  7. android滑动view
  8. EventBus Usage
  9. Android视频教程
  10. Using smem on Android