A2dp连接流程(android8及之前版本)

前言

Android P在a2dp协议有些许改动,支持多A2dp设备同时连接,流程上有变化,以下是记录Android O及以前的A2dp设备连接流程,以备我后续忘记时查阅.

正文
先简单讲讲应用层调用绑定和连接过程
扫描到设备后点击设备列表,通过反射调用BluetoothDevice的createBond方法发起绑定

 private void createBond(BluetoothDevice device) {
        try {
            Method method = BluetoothDevice.class.getMethod("createBond");
            method.invoke(device);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

发起绑定后会受到绑定状态变化的广播

 public static final String ACTION_BOND_STATE_CHANGED =
            "android.bluetooth.device.action.BOND_STATE_CHANGED";

绑定成功的状态变化为:
10(BOND_NONE) -> 11(BOND_BONDING) -> 12(BOND_BONDED)
如果是10 -> 11 - > 10 说明bond失败,可以重新发起bond

case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
                    int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, 10);
                    Log.i(TAG, "bond state change :bond state is " + bondState);
                    switch (bondState) {
                        case BluetoothDevice.BOND_BONDING:
                           //绑定中
                            break;
                        case BluetoothDevice.BOND_NONE:
                          //绑定失败
                            break;
                        case BluetoothDevice.BOND_BONDED:
                            //绑定成功,去连接设备
                            connect(device);

                            break;

                    }
                    break;

连接放在线程执行,需要区分不同的deviceType来获取不同的代理对象,关于deviceType我前面写过一个相关分析的博客

/**
     * 连接设备
     * 具体实现 int deviceType = device.getBluetoothClass().getMajorDeviceClass() = BITMASK & 下面的类型;
     * 不同设备类型该值不同,比如computer蓝牙为256、phone 蓝牙为512、打印机蓝牙为1536等等
     * public static class Major {
     * private static final int BITMASK           = 0x1F00;
     * 

* public static final int MISC = 0x0000; * public static final int COMPUTER = 0x0100; * public static final int PHONE = 0x0200; * public static final int NETWORKING = 0x0300; * public static final int AUDIO_VIDEO = 0x0400; * public static final int PERIPHERAL = 0x0500; * public static final int IMAGING = 0x0600; * public static final int WEARABLE = 0x0700; * public static final int TOY = 0x0800; * public static final int HEALTH = 0x0900; * public static final int UNCATEGORIZED = 0x1F00; * } */ public void connect(final BluetoothDevice device) { currentDevice = device; //测试,实际需要判断设备类型创建不同的profile final int deviceType = device.getBluetoothClass().getMajorDeviceClass(); new Thread() { @Override public void run() { if (deviceType == (0x1F00 & 0x0500)) {//4:input_device Log.i(TAG, "connect input device:" + device); adapter.getProfileProxy(mContext, mProfileListener, INPUT_DEVICE); } else if (deviceType == (0x1F00 & 0x0400)) {//AUDIO_VIDEO Log.i(TAG, "connect a2dp device:" + device); adapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); } else if (deviceType == (0x1F00 & 0x0200)) {//PHONE } } }.start(); }

在回调里面来进行连接操作

 private BluetoothProfile mBluetoothProfile;
    private BluetoothA2dp mA2dp;
    private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
        @Override
        public void onServiceConnected(int profile, BluetoothProfile proxy) {
            Log.i(TAG, "mConnectListener onServiceConnected");
            mBluetoothProfile = proxy;
            //判断连接的profile
            switch (profile) {
                case BluetoothProfile.A2DP:
                    mA2dp = (BluetoothA2dp) proxy;
                    setPriority(currentDevice, profile);
                    try {
                        //通过反射获取BluetoothA2dp中connect方法(hide的),进行连接。
                        Method connectMethod = BluetoothA2dp.class.getMethod("connect",
                                BluetoothDevice.class);
                        connectMethod.invoke(mA2dp, currentDevice);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
                case INPUT_DEVICE:
                    try {
                        //得到BluetoothInputDevice然后反射connect连接设备
                        Class mInputDevice = Class.forName("android.bluetooth.BluetoothInputDevice");
                        Method method = mInputDevice.getMethod("connect", String.class);
                        method.invoke(mInputDevice.newInstance(), currentDevice);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;

            }


        }

        @Override
        public void onServiceDisconnected(int profile) {
            Log.i(TAG, "mConnectListener onServiceConnected");
        }
    };

连接状态会有广播回调,不同类型的设备连接状态的广播是不一样的,a2dp连接广播为:

 public static final String ACTION_CONNECTION_STATE_CHANGED =
        "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";

下面就来看看framework层a2dp的连接流程
应用调用connect后到
framework/base/core/java/android/bluetooth/BluetoothA2dp.java
A2dp连接流程(android8及之前版本)_第1张图片
可以看到调用了mService.connect(device);
这里通过binder通信调到了Bluetooth.apk里的:
package/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.java
A2dp连接流程(android8及之前版本)_第2张图片
这里
1,检查权限
2,判断优先级
3,检查设备是否支持a2dp和a2dpSink
4,检查当前设备是否已经连接,或者正在连接

接下来就到了同目录下的A2dpStateMachine.java的内部类

private class Connected extends State {
	@override
	public boolean processMessage(Message message){
	}
}

A2dp连接流程(android8及之前版本)_第3张图片
这里
1,当前要连接的设备和已经连接的设备(mCurrentDevice)是否一致,一致就不往下走
2,发送广播通知其他进程,状态从disconnected -> connecting
3,断开mCurrentDevice,if断开失败,发送当前设备连接失败connecting -> disconnected
4,mTargetDevice = device ,mTargetDevice 为即将要连接的设备
5,transitionTo(mPending);
A2dp连接流程(android8及之前版本)_第4张图片
将消息延迟,

未完待续…

你可能感兴趣的:(framework)