Giới thiệu
Bài viết này hướng dẫn cách kiểm tra trạng thái kết nối Bluetooth (đã cắm/đã ngắt) trên Android bằng BroadcastReceiver lắng nghe các action: ACTION_ACL_CONNECTED, ACTION_ACL_DISCONNECTED, ACTION_ACL_DISCONNECT_REQUESTED.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Thiết kế giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center">
<TextView
android:id="@+id/tvStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Đang kiểm tra Bluetooth..."
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Mở cài đặt Bluetooth và kết nối/ngắt thiết bị để test"
android:textSize="14sp"
android:gravity="center" />
</LinearLayout>
Bước 3: Viết code kiểm tra (src/MainActivity.java)
import androidx.appcompat.app.AppCompatActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private TextView tvStatus;
private BluetoothAdapter bluetoothAdapter;
private BroadcastReceiver bluetoothReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvStatus = findViewById(R.id.tvStatus);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
tvStatus.setText("Thiết bị không hỗ trợ Bluetooth");
return;
}
// Kiểm tra trạng thái hiện tại
updateStatus(bluetoothAdapter.isEnabled() ? "Bluetooth: BẬT" : "Bluetooth: TẮT");
// BroadcastReceiver cho trạng thái kết nối thiết bị
bluetoothReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String deviceName = device != null ? device.getName() : "Unknown";
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)) {
String msg = "Đã kết nối: " + deviceName;
updateStatus(msg);
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
} else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
String msg = "Đã ngắt kết nối: " + deviceName;
updateStatus(msg);
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
} else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(action)) {
// Đang trong quá trình ngắt kết nối
updateStatus("Đang ngắt kết nối: " + deviceName);
}
}
};
// Đăng ký receiver
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
// Thêm cả state change của adapter
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(bluetoothReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bluetoothReceiver != null) {
unregisterReceiver(bluetoothReceiver);
}
}
private void updateStatus(String message) {
runOnUiThread(() -> tvStatus.setText(message));
}
}
Bước 4: Manifest (androidManifest.xml)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="app.com.sample">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ (API 31+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị thật (emulator không hỗ trợ Bluetooth thật), nhấn Run. Bật Bluetooth, kết nối tai nghe/loa -> thấy Toast "Đã kết nối". Ngắt kết nối -> thấy "Đã ngắt kết nối".
Quyền Bluetooth theo phiên bản Android
| Android Version | API Level | Permissions Required |
|---|---|---|
| Android 11 và cũ hơn | ≤ 30 | BLUETOOTH, BLUETOOTH_ADMIN |
| Android 12 (S) | 31 | BLUETOOTH_CONNECT, BLUETOOTH_SCAN (runtime) |
| Android 13+ (T+) | 33+ | BLUETOOTH_CONNECT, BLUETOOTH_SCAN + BLUETOOTH_ADVERTISE nếu cần |
Runtime Permission (Android 12+)
// Kiểm tra và yêu cầu quyền runtime
private void checkBluetoothPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
String[] permissions = {
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_SCAN
};
for (String perm : permissions) {
if (checkSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(permissions, REQUEST_CODE_BLUETOOTH);
return;
}
}
}
// Permission granted, proceed
initBluetooth();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_BLUETOOTH) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initBluetooth();
}
}
}
Lấy danh sách thiết bị đã ghép đôi (Bonded)
// Lấy tất cả thiết bị đã paired SetbondedDevices = bluetoothAdapter.getBondedDevices(); for (BluetoothDevice device : bondedDevices) { String name = device.getName(); String address = device.getAddress(); // MAC address int bondState = device.getBondState(); // BOND_BONDED, BOND_BONDING, BOND_NONE // Kiểm tra kết nối hiện tại (cần connect socket hoặc dùng BroadcastReceiver như trên) }
Kiểm tra kết nối Profile cụ thể (A2DP, HFP, HID...)
// Cần BLUETOOTH_PRIVILEGED (system app) hoặc dùng Reflection
// Hoặc dùng BluetoothProfile.ServiceListener (API 11+)
bluetoothAdapter.getProfileProxy(this, new BluetoothProfile.ServiceListener() {
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
// Kiểm tra thiết bị đang kết nối A2DP (audio streaming)
for (BluetoothDevice device : proxy.getConnectedDevices()) {
// device đang phát nhạc
}
}
}
@Override
public void onServiceDisconnected(int profile) {}
}, BluetoothProfile.A2DP);
Lưu ý quan trọng
- BroadcastReceiver chỉ nhận khi app chạy (foreground). Muốn nhận khi app background/killed: dùng
BluetoothAdapter.setBluetoothPolicy()hoặcCompanionDeviceManager. - Không thể liệt kê thiết bị đang kết nối trực tiếp từ BluetoothAdapter public API (cần reflection hoặc Profile Proxy).
- Luôn
unregisterReceivertrongonDestroy. - Test trên thiết bị thật - emulator không có Bluetooth hardware.