Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách đóng panel thông báo khi bấm nút trên thông báo Android

Giới thiệu

Khi thêm Action button vào thông báo (qua addAction()), panel thông báo (notification shade) mặc định **không tự đóng** sau khi bấm nút. Bài này hướng dẫn cách buộc đóng panel bằng cách gửi broadcastIntent với Intent.ACTION_CLOSE_SYSTEM_DIALOGS.

Yêu cầu

  • Android 5.0+ (API 21) cho Action button
  • Quyền android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS (chỉ system apps được cấp, ứng dụng thường **không thể** dùng action này từ API 23+)
⚠️ Lưu ý quan trọng: Từ Android 6.0 (Marshmallow), Google hạn chế quyền BROADCAST_CLOSE_SYSTEM_DIALOGS chỉ cho system apps. Ứng dụng thông thường **không thể** ép đóng notification shade bằng cách này. Giải pháp thay thế: dùng setAutoCancel(true) trên action's PendingIntent (chỉ đóng thông báo đó, không đóng toàn bộ panel).

Cách làm (chỉ dành cho system apps / rooted devices)

1. Tạo BroadcastReceiver để đóng panel

public class ClosePanelReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Chỉ system apps mới có hiệu lực
        Intent closeDialogs = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        context.sendBroadcast(closeDialogs);
    }
}

2. Đăng ký trong Manifest

<receiver android:name=".ClosePanelReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="com.example.CLOSE_NOTIFICATION_PANEL" />
    </intent-filter>
</receiver>

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

3. Gán vào Action button

Intent closeIntent = new Intent("com.example.CLOSE_NOTIFICATION_PANEL");
PendingIntent closePendingIntent = PendingIntent.getBroadcast(
        this, 0, closeIntent, PendingIntent.FLAG_IMMUTABLE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_launcher)
        .setContentTitle("Có nút bấm")
        .setContentText("Bấm nút sẽ cố gắng đóng panel")
        .addAction(R.drawable.ic_close, "Đóng panel", closePendingIntent)
        .setAutoCancel(true);

Giải pháp thực tế cho ứng dụng thông thường

Vì không thể ép đóng toàn bộ panel, hãy thiết kế UX phù hợp:

  1. Dùng setAutoCancel(true): Thông báo biến mất sau khi bấm action → panel gọn nhẹ hơn.
  2. Mở Activity với FLAG_ACTIVITY_NEW_TASK: Chuyển người dùng sang app, panel tự thu gọn.
  3. Foreground Service với ongoing notification: Dành cho media player, download manager.

Ví dụ thực tế: Nút "Đọc sau" / "Xóa"

// Nút "Đọc sau" - mở app, đánh dấu đã đọc
Intent readLaterIntent = new Intent(this, ArticleActivity.class);
readLaterIntent.putExtra("action", "read_later");
readLaterIntent.putExtra("article_id", articleId);
PendingIntent readLaterPI = PendingIntent.getActivity(this, 1, readLaterIntent, 
        PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

// Nút "Xóa" - chỉ xóa thông báo, không mở app
Intent dismissIntent = new Intent(this, NotificationActionReceiver.class);
dismissIntent.setAction("DISMISS");
dismissIntent.putExtra("notification_id", notificationId);
PendingIntent dismissPI = PendingIntent.getBroadcast(this, 2, dismissIntent, 
        PendingIntent.FLAG_IMMUTABLE);

builder.addAction(R.drawable.ic_bookmark, "Đọc sau", readLaterPI)
       .addAction(R.drawable.ic_delete, "Xóa", dismissPI)
       .setAutoCancel(false); // Giữ thông báo nếu bấm "Đọc sau"

Kết luận

Không thể đóng hoàn toàn notification shade từ app thường do chính sách bảo mật Android. Hãy tập trung vào trải nghiệm người dùng: tự xóa thông báo sau hành động, hoặc chuyển sang app để panel tự thu.