项目是TV端的,产品要求不经过设置界面,开机进入引导页,自动搜索蓝牙遥控器并且建立连接。
刚开始接手的时候以为会很快完成,无非就是调用API吗?可是事实不是这样,前后花了一些时间,才解决。
好了,当时尝试了Socket连接以及低功耗连接BLE,事实证明都不可行,后来就在想设置界面是怎么连接的呢,终于找到了答案。
蓝牙设置界面入口在BluetoothSettings.java,这个BluetoothSettings继承自DeviceListPreferenceFragment.java。点击某个搜索到的蓝牙列表项之后,走的流程如下:
void onClicked() {
int bondState = mCachedDevice.getBondState();
if (mCachedDevice.isConnected()) {
askDisconnect();
} else if (bondState == BluetoothDevice.BOND_BONDED) {
mCachedDevice.connect(true);
} else if (bondState == BluetoothDevice.BOND_NONE) {
pair();
}
}
在这个方法里面对当前蓝牙设备状态进行判断,如果没有绑定上,去pair,绑定上了
进行连接,调用的mCachedDevice.connect(true);这个mCachedDevice是
/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
我们看下其中具体实现:
public void connect(boolean connectAllProfiles) {
//如果没有连接上,返回
if (!ensurePaired()) {
return;
}
mConnectAttempted = SystemClock.elapsedRealtime();
connectWithoutResettingTimer(connectAllProfiles);
}
具体实现在connectWithoutResettingTimer方法中,我们看最终其调用的方法:
synchronized void connectInt(LocalBluetoothProfile profile) {
if (!ensurePaired()) {
return;
}
if (profile.connect(mDevice)) {
if (Utils.D) {
Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
}
return;
}
Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
}
这个profile是什么呢?它的意义很大,其实代表我们蓝牙协议具体实现接口,蓝牙连接的设备有很多种,我们的蓝牙遥控器属于Hid设备,是其中之一,HidProfile是Hid连接协议,一层层查找,最终找到蓝牙连接的最终实现在framework/base/core/java/android/bluetooth/BluetoothInputDevice.java。
/**
* Initiate connection to a profile of the remote bluetooth device.
*
* <p> The system supports connection to multiple input devices.
*
* <p> This API returns false in scenarios like the profile on the
* device is already connected or Bluetooth is not turned on.
* When this API returns true, it is guaranteed that
* connection state intent for the profile will be broadcasted with
* the state. Users can get the connection state of the profile
* from this intent.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
* permission.
*
* @param device Remote Bluetooth Device
* @return false on immediate error,
* true otherwise
* @hide
*/
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
Log.d(TAG,"mService is null ?"+ mService==null);
if (mService != null && isEnabled() && isValidDevice(device)) {
try {
return mService.connect(device);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
}
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
从该方法的注释中就可以看出,该方法就是用来连接Hid蓝牙设备的,好了,所以我们最终只要把这个类的方法调用起来就可以了,这个类直接SDK是获取不到的,不过也不要直接反射这个类,我们可以通过BluetoothAdapter的getProfileProxy方法获取到该类对象。
在其回调中,反射调用connect方法。
好了,到这里就大功告成啦~~