Android 8.0实现蓝牙遥控器自动配对
作者:lojotee 发布时间:2021-08-05 08:24:16
本文要实现的是在 android 8.0 的平台上,蓝牙遥控器与TV自动配对,具体就是在TV端打开配对界面,TV端开始搜索远程蓝牙设备,按下遥控器按键让蓝牙遥控器进入对码模式,此时蓝牙遥控器就能作为一个远程蓝牙设备被发现,TV端扫描到这个远程蓝牙设备(蓝牙遥控器),就会自动进行配对连接。
话不多说,直接上代码分析。
public class RcConnectActivity extends Activity {
private static final String TAG = "RcConnectActivity";
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private BluetoothDevice mBluetoothDevice;
private BluetoothReceiver mBluetoothReceiver = null;
private boolean isConnected = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.rc_connect);
registerReceiver();
if (mBluetoothAdapter != null) {
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.startDiscovery();
Log.d(TAG, "mBluetoothAdapter.startDiscovery");
} else {
mBluetoothAdapter.enable();
Log.d(TAG, "mBluetoothAdapter.enable");
}
} else {
Toast.makeText(this, R.string.bluetooth_tip, Toast.LENGTH_SHORT).show();
}
}
首先我们要注册一个广播 * ,用来接收蓝牙扫描搜索配对过程中一些蓝牙相关的广播,以便进行相对应的操作。
public void registerReceiver() {
Log.d(TAG, "registerReceiver");
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
mBluetoothReceiver = new BluetoothReceiver();
registerReceiver(mBluetoothReceiver, filter);
}
BluetoothDevice.ACTION_FOUND 也就是 android.bluetooth.device.action.FOUND,当发现远程蓝牙设备的时候,系统就会发出这条广播。接收这条广播需要以下权限。
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED:当蓝牙连接状态改变时,就会发送此广播。
BluetoothAdapter.ACTION_STATE_CHANGED:也就是 android.bluetooth.adapter.action.STATE_CHANGED 当本地蓝牙适配器的状态改变时,比如打开蓝牙或者关闭蓝牙的时候,就会发送此广播。
BluetoothAdapter.ACTION_DISCOVERY_FINISHED:当本地蓝牙适配器完成设备扫描搜索过程的时候,就会发送此广播。
注册完广播接着就是通过 BluetoothAdapter.getDefaultAdapter() 来获取本地蓝牙适配器,如果硬件不支持蓝牙的话,那么返回值为null。如果能获取到,证明TV端是有可用的蓝牙模块,接着通过 isEnabled() 这个方法来判断TV端的蓝牙模块是否已经打开并且可以使用,相当于 getBluetoothState() == STATE_ON 。如果已经打开蓝牙,那么就可以通过 startDiscovery() 进行扫描蓝牙设备,否则就通过 enable() 来打开蓝牙。
startDiscovery() 需要<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
这个权限。
private class BluetoothReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "action = " + action);
if(BluetoothDevice.ACTION_FOUND.equals(action)){
mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "find device : " + "[ "+ mBluetoothDevice.getName() +" ]" + ":" + mBluetoothDevice.getAddress());
if (mBluetoothDevice.getName() == null || !mBluetoothDevice.getName().equals("RCSP")) {
return;
} else
{
if (mBluetoothDevice.getBondState() == BluetoothDevice.BOND_NONE) {
Log.d(TAG, "attemp to bond: " + "[ " + mBluetoothDevice.getName() + " ]");
try {
mBluetoothDevice.createBond();
isConnected = true;
} catch (Exception e) {
e.printStackTrace();
}
}
}
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
int status = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
if (BluetoothAdapter.STATE_ON == status) {
mBluetoothAdapter.startDiscovery();
Log.d(TAG, "mBluetoothAdapter.startDiscovery---STATE_ON");
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
if (!isConnected) {
mBluetoothAdapter.startDiscovery();
Log.d(TAG, "mBluetoothAdapter.startDiscovery---ACTION_DISCOVERY_FINISHED");
}
} else if (BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
int newState = intent.getExtras().getInt(BluetoothProfile.EXTRA_STATE);
switch (newState) {
case BluetoothProfile.STATE_CONNECTING:
Log.d(TAG, "CONNECTING");
Toast.makeText(context, R.string.bluetooth_connecting, Toast.LENGTH_SHORT).show();
break;
case BluetoothProfile.STATE_CONNECTED:
Log.d(TAG, "CONNECTED");
Toast.makeText(context, R.string.bluetooth_connected, Toast.LENGTH_SHORT).show();
RcConnectActivity.this.finish();
break;
}
}
}
}
流程分析:
1、如果TV端的蓝牙模块已经打开,那么就执行 startDiscovery(),否则通过 enable() 打开蓝牙,此时会接收到 BluetoothAdapter.ACTION_STATE_CHANGED 这条广播。蓝牙有四种状态,分别是STATE_OFF、STATE_TURNING_ON、STATE_ON、STATE_TURNING_OFF。当蓝牙状态为STATE_ON,表示蓝牙已经打开并且已经准备就绪,此时才可以进行startDiscovery(),否则 startDiscovery() 会返回false,无法扫描搜索远程蓝牙设备。
2、扫描搜索到远程设备之后,判断是不是目标设备,目标设备蓝牙遥控器的名字为 RCSP 。如果 getName() 获取到的名字为null,或者不是 RCSP,直接 return,不进行任何操作。android 8.0 要对 getName() 为 null 进行处理,不然程序会运行出错。如果搜索到目标设备,通过 createBond() 方法,实现自动配对。
3、startDiscovery() 会进行大约12秒的扫描搜索,有可能此时我们的目标设备还没有进入对码模式,还不能被TV端发现,从而也无法自动配对。当扫描搜索完成之后,会发送 BluetoothAdapter.ACTION_DISCOVERY_FINISHED 这条广播,此时我们在判断目标设备是否已经配对连接,如果没有,再次调用 startDiscovery() 进行扫描搜索。
4、当目标设备在进行自动配对的时候,我们通过接收BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED 这条广播,来判断目标设备的状态,并用 Toast 提示配对是否成功。
来源:https://blog.csdn.net/lojotee/article/details/103693201


