Giới thiệu
Bài viết này hướng dẫn cách phát hiện khi người dùng cắm hoặc rút tai nghe (headset/earphone) vào jack 3.5mm hoặc cổng USB-C trên thiết bị Android bằng BroadcastReceiver lắng nghe action ACTION_HEADSET_PLUG.
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"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Phát hiện cắm/rút tai nghe"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
Bước 3: Viết code phát hiện (src/MainActivity.java)
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private BroadcastReceiver headsetReceiver;
private boolean isHeadsetPlugged = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
headsetReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_HEADSET_PLUG.equals(action)) {
int state = intent.getIntExtra("state", -1);
int microphone = intent.getIntExtra("microphone", 0);
String name = intent.getStringExtra("name");
if (state == 1) {
isHeadsetPlugged = true;
String msg = "Tai nghe đã cắm" + (microphone == 1 ? " (có mic)" : "");
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
} else if (state == 0) {
isHeadsetPlugged = false;
Toast.makeText(context, "Tai nghe đã rút ra", Toast.LENGTH_SHORT).show();
}
// Có thể gửi event cho các component khác qua EventBus/LiveData/RxJava
}
}
};
// Đăng ký receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
registerReceiver(headsetReceiver, filter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Quan trọng: Hủy đăng ký để tránh memory leak
if (headsetReceiver != null) {
unregisterReceiver(headsetReceiver);
}
}
}
Bước 4: Cấu hình 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" />
<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ị, nhấn Run. Cắm/rút tai nghe để thấy Toast thông báo. Lưu ý: Cần test trên thiết bị thật, emulator có thể không mô phỏng jack tai nghe.
Giải thích các extra trong Intent
| Extra Key | Giá trị | Mô tả |
|---|---|---|
state |
0 hoặc 1 | 0 = rút ra, 1 = cắm vào |
microphone |
0 hoặc 1 | 1 = tai nghe có mic, 0 = không có mic |
name |
String | Tên thiết bị âm thanh (ví dụ: "Headset", "USB Audio Device") |
Lưu ý quan trọng
- Phải hủy đăng ký receiver trong onDestroy() để tránh memory leak và crash.
ACTION_HEADSET_PLUGlà sticky broadcast: khi đăng ký, bạn nhận ngay trạng thái hiện tại.- Không cần khai báo trong Manifest, đăng ký động (dynamic registration) trong code là đủ.
- Từ Android 10 (API 29), broadcast này bị hạn chế, nhưng vẫn hoạt động cho ứng dụng đang chạy (foreground).
- Bluetooth headset dùng action khác:
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED. - USB-C audio/HDMI audio cũng kích hoạt broadcast này.
Mở rộng: Kiểm tra trạng thái hiện tại bất kỳ lúc nào
// Kiểm tra trạng thái ngay lập tức mà không cần chờ broadcast
public boolean isHeadsetConnected(Context context) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
return audioManager.isWiredHeadsetOn();
}