Android 蓝牙配对Settings应用里面的简要流程记录
文章目录
- Android 蓝牙配对Settings应用里面的简要流程记录
- 一、前言
- 二、Settings蓝牙配对的关键代码
- 1、接收蓝牙请求的地方 AndroidManifest.xml
- 2、BluetoothPairingRequest
- 3、BluetoothPairingService
- 4、BluetoothPairingDialog
- 5、BluetoothNameDialogFragment.java
- 6、BluetoothPairingController
- 三、其他
- 1、Settings和TvSettings的配对界面
- (1)TvSettings蓝牙配对对话框
- (2)Settings蓝牙配对对话框
- 2、自定义的应用界面监听和处理蓝牙配对广播
- 3、Android 蓝牙相关广播介绍
- 4、Android13 不能静态注册的几个广播
- 5、Android13 蓝牙协议属性配置详解
一、前言
本文只是简单分析一下原生设置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