蓝牙
由于项目中负责了蓝牙音乐模块,所以也对蓝牙做了一点点基础研究
申请权限
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
确认蓝牙功能
BluetoothManager mBluetoothManager = (BluetoothManager) requireContext()
.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
//在API17及以下版本
//BluetoothAdapter mDefaultAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter != null) {
//说明支持蓝牙功能
}
开启蓝牙
//确认蓝牙是否开启,未开启进行蓝牙打开控制
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 200);
}
//接收蓝牙开关请求结果
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: requestCode = " + requestCode);
if (requestCode == 200) {
if (resultCode == RESULT_OK) {
// 用户已开启蓝牙
Log.d(TAG, "onActivityResult: 用户已开启蓝牙");
} else {
// 用户未开启蓝牙
Log.d(TAG, "onActivityResult: 用户未开启蓝牙");
}
}
}
获取配对过的蓝牙
BluetoothManager mBluetoothManager = (BluetoothManager) requireContext()
.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter mBluetoothAdapter = mBluetoothManager.getAdapter();
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
for (BluetoothDevice bondedDevice : bondedDevices) {
Log.d(TAG, "onViewCreated: bondedDevice = " + bondedDevice);
}
扫描蓝牙并配对
权限
扫描蓝牙需要以下运行时权限,进行控制
<!-- google在android6.0之后,为了更好的保护用户的数据安全,所有需要访问硬件唯一标识符的地方都需要申请位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
实现
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
requireContext().registerReceiver(mScanDevicesReceiver, filter);
mBinding.discoveryBluetooth.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: discoveryBluetooth");
mBluetoothAdapter.startDiscovery();
}
});
public BroadcastReceiver mScanDevicesReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "onReceive: device = " + device.getAddress()
+ " device name = " + device.getName());
// 如果已经找到想要的设备,可以停止扫描
mBluetoothAdapter.cancelDiscovery();
// 与发现的蓝牙设备配对
device.createBond();
}
}
};
蓝牙连接
蓝牙设备间是通过socket通信,C/S架构,一个为服务端,一个为client段;由于蓝牙连接是耗时操作,因此我们需要在子线程中进行调用实现
服务端
public class AcceptThread extends Thread {
private static final String TAG = AcceptThread.class.getSimpleName();
private final BluetoothServerSocket mmServerSocket;
private BluetoothAdapter mBluetoothAdapter;
public static final String NAME = "CUSTOM_NAME";
public static final UUID MY_UUID = UUID.fromString("1231233213");
public AcceptThread(BluetoothAdapter adapter) {
mBluetoothAdapter = adapter;
BluetoothServerSocket tmp = null;
try {
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's listen() method failed", e);
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
try {
socket = mmServerSocket.accept();
if (socket != null) {
//TODO 用来处理数据
mmServerSocket.close();
}
} catch (IOException e) {
Log.e(TAG, "Socket's accept() method failed", e);
}
}
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the connect socket", e);
}
}
}
客户端
public class ConnectThread extends Thread {
private static final String TAG = ConnectThread.class.getSimpleName();
private final BluetoothSocket mSocket;
private final BluetoothDevice mDevice;
public static final UUID MY_UUID = UUID.fromString("1231233213");
public ConnectThread(BluetoothDevice device) {
BluetoothSocket tmp = null;
mDevice = device;
try {
tmp = mDevice.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "Socket's create() method failed", e);
}
mSocket = tmp;
}
public void run() {
try {
mSocket.connect();
//TODO 处理数据
} catch (IOException connectException) {
try {
mSocket.close();
} catch (IOException closeException) {
Log.e(TAG, "Could not close the client socket", closeException);
}
}
}
public void cancel() {
try {
mSocket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close the client socket", e);
}
}
}
注意客户端和服务端的UUID应保持一致
A2DPSinkStateMachine
A2DPSinkStateMachine
(A2DP Sink State Machine
)是Android
中用于管理A2DP
(Advanced Audio Distribution Profile
)音频音频接收端的状态机。A2DP
是一种蓝牙配置文件,用于在蓝牙设备之间传输高质量的音频流。
A2DPSinkStateMachine
负责处理A2DP Sink
设备的连接、断开连接和音频流的控制。它管理连接状态、音频焦点和音频路由等相关操作。以下是
A2DPSinkStateMachine
的几个关键状态:
- Idle(空闲状态):表示
A2DP Sink
设备处于未连接状态。- Connecting(连接中状态):表示
A2DP Sink
设备正在连接到A2DP
源设备。- Connected(已连接状态):表示
A2DP Sink
设备已成功连接到A2DP
源设备,并可以接收音频流。- Disconnecting(断开连接中状态):表示A2DP Sink设备正在与
A2DP
源设备断开连接。
A2DPSinkStateMachine
还提供了一些方法和回调事件,用于控制和监控A2DP Sink
设备的连接和音频流操作。开发人员可以使用这些方法和回调来管理A2DP Sink
设备的状态、处理连接和断开连接的操作,并执行相关的音频控制,例如音频焦点管理和音频路由控制。需要注意的是,
A2DPSinkStateMachine
是Android
框架中的一个内部组件,一般情况下,开发人员无需直接与其交互。相反,可以使用Android
提供的A2DP API
和相关类来实现对A2DP Sink
设备的操作和控制。
AvrcpControllerStateMachine
AvrcpControllerStateMachine
(AVRCP Controller State Machine
)是Android
中用于管理AVRCP
(Audio/Video Remote Control Profile
)控制器设备的状态机。AVRCP
是一种蓝牙配置文件,用于在蓝牙设备之间进行音频和视频的远程控制。
AvrcpControllerStateMachine
负责处理AVRCP
控制器设备与远程设备(如蓝牙音箱或蓝牙耳机)之间的连接、断开连接和媒体控制。它管理连接状态、媒体播放控制、元数据信息和事件通知等相关操作。以下是
AvrcpControllerStateMachine
的几个关键状态:
- Idle(空闲状态):表示
AVRCP
控制器设备处于未连接状态。- Connecting(连接中状态):表示
AVRCP
控制器设备正在连接到远程设备。- Connected(已连接状态):表示
AVRCP
控制器设备已成功连接到远程设备,并可以进行媒体控制。- Disconnecting(断开连接中状态):表示
AVRCP
控制器设备正在与远程设备断开连接。
AvrcpControllerStateMachine
还提供了一些方法和回调事件,用于控制和监控AVRCP
控制器设备与远程设备之间的连接和媒体控制操作。开发人员可以使用这些方法和回调来管理AVRCP
控制器设备的状态、处理连接和断开连接的操作,并执行相关的媒体控制,例如播放、暂停、跳转等操作。需要注意的是,
AvrcpControllerStateMachine
是Android
框架中的一个内部组件,一般情况下,开发人员无需直接与其交互。相反,可以使用Android提供的AVRCP
API
和相关类来实现对AVRCP
控制器设备的操作和控制。
BluetoothMediaBrowserService
BluetoothMediaBrowserService
是一个类似于MediaBrowserService
的Android服务类,用于与蓝牙媒体设备进行通信和交互。它提供了管理与蓝牙媒体设备连接、浏览媒体内容和控制播放等功能。
在项目中主要通过该类判断,蓝牙底层传递的音乐信息,如歌曲进度,歌曲切换等