ภาพรวม
การเพิ่มการสั่น (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)
การทดสอบ
- รันแอปบนอุปกรณ์จริง (Emulator ไม่มี Motor สั่น)
- กดปุ่มสร้าง Notification
- สังเกต: อุปกรณ์สั่นตาม Pattern (1วิ สั่น, 1วิ หยุด, ซ้ำ 3 รอบ) และมีเสียงแจ้งเตือน
- ลองตั้งโหมด Silent/Vibrate Only → ทดสอบอีกครั้ง
- ไป 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) และทดสอบบนอุปกรณ์จริงหลายรุ่น