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

来源:互联网 发布:c语言初学者用什么编程软件 编辑:程序博客网 时间:2024/06/14 23:02

转载请标明出处: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 *<p>BluetoothInputDevice is a proxy object for controlling the Bluetooth38 * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get39 * the BluetoothInputDevice proxy object.40 *41 *<p>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     * <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 of61     * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},62     * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.63     *64     * <p>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     * <p> The system supports connection to multiple input devices.309     *310     * <p> 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     * <p>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     * <p> 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     * <p> 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     * <p>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<BluetoothDevice> getConnectedDevices() 395396    /**397     * {@inheritDoc}398     */399    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) 412413    /**414     * {@inheritDoc}415     */416    public int getConnectionState(BluetoothDevice device) 429430    /**431     * Set priority of the profile432     *433     * <p> The device should already be paired.434     *  Priority can be one of {@link #PRIORITY_ON} or435     * {@link #PRIORITY_OFF},436     *437     * <p>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     * <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 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     * <p>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    * <p>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     * <p>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     * <p>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     * <p>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     * <p>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     * <p>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     * <p>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<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,欢迎大家进群交流。