Android 蓝牙配对Settings应用里面的简要流程记录

发布于:2024-06-16 ⋅ 阅读:(19) ⋅ 点赞:(0)

Android 蓝牙配对Settings应用里面的简要流程记录

一、前言

本文只是简单分析一下原生设置Settings中蓝牙配对的大致流程,具体细节有需要的自行研究。

另外我这里的开发平台是AML平台的,所以会有Settings和TvSettings,
其实这两个应用都会监听到蓝牙配请求,都会进行处理,这也是为啥会出现两次蓝牙配对弹框确认的情况。

如果想看看蓝牙配对流程或者蓝牙配对界面就行修改可以收藏看看。

二、Settings蓝牙配对的关键代码

Settings中蓝牙界面和蓝牙相关逻辑的代码,都是在:packages\apps\Settings\src\com\android\settings\bluetooth\ 目录

1、接收蓝牙请求的地方 AndroidManifest.xml

packages\apps\Settings\src\com\android\Settings\AndroidManifest.xml

<activity android:name=".bluetooth.BluetoothPairingDialog" //(1)这是一个Activity
    android:permission="android.permission.BLUETOOTH_PRIVILEGED"
    android:excludeFromRecents="true"
    android:windowSoftInputMode="stateVisible|adjustResize"
    android:theme="@style/Theme.AlertDialog"
    android:exported="true"
    android:taskAffinity=".bluetooth.BluetoothPairingDialog">
    <intent-filter android:priority="1">
    	//(2)接收蓝牙请求
   	 	<action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
    	<category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
        
<receiver android:name=".bluetooth.BluetoothPairingRequest" //(3)这是一个静态广播接收者
        android:exported="true">
	<intent-filter>
		//(4)接收蓝牙请求
        <action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
        <action android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE"/>
	</intent-filter>
</receiver>

2、BluetoothPairingRequest

Settings\src\com\android\settings\bluetooth\BluetoothPairingRequest .java

public final class BluetoothPairingRequest extends BroadcastReceiver {
    private static final String TAG = "BluetoothPairingRequest";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action == null) {
            return;
        }
。。。
            if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
                ...) {
                device.setPairingConfirmation(true); //(1)直接确认配对的情况
            } else if (powerManager.isInteractive() && shouldShowDialog) {
                // Since the screen is on and the BT-related activity is in the foreground,
                // just open the dialog
                // convert broadcast intent into activity intent (same action string)
                Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(
                    context, intent, BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND);
				//(2)拉起蓝牙配对对话框
                context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
            } else {
                // (3)拉起 BluetoothPairingService
                intent.setClass(context, BluetoothPairingService.class);
                intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
                context.startServiceAsUser(intent, UserHandle.CURRENT);
    ...
		
            mBluetoothManager.getCachedDeviceManager().pairDeviceByCsip(device, groupId);
        }
    }
}

可以看到这个静态的广播接收者,主要功能大概有:

某些条件下直接确认配对设备

某些条件下拉起蓝牙配对确认对话框

某些条件下拉起蓝牙配对服务

AndroidManifest.xml 已经监听配对会拉起蓝牙配对对话框,这里再拉起会冲突吗?

其实不会,因为这里会有判断对话框是否已经拉起。

3、BluetoothPairingService

Settings\src\com\android\settings\bluetooth\BluetoothPairingService.java

//取消配对
mDevice.cancelBondProcess();

这个主要是启动蓝牙服务;

BluetoothPairingService主要是监听配对是否取消和配对过程异常等情况,具体逻辑就不分析了。

4、BluetoothPairingDialog

Settings\src\com\android\settings\bluetooth\BluetoothPairingDialog.java

这里主要是拉起显示配对的对话框和随时监听配对情况

public class BluetoothPairingDialog extends FragmentActivity {


    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            //如果已经绑定了 或者取消配对都会关闭对话框界面
            if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
                int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
                        BluetoothDevice.ERROR);
                if (bondState == BluetoothDevice.BOND_BONDED ||
                        bondState == BluetoothDevice.BOND_NONE) {
                    dismiss();
                }
            } else if (BluetoothDevice.ACTION_PAIRING_CANCEL.equals(action)) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                if (device == null || mBluetoothPairingController.deviceEquals(device)) {
                    dismiss();
                }
            }
        }
    };

  @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        BluetoothPairingDialogFragment bluetoothFragment = ...;
        //正常情况下会拉起蓝牙配对对话框
        if (!fragmentFound) {
            bluetoothFragment.show(getSupportFragmentManager(), FRAGMENT_TAG);
        }
    }


}

从上面代码看,BluetoothPairingDialog主要作用是拉起对话框界面BluetoothPairingDialogFragment;

如果要修改蓝牙对话对话框的界面和相关信息,不是修改 BluetoothPairingDialog 的代码,

而是要修改BluetoothNameDialogFragment 的代码。

5、BluetoothNameDialogFragment.java

packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothNameDialogFragment.java

该界面主要是根据情况显示配对对话框的内容

public class BluetoothPairingDialogFragment extends InstrumentedDialogFragment {

	//里面的代码基本都是对话框界面和相关逻辑的控制
...

	//点击取消和确认配对情况的回调
    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (which == DialogInterface.BUTTON_POSITIVE) {
            mPositiveClicked = true;
            mPairingController.onDialogPositiveClick(this);
        } else if (which == DialogInterface.BUTTON_NEGATIVE) {
            mPairingController.onDialogNegativeClick(this);
        }
        mPairingDialogActivity.dismiss();
    }

}

6、BluetoothPairingController

Settings\src\com\android\settings\bluetooth\BluetoothPairingController.java

这个类就相当于一个工具类,执行具体的逻辑。

public class BluetoothPairingController implements OnCheckedChangeListener,
        BluetoothPairingDialogListener {
	//确认配对后的操作
    private void onPair(String passkey) {
        Log.d(TAG, "Pairing dialog accepted");
        switch (mType) {
            case BluetoothDevice.PAIRING_VARIANT_PIN:
            case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
                mDevice.setPin(passkey);
                break;


            case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
            case BluetoothDevice.PAIRING_VARIANT_CONSENT:
                mDevice.setPairingConfirmation(true); //确认配对关键
                break;

            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY:
            case BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN:
            case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
            case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
                // Do nothing.
                break;

            default:
                Log.e(TAG, "Incorrect pairing type received");
        }
    }

	//取消配对或者关闭配对对话框的操作
    public void onCancel() {
            Log.d(TAG, "Pairing dialog canceled");
            mDevice.cancelBondProcess(); //取消配对关键
    }
}

三、其他

1、Settings和TvSettings的配对界面

dumpsys window 查看相关界面信息:

//(1)查看Settings 的配对界面显示情况
console:/ # dumpsys window| grep mFoc
  mFocusedApp=ActivityRecord{e4d15f7 u0 com.android.settings/.bluetooth.BluetoothPairingDialog t30}
    mFocusedWindow=Window{5509839 u0 com.android.settings/com.android.settings.bluetooth.BluetoothPairingDialog}
console:/ # 
console:/ #

//(2)查看TvSettings 的配对界面显示情况
console:/ # dumpsys window| grep mFoc
  mFocusedApp=ActivityRecord{f08fb5d u0 com.android.tv.settings/.accessories.BluetoothPairingDialog t31}
    mFocusedWindow=Window{931897e u0 com.android.tv.settings/com.android.tv.settings.accessories.BluetoothPairingDialog}

console:/ #

从dumpsys window 的窗口信息可以看到:

1、Settings的应用包名是:com.android.settings
2、TvSettings的应用包名是:com.android.tv.settings
3、Settings拉起配对对话框的类是:com.android.settings.bluetooth.BluetoothPairingDialog
4、TvSettings拉起配对对话框的类是:com.android.tv.settings.accessories.BluetoothPairingDialog

Settings和TvSettings的代码都在packages/apps/目录下,

原生Settings的具体逻辑是比TvSettings处理更详细一些,有兴趣的可以自己看看。

2、TvSettings蓝牙配对对话框和原生Settings配对对话框

(1)TvSettings蓝牙配对对话框

在这里插入图片描述

(2)Settings蓝牙配对对话框

在这里插入图片描述

(3)隐藏"通讯录访问"选框

有些方案是商显或者平板方案,可能需要取消这个现实,修改的地方;

Settings\src\com\android\settings\bluetooth\BluetoothPairingDialogFragment.java

//	contactSharing.setVisibility(mPairingController.isContactSharingVisible() ? View.VISIBLE : View.GONE);
        //隐藏"访问通讯录和通话记录"选项
        contactSharing.setVisibility(View.GONE);

可能有多种对话框会显示,全局搜索 “contactSharing.setVisibility”进行修改就可以了。

修改后的样式:

在这里插入图片描述

隐藏"通讯录选项"还可以修改:BluetoothPairingController的isContactSharingVisible()方法逻辑。

3、如果要去除TvSettings 的蓝牙配对监听

package\apps\TvSettings\Settings\AndroidManifest.xml

删除或者注释掉下面这段代码就OK了:

        <receiver
            android:name=".accessories.BluetoothPairingRequest"
            android:exported="true">
            <intent-filter>
                <action android:name="android.bluetooth.device.action.PAIRING_REQUEST"/>
            </intent-filter>
        </receiver>

        <activity
            android:name=".accessories.BluetoothPairingDialog"
            android:configChanges="keyboard|keyboardHidden|navigation"
            android:excludeFromRecents="true"
            android:exported="true"
            android:permission="android.permission.BLUETOOTH_PRIVILEGED"
            android:taskAffinity="">
            <intent-filter>
                <action android:name="android.bluetooth.device.action.PAIRING_REQUEST"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

2、自定义的应用界面监听和处理蓝牙配对广播

主要代码如下:

//监听蓝牙配对广播
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); //;蓝牙配对广播
context.registerReceiver(mBluetoothReceiver, mIntentFilter);

class BluetoothReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context content, Intent intent) {
            String action = intent.getAction();
            LogUtil.debug("onReceive action = " + action);
            if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {

BluetoothDevice device =  intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//设置蓝牙配对
                device.setPairingConfirmation(true);
                abortBroadcast();//关闭广播传递,防止原生设置监听到配对
            }
  }      

这里是监听到蓝牙配对后,后台直接确认配对,不用点击系统Settings的配对对话框就会确认配对。

并且这里进行了 abortBroadcast ,其他应用就不会收到蓝牙配对广播。

动态监听的方式肯定是比静态静态的方式更快收到广播。

自定义代码中也可以自己写对话框确认是否配对和取消配对。

3、Android 蓝牙相关广播介绍

蓝牙相关广播都是在 BluetoothDevice.java 和 BluetoothAdapter.java 中进行了定义。

蓝牙相关广播主要包括:蓝牙开关,蓝牙连接,蓝牙状态改变,蓝牙配对等等等等。

//Android13 中的源码地址:

packages\modules\Bluetooth\framework\java\android\bluetooth\BluetoothDevice.java

packages\modules\Bluetooth\framework\java\android\bluetooth\BluetoothAdapter.java

https://blog.csdn.net/wenzhi20102321/article/details/134956116

4、Android13 不能静态注册的几个广播

android.intent.action.SCREEN_ON //屏幕亮起

android.intent.action.SCREEN_OFF//屏幕亮起

android.intent.action.BATTERY_CHANGED //电池电量改变

android.intent.action.CONFIGURATION_CHANGED //配置改变,界面语言,设备方向等配置信息

android.intent.action.TIME_TICK //每分钟回调一次

具体内容:

https://blog.csdn.net/wenzhi20102321/article/details/134956090

5、Android13 蓝牙协议属性配置详解

https://blog.csdn.net/wenzhi20102321/article/details/139703045