猜你喜欢
- Caffeine和Spring Boot集成Caffeine是使用Java8对Guava缓存的重写版本,在Spring Boot 2.0中将
- 近期在开发中遇到一种需求:根据用户的权限决定是否显示某操作按钮。例如:若用户拥有删除数据的权限,则在界面中显示“删除”按钮;若用户无该权限,
- 使用BufferedReader(缓存读取流)可以每次读取文件的一行。对于文件内容如果是按行为单位排列的话,则使用BufferedReade
- 使用System.Environment获取电脑的相关属性,入门案例,具体内容如下static void Main(string[] arg
- 一、背景1.1 应用系统的架构历史1.2 什么是微服务?起源:微服务的概念源于 2014 年 3 月 Martin Fowler 所写的一篇
- 原因每次使用idea新建项目,就会在默认的c盘下的一个maven仓库中下载jar包,可是我自己指定maven仓库不是这个。如何让idea在新
- 一、前言一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文
- 将二维数组转化为一维数组1. 为了偷懒所以我写了一个随机生成二维数组的函数/* * 自动创建随机为100以内的二维
- java 出现Zipexception 异常的解决办法1 异常描述在从 SVN 检出项目并配置完成后,启动 Tomcat 服务器,报出如下错
- 本文主要介绍Android实现拍照、录像、录音代码的资料,这里整理了详细的代码,有需要的小伙伴可以参考下。RecordActivity.ja
- 本篇博客我们继续的来聊SpringMVC的东西,下方我们将会聊到js、css这些静态文件的加载配置,以及服务器推送的两种实现方式。当然我们在
- 本文实例讲述了Winform实现调用asp.net数据接口的方法,分享给大家供大家参考。具体实现方法如下:一、问题:最近一个WPF项目需要改
- 本文实例讲述了Windows窗体的.Net框架绘图技术实现方法,非常实用,具体内容如下:一般来说,当编写一个典型的Windows 窗体程序时
- 本文实例总结了Java编程实现生成给定范围内不重复随机数的方法。分享给大家供大家参考,具体如下:在Java中的Math类中存在一个rando
- 1、JDK1.8之前:假设有实体类User,里面有字段id,我们将相同id的User进行分组,并存放在Map中。(例子不是很恰当,但很能说明
- 1、什么是servlet异步请求Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:(1)、Servlet 接收
- 每一个基于java的应用程序都有一个共同工作来展示给用户看到的内容作为工作的应用几个对象。当编写一个复杂的Java应用程序,应用程序类应该尽
- 本文主要给大家介绍了关于Java8中Optional类型和Kotlin中可空类型使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一
- 本文实例讲述了C#使用Socket实现发送和接收图片的方法。分享给大家供大家参考。具体如下:using System;using Syste
- 什么是fescar?关于fescar的详细介绍,请参阅fescar wiki。传统的2PC提交协议,会持有一个全局性的锁,所有局部事务预提交