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

วิธีเพิ่ม Vibration และ Sound ให้ Notification ใน Android

ภาพรวม

การเพิ่มการสั่น (Vibration) และเสียง (Sound) ให้ Notification ช่วยดึงดูดความสนใจผู้ใช้ได้ดีขึ้น ตั้งแต่ Android 8.0 (API 26) ต้องตั้งค่าทั้งสองที่ Notification Channel ส่วน API เก่าตั้งที่ Builder โดยตรงได้

ตัวอย่าง: Notification พร้อม Vibration Pattern และ Sound

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

Android Studio → New Project → Empty Activity (Package: app.tutorialspoint.com.notifyme)

ขั้นตอนที่ 2: Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnCreateNotification"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Create notification with Vibration & Sound"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

ขั้นตอนที่ 3: MainActivity.java

package app.tutorialspoint.com.notifyme;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import androidx.core.app.NotificationCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    private static final String CHANNEL_ID = "vibration_sound_channel";
    private static final String DEFAULT_CHANNEL_ID = "default";

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

        createNotificationChannel();

        Button btnCreateNotification = findViewById(R.id.btnCreateNotification);
        btnCreateNotification.setOnClickListener(v -> createNotificationWithVibrationAndSound());
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "Vibration & Sound Notifications",
                    NotificationManager.IMPORTANCE_HIGH
            );
            channel.setDescription("Notifications with custom vibration pattern and sound");

            // 1. ตั้งค่า Vibration Pattern ที่ Channel Level
            // รูปแบบ: {delay, vibrate, sleep, vibrate, sleep...} หน่วยเป็น milliseconds
            // ตัวอย่าง: สั่น 1 วิ, หยุด 1 วิ, สั่น 1 วิ, หยุด 1 วิ, สั่น 1 วิ (รวม 5 วิ)
            long[] vibrationPattern = {0, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000};
            channel.enableVibration(true);
            channel.setVibrationPattern(vibrationPattern);

            // 2. ตั้งค่า Sound ที่ Channel Level
            Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            channel.setSound(alarmSound, new android.media.AudioAttributes.Builder()
                    .setUsage(android.media.AudioAttributes.USAGE_NOTIFICATION)
                    .setContentType(android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .build());

            // 3. ตั้งค่าเพิ่มเติม
            channel.enableLights(true);
            channel.setLightColor(android.graphics.Color.GREEN);
            channel.setLockscreenVisibility(android.app.Notification.VISIBILITY_PUBLIC);

            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }

    private void createNotificationWithVibrationAndSound() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("Vibration & Sound Alert")
                .setContentText("This notification has custom vibration pattern and sound")
                .setPriority(NotificationCompat.PRIORITY_HIGH)
                .setAutoCancel(true)
                // Fallback สำหรับ API < 26 (ยังทำงานได้แต่ Channel มีความสำคัญมากกว่า)
                .setVibrate(new long[]{0, 1000, 1000, 1000, 1000, 1000})
                .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));

        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        int notificationId = (int) System.currentTimeMillis();
        manager.notify(notificationId, builder.build());
    }
}

ขั้นตอนที่ 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" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <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>

Vibration Pattern - การออกแบบรูปแบบการสั่น

รูปแบบ Array: long[] {delay, vibrate, sleep, vibrate, sleep, ...}

  • ค่าตัวแรก (index 0): **Delay** ก่อนเริ่มสั่นครั้งแรก (มักเป็น 0)
  • ค่าคี่ (index 1, 3, 5...): **ระยะเวลาสั่น** (Vibrate ON) - milliseconds
  • ค่าคู่ (index 2, 4, 6...): **ระยะเวลาหยุด** (Sleep/OFF) - milliseconds

ตัวอย่าง Pattern

Patternผลลัพธ์
{0, 500}สั่น 0.5 วิ แล้วหยุด (สั่นครั้งเดียวสั้น)
{0, 200, 100, 200}สั่น 0.2วิ หยุด 0.1วิ สั่น 0.2วิ (Double tap)
{0, 1000, 1000, 1000, 1000, 1000}สั่น 1วิ หยุด 1วิ สั่น 1วิ หยุด 1วิ สั่น 1วิ (Heartbeat)
{0, 500, 500, 500, 500, 500, 500, 500, 500}สั่นสั้นๆ ติดกัน 4 ครั้ง (Urgent)

Predefined Patterns (ไม่ต้องสร้างเอง)

// ใช้ VibrationEffect (API 26+)
VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE); // สั่นครั้งเดียว
VibrationEffect.createWaveform(new long[]{0, 500, 1000}, -1); // วงจรซ้ำ (-1 = ไม่ซ้ำ, 0 = ซ้ำตลอด)

// สำหรับ Notification Channel
channel.setVibrationPattern(new long[]{0, 500, 1000});

Sound - การตั้งค่าเสียง

1. เสียง Default ของระบบ

Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
channel.setSound(defaultSound, audioAttributes);

2. เสียง Custom (res/raw/)

Uri customSound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + 
        getPackageName() + "/raw/custom_notification.mp3");
channel.setSound(customSound, audioAttributes);

3. ไม่มีเสียง (Silent)

// ไม่เรียก setSound() หรือ
channel.setSound(null, null);

Permission VIBRATE

ต้องประกาศใน Manifest:

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

ไม่ต้องขอ Runtime Permission (Normal Permission)

การทดสอบ

  1. รันแอปบนอุปกรณ์จริง (Emulator ไม่มี Motor สั่น)
  2. กดปุ่มสร้าง Notification
  3. สังเกต: อุปกรณ์สั่นตาม Pattern (1วิ สั่น, 1วิ หยุด, ซ้ำ 3 รอบ) และมีเสียงแจ้งเตือน
  4. ลองตั้งโหมด Silent/Vibrate Only → ทดสอบอีกครั้ง
  5. ไป Settings → Notifications → Channel → ปิด Vibration/Sound → ทดสอบว่าหยุดทำงาน

ข้อควรพิจารณา

  • ผู้ใช้ควบคุมได้: User ปิด Vibration/Sound ของ Channel ได้ใน Settings
  • Do Not Disturb: ในโหมด DND การสั่นและเสียงอาจถูกบล็อก (ขึ้นอยู่กับ Policy และ Importance)
  • Battery: การสั่นนาน/บ่อย ใช้แบตเตอรี่มาก
  • Accessibility: ผู้ใช้บางคนอาจปิดการสั่นทั้งระบบ
  • Fallback: ใส่ setVibrate/setSound ใน Builder ด้วยสำหรับ API < 26
แนวทางปฏิบัติ: ใช้ Vibration Pattern ที่สื่อความหมาย (Heartbeat = Urgent, Double tap = Message, Long = Call) และทดสอบบนอุปกรณ์จริงหลายรุ่น