Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีแสดงรายการเสียงแจ้งเตือนที่มีอยู่ใน Android (Ringtone Picker)

ภาพรวม

ตัวอย่างนี้สาธิตการเปิด Ringtone Picker ของระบบเพื่อให้ผู้ใช้เลือกเสียงแจ้งเตือนจากรายการที่มีอยู่ (System Ringtones + Custom Ringtones)

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → File → New Project

ขั้นตอนที่ 2: 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:onClick="setRingtone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="32dp"
        android:text="set ringtone" />

    <Button
        android:onClick="createNotification"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="16dp"
        android:text="Create notification" />
</RelativeLayout>

ขั้นตอนที่ 3: MainActivity - เปิด Ringtone Picker

package app.tutorialspoint.com.notifyme;

import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    public static final String NOTIFICATION_CHANNEL_ID = "10001";
    private final static String default_notification_channel_id = "default";
    private String chosenRingtone;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        onNewIntent(getIntent());
    }

    // เปิด System Ringtone Picker
    public void setRingtone(View view) {
        Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
        
        // ประเภทเสียง: TYPE_RINGTONE, TYPE_NOTIFICATION, TYPE_ALARM, TYPE_ALL
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
        
        // หัวข้อ Dialog
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, "Select Notification Tone");
        
        // เสียงปัจจุบัน (null = ไม่มีการเลือก)
        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
        
        // ไม่แสดงตัวเลือก "Default" (optional)
        // intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, false);
        
        // ไม่แสดงตัวเลือก "Silent" (optional)
        // intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false);
        
        startActivityForResult(intent, 5); // Request code = 5
    }

    public void createNotification(View view) {
        NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(MainActivity.this, default_notification_channel_id);

        mBuilder.setContentTitle("Notify Me");
        mBuilder.setContentText("Something important!");
        mBuilder.setSmallIcon(R.drawable.ic_launcher_foreground);
        mBuilder.setAutoCancel(true);

        // ใช้เสียงที่เลือก
        if (chosenRingtone != null) {
            mBuilder.setSound(Uri.parse(chosenRingtone));
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel notificationChannel = new NotificationChannel(
                NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
            
            if (chosenRingtone != null) {
                notificationChannel.setSound(Uri.parse(chosenRingtone), null);
            }
            
            mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
            assert mNotificationManager != null;
            mNotificationManager.createNotificationChannel(notificationChannel);
        }

        assert mNotificationManager != null;
        mNotificationManager.notify((int) System.currentTimeMillis(), mBuilder.build());
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == Activity.RESULT_OK && requestCode == 5) {
            Uri uri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
            if (uri != null) {
                this.chosenRingtone = uri.toString();
                Toast.makeText(this, "Selected: " + uri.getLastPathSegment(), Toast.LENGTH_SHORT).show();
            } else {
                this.chosenRingtone = null;
                Toast.makeText(this, "Default tone selected", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

ขั้นตอนที่ 4: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.tutorialspoint.com.notifyme">

    <uses-permission android:name="android.permission.VIBRATE" />

    <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>

RingtoneManager EXTRA Parameters

Extra Keyประเภทคำอธิบาย
EXTRA_RINGTONE_TYPEintTYPE_RINGTONE(1), TYPE_NOTIFICATION(2), TYPE_ALARM(4), TYPE_ALL(-1)
EXTRA_RINGTONE_TITLEStringหัวข้อ Dialog Picker
EXTRA_RINGTONE_EXISTING_URIUriURI เสียงที่เลือกอยู่ (สำหรับ Pre-select)
EXTRA_RINGTONE_SHOW_DEFAULTbooleanแสดงตัวเลือก "Default" (default: true)
EXTRA_RINGTONE_SHOW_SILENTbooleanแสดงตัวเลือก "Silent" (default: true)
EXTRA_RINGTONE_PICKED_URIUri (Result)URI ที่ผู้ใช้เลือก (ใน onActivityResult)

Ringtone Type Constants

// ใน RingtoneManager
public static final int TYPE_RINGTONE = 1;      // เสียงโทรเข้า
public static final int TYPE_NOTIFICATION = 2;  // เสียงแจ้งเตือน (Notification)
public static final int TYPE_ALARM = 4;         // เสียงนาฬิกาปลุก
public static final int TYPE_ALL = -1;          // ทั้งหมดรวมกัน

// ใช้รวมได้ (Bitwise OR)
// TYPE_RINGTONE | TYPE_NOTIFICATION = 3 (โทร + แจ้งเตือน)

การใช้งานขั้นสูง

1. Pre-select เสียงปัจจุบัน

// ดึงเสียงปัจจุบันจาก Settings
Uri currentTone = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION);

Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION);
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, currentTone); // Pre-select
startActivityForResult(intent, REQUEST_CODE);

2. Custom Ringtone Picker (สร้างเอง)

หากต้องการ UI เฉพาะตัว ใช้ RingtoneManager.getRingtone() และสร้าง ListView/RecyclerView เอง

// ดึงรายการ Ringtone ทั้งหมด
RingtoneManager manager = new RingtoneManager(this);
manager.setType(RingtoneManager.TYPE_NOTIFICATION);
Cursor cursor = manager.getCursor();

while (cursor.moveToNext()) {
    String title = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
    Uri uri = manager.getRingtoneUri(cursor.getPosition());
    // เพิ่มลงใน Adapter
}

3. ใช้กับ Notification Channel (Android 8.0+)

// บันทึก URI ที่เลือกไว้ใน SharedPreferences
SharedPreferences prefs = getSharedPreferences("notification_prefs", MODE_PRIVATE);
prefs.edit().putString("ringtone_uri", chosenRingtone).apply();

// ตอนสร้าง Channel อ่านค่ามาใช้
String savedUri = prefs.getString("ringtone_uri", null);
if (savedUri != null) {
    channel.setSound(Uri.parse(savedUri), new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
        .build());
}

ข้อควรระวัง

  • Request Code: ใช้ค่าที่ไม่ซ้ำกันในแอป (ในตัวอย่างใช้ 5)
  • onActivityResult Deprecated: Android 13+ (API 33+) ควรใช้ ActivityResultContracts แทน
  • Emulator: อาจไม่มี Ringtone ให้เลือก ต้องทดสอบบนอุปกรณ์จริง
  • OEM Customization: Samsung, Xiaomi, Oppo อาจมี Ringtone Picker UI ต่างจาก Stock Android
  • Permission: ไม่ต้องการ Permission เพิ่มเติมสำหรับ Ringtone Picker

Modern API (Android 13+ / API 33+)

// ใช้ ActivityResultLauncher แทน startActivityForResult
ActivityResultLauncher ringtonePickerLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
            Uri uri = result.getData().getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
            // Handle URI
        }
    }
);

// เรียกใช้
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
// ... putExtras ...
ringtonePickerLauncher.launch(intent);