Hướng dẫn này trình bày cách mở trình chọn chuông báo hệ thống (RingtonePicker) từ Activity và lấy URI chuông báo được chọn. Sử dụng RingtoneManager.ACTION_RINGTONE_PICKER intent.
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: Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<Button
android:id="@+id/btnSelRingtone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Chọn chuông báo" />
<TextView
android:id="@+id/tvRingtone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_below="@id/btnSelRingtone"
android:textStyle="bold|italic"
android:text="Đường dẫn chuông báo" />
</RelativeLayout>
Bước 3: Code MainActivity (src/MainActivity.java)
import android.annotation.SuppressLint;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
Button btn;
TextView txtView;
private static final int REQUEST_RINGTONE = 999;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btnSelRingtone);
txtView = findViewById(R.id.tvRingtone);
btn.setOnClickListener(v -> {
// Lấy chuông báo mặc định hiện tại (loại ALARM làm ví dụ)
Uri currentTone = RingtoneManager.getActualDefaultRingtoneUri(
MainActivity.this, RingtoneManager.TYPE_ALARM);
// Tạo intent mở Ringtone Picker
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Chọn chuông báo");
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentTone);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false); // Không hiện "None"
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true); // Hiện "Default"
startActivityForResult(intent, REQUEST_RINGTONE);
});
}
@SuppressLint("SetTextI18n")
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_RINGTONE && resultCode == RESULT_OK) {
Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
if (uri != null) {
txtView.setText("Đã chọn: " + uri.toString());
// Có thể set làm chuông báo mặc định:
// RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE, uri);
} else {
txtView.setText("Đã chọn: Mặc định (Default)");
}
} else if (resultCode == RESULT_CANCELED) {
txtView.setText("Đã hủy chọn");
}
}
}
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"
xmlns:tools="https://schemas.android.com/tools"
package="app.com.sample">
<!-- Quyền WRITE_SETTINGS cần thiết để THAY ĐỔI cài đặt hệ thống (set ringtone mặc định) -->
<uses-permission
android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<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>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Lưu ý: QuyềnWRITE_SETTINGSlà quyền đặc biệt (special permission), từ Android 6.0 (API 23) yêu cầu người dùng cấp qua màn hình Settings đặc biệt. Chỉ cần nếu bạn gọiRingtoneManager.setActualDefaultRingtoneUri(). Chỉ chọn (picker) không cần quyền này.
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn "Chọn chuông báo" → hệ thống mở danh sách chuông → chọn một cái → URI hiển thị trên TextView.

Các loại chuông báo (RingtoneManager.TYPE_*)
| Hằng số | Mô tả |
|---|---|
TYPE_RINGTONE |
Chuông gọi đến (mặc định) |
TYPE_NOTIFICATION |
Thông báo (SMS, app...) |
TYPE_ALARM |
Báo thức |
TYPE_ALL |
Tất cả các loại trên |
Extra quan trọng cho Intent
| Extra | Kiểu | Mô tả |
|---|---|---|
EXTRA_RINGTONE_TYPE |
int | Loại chuông hiển thị (TYPE_RINGTONE, NOTIFICATION, ALARM, ALL) |
EXTRA_RINGTONE_TITLE |
String | Tiêu đề dialog picker |
EXTRA_RINGTONE_EXISTING_URI |
Uri | Chuông hiện tại được chọn sẵn (highlight) |
EXTRA_RINGTONE_SHOW_SILENT |
boolean | Hiện mục "None" (không chuông) |
EXTRA_RINGTONE_SHOW_DEFAULT |
boolean | Hiện mục "Default" (chuông mặc định hệ thống) |
EXTRA_RINGTONE_PICKED_URI |
Uri (return) | URI chuông được chọn (trong onActivityResult) |
Set chuông báo mặc định lập trình (Cần WRITE_SETTINGS)
// Kiểm tra quyền WRITE_SETTINGS (API 23+)
if (Settings.System.canWrite(this)) {
RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE, uri);
Toast.makeText(this, "Đã đặt làm chuông mặc định", Toast.LENGTH_SHORT).show();
} else {
// Yêu cầu người dùng cấp quyền qua Settings
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
Phát chuông báo (Preview)
// Phát chuông từ URI Ringtone ringtone = RingtoneManager.getRingtone(context, uri); ringtone.play(); // Dừng ringtone.stop();