ภาพรวม
คำถามนี้ถามถึงการใส่ EditText ใน Notification แต่ EditText ใน RemoteViews ไม่สามารถรับ Input ได้จริง บทความนี้อธิบายข้อจำกัดและเสนอวิธีที่ถูกต้องคือ RemoteInput
ทำไม EditText ใน Notification ไม่ทำงาน?
| ปัญหา | สาเหตุ |
|---|---|
| ไม่สามารถพิมพ์ได้ | RemoteViews ไม่สร้าง Input Connection ให้ EditText |
| ไม่ได้รับ Focus | Notification UI ไม่อนุญาตให้ View ใน RemoteViews รับ Focus |
| Keyboard ไม่ขึ้น | ระบบไม่รองรับ Soft Keyboard ใน Notification Shade แบบ Custom Layout |
| Security | ป้องกัน Keylogger และ UI Spoofing |
วิธีที่ถูกต้อง: ใช้ RemoteInput (API 24+)
RemoteInput เป็น API มาตรฐานของ Android สำหรับรับข้อมูลจาก Notification โดยตรง
1. เพิ่ม Dependency (ถ้ายังไม่มี)
// build.gradle
dependencies {
implementation "androidx.core:core:1.12.0"
// RemoteInput อยู่ใน androidx.core.app.RemoteInput
}
2. สร้าง Notification พร้อม RemoteInput
public void createNotificationWithInput(View view) {
// Key สำหรับดึงข้อมูลที่ผู้ใช้พิมพ์
final String KEY_REPLY = "key_reply";
// สร้าง RemoteInput
RemoteInput remoteInput = new RemoteInput.Builder(KEY_REPLY)
.setLabel("พิมพ์ข้อความตอบกลับ...")
.setChoices(new String[]{"ตกลง", "ไม่ตกลง", "ภายหลัง"}) // Quick replies (optional)
.build();
// PendingIntent สำหรับรับผลลัพธ์ (ใช้ BroadcastReceiver หรือ Activity)
Intent replyIntent = new Intent(this, NotificationReplyReceiver.class);
replyIntent.setAction("REPLY_ACTION");
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
this, 0, replyIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
// สร้าง Action
NotificationCompat.Action action = new NotificationCompat.Action.Builder(
R.drawable.ic_reply_icon, "ตอบกลับ", replyPendingIntent)
.addRemoteInput(remoteInput)
.setAllowGeneratedReplies(true)
.setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
.build();
// สร้าง Notification ด้วย MessagingStyle (เหมาะสำหรับแชท)
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("ฉัน")
.setConversationTitle("การสนทนา")
.addMessage("สวัสดี! มีอะไรให้ช่วยไหม?", System.currentTimeMillis() - 10000, "ผู้อื่น")
.addMessage("ขอสอบถามหน่อยครับ", System.currentTimeMillis(), "ฉัน");
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setStyle(messagingStyle)
.addAction(action)
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_MESSAGE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
3. BroadcastReceiver รับข้อมูล
public class NotificationReplyReceiver extends BroadcastReceiver {
private static final String KEY_REPLY = "key_reply";
@Override
public void onReceive(Context context, Intent intent) {
if ("REPLY_ACTION".equals(intent.getAction())) {
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
if (remoteInput != null) {
CharSequence replyText = remoteInput.getCharSequence(KEY_REPLY);
if (replyText != null) {
String userReply = replyText.toString();
// ประมวลผลข้อความตอบกลับ
Log.d("NOTIFICATION_REPLY", "User replied: " + userReply);
// ส่งต่อไปยัง Server, Database, หรืออัปเดต UI
processReply(context, userReply);
}
}
}
}
private void processReply(Context context, String reply) {
// TODO: Implement your logic here
// e.g., send to API, save to DB, update UI via EventBus/LiveData
}
}
4. ลงทะเบียน Receiver ใน Manifest
<receiver
android:name=".NotificationReplyReceiver"
android:exported="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="REPLY_ACTION" />
</intent-filter>
</receiver>
ตัวเลือกอื่น: ใช้ Activity แทน BroadcastReceiver
// ใช้ Activity แทน Receiver (สำหรับกรณีซับซ้อน)
Intent replyIntent = new Intent(this, ReplyActivity.class);
PendingIntent replyPendingIntent = PendingIntent.getActivity(
this, 0, replyIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);
// ใน ReplyActivity.onCreate()
Bundle remoteInput = RemoteInput.getResultsFromIntent(getIntent());
if (remoteInput != null) {
String reply = remoteInput.getCharSequence(KEY_REPLY).toString();
// ประมวลผล...
finish(); // ปิด Activity ทันที
}
เปรียบเทียบ: EditText vs RemoteInput
| คุณสมบัติ | EditText ใน RemoteViews | RemoteInput (มาตรฐาน) |
|---|---|---|
| รับ Input ได้จริง | ❌ ไม่ได้ | ✅ ได้ |
| แสดง Keyboard | ❌ ไม่ได้ | ✅ ได้ (Inline) |
| Quick Replies | ❌ ไม่ได้ | ✅ รองรับ (setChoices) |
| Voice Input | ❌ ไม่ได้ | ✅ รองรับ (setAllowFreeFormInput) |
| รองรับ Android Version | ไม่ทำงานทุก Version | API 24+ (Android 7.0+) |
| UI Consistency | แตกต่างจากระบบ | เข้ากับ System UI |
ขั้นสูง: Smart Reply (ML Kit)
// ใช้ ML Kit Smart Reply สร้าง Quick Replies อัตโนมัติ
SmartReplyGenerator generator = SmartReply.getClient();
generator.suggestReplies(conversation)
.addOnSuccessListener(result -> {
if (result.getStatus() == SmartReplySuggestionResult.STATUS_SUCCESS) {
List suggestions = result.getSuggestions();
String[] quickReplies = suggestions.stream()
.map(SmartReplySuggestion::getText)
.toArray(String[]::new);
// นำไปใช้กับ RemoteInput.setChoices(quickReplies)
}
});
สรุป
- อย่าใช้ EditText ใน Custom Notification Layout - ไม่ทำงาน
- ใช้ RemoteInput + Action + MessagingStyle - วิธีมาตรฐาน ทำงานได้จริง
- รองรับ Quick Replies, Voice Input, Smart Reply - ประสบการณ์ผู้ใช้ดีที่สุด
- ทดสอบบน Android 7.0+ - RemoteInput ต้องการ API 24+