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

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

相关推荐
selt7919 小时前
Redisson之RedissonLock源码完全解析
android·java·javascript
Yao_YongChao9 小时前
Android MVI处理副作用(Side Effect)
android·mvi·mvi副作用
非凡ghost10 小时前
JRiver Media Center(媒体管理软件)
android·学习·智能手机·媒体·软件需求
席卷全城10 小时前
Android 推箱子实现(引流文章)
android
齊家治國平天下10 小时前
Android 14 系统中 Tombstone 深度分析与解决指南
android·crash·系统服务·tombstone·android 14
maycho12312 小时前
MATLAB环境下基于双向长短时记忆网络的时间序列预测探索
android
思成不止于此13 小时前
【MySQL 零基础入门】MySQL 函数精讲(二):日期函数与流程控制函数篇
android·数据库·笔记·sql·学习·mysql
brave_zhao13 小时前
达梦数据库(DM8)支持全文索引功能,但并不直接兼容 MySQL 的 FULLTEXT 索引语法
android·adb
sheji341613 小时前
【开题答辩全过程】以 基于Android的网上订餐系统为例,包含答辩的问题和答案
android
easyboot14 小时前
C#使用SqlSugar操作mysql数据库
android·sqlsugar