您的位置:首页 > 移动开发

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

2017-08-03 10:27 459 查看
转载请标明出处: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 *<p>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 *<p>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     * <p>This intent will have 3 extras:
54     * <ul>
55     *   <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
56     *   <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
57     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
58     * </ul>
59     *
60     * <p>{@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     * <p>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     * <p> The system supports connection to multiple input devices.
309     *
310     * <p> 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     * <p>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     * <p> 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     * <p> 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     * <p>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<BluetoothDevice> getConnectedDevices()
395
396    /**
397     * {@inheritDoc}
398     */
399    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states)
412
413    /**
414     * {@inheritDoc}
415     */
416    public int getConnectionState(BluetoothDevice device)
429
430    /**
431     * Set priority of the profile
432     *
433     * <p> The device should already be paired.
434     *  Priority can be one of {@link #PRIORITY_ON} or
435     * {@link #PRIORITY_OFF},
436     *
437     * <p>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     * <p> The priority can be any of:
467     * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
468     * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
469     *
470     * <p>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     * <p>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    * <p>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     * <p>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     * <p>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     * <p>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     * <p>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     * <p>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     * <p>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<BluetoothDevice> 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 HID
相关文章推荐