Comment ignorer la notification après avoir cliqué sur l'action


143

Depuis le niveau d'API 16 (Jelly Bean), il est possible d'ajouter des actions à une notification avec

builder.addAction(iconId, title, intent);

Mais lorsque j'ajoute une action à une notification et que l'action est activée, la notification ne sera pas rejetée. Lorsque vous cliquez sur la notification elle-même, elle peut être rejetée avec

notification.flags = Notification.FLAG_AUTO_CANCEL;

ou

builder.setAutoCancel(true);

Mais évidemment, cela n'a rien à voir avec les actions associées à la notification.

Des indices? Ou cela ne fait-il pas encore partie de l'API? J'ai rien trouvé.

Réponses:


155

Lorsque vous avez appelé notifier sur le gestionnaire de notifications, vous lui avez donné un identifiant - c'est l'identifiant unique que vous pouvez utiliser pour y accéder plus tard (cela provient du gestionnaire de notifications:

notify(int id, Notification notification)

Pour annuler, vous appelleriez:

cancel(int id)

avec le même identifiant. Donc, fondamentalement, vous devez garder une trace de l'id ou éventuellement mettre l'id dans un bundle que vous ajoutez à l'intention à l'intérieur de PendingIntent?


25
Merci, cela a résolu mon problème. Cependant, je pense toujours que c'est un peu trop compliqué. Au lieu de simplement fournir une API pour rejeter automatiquement la notification lorsqu'une action est activée, vous devez travailler avec l'intention et l'ID de notification pour obtenir la même chose.
endowzoner

2
Si vous pensez que c'est compliqué, ne cherchez pas à mettre à jour une notification (ne perdez pas la trace de cet identifiant), ou à vérifier s'il est affiché ou non (l'API ne le suit pas, vous devez le faire) ...: P
Travis

2
@Daksh: Fondamentalement, vous ajoutez la balise de notification et l'ID à votre intention qui démarre lorsque vous appuyez sur votre action. Avec ces informations supplémentaires, vous pouvez vérifier dans l'activité de démarrage si elle a été lancée via une action de notification.
endowzoner

5
Exemple de code de onCreate (): Bundle extras = getIntent (). GetExtras (); if (extras! = null) {String tag = extras.getString (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_TAG); int id = extras.getInt (NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); if (NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATION_TAG.equals (tag)) {// l'activité a été démarrée via une action de notification, ignorer // notification NotificationManager manager = (NotificationManager) getSystemService (Service.NOTIFICATION_SERVICE); manager.cancel (tag, id); }}
endowzoner

1
Dans la nouvelle API, vous avez notifié (balise String, identifiant int, notification de notification) et annulez en conséquence (balise chaîne, identifiant int)
Malachiasz

64

J'ai trouvé que c'était un problème lors de l'utilisation de la notification d'affichage tête haute de Lollipop. Voir les directives de conception . Voici le code complet (ish) à implémenter.

Jusqu'à présent, avoir un bouton «Ignorer» était moins important, mais maintenant c'est plus dans votre visage.

notification en tête

Construire la notification

int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, context);

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(NotificationCompat.PRIORITY_MAX) //HIGH, MAX, FULL_SCREEN and setDefaults(Notification.DEFAULT_ALL) will make it a Heads Up Display Style
        .setDefaults(Notification.DEFAULT_ALL) // also requires VIBRATE permission
        .setSmallIcon(R.drawable.ic_action_refresh) // Required!
        .setContentTitle("Message from test")
        .setContentText("message")
        .setAutoCancel(true)
        .addAction(R.drawable.ic_action_cancel, "Dismiss", dismissIntent)
        .addAction(R.drawable.ic_action_boom, "Action!", someOtherPendingIntent);

// Gets an instance of the NotificationManager service
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

// Builds the notification and issues it.
notifyMgr.notify(notificationId, builder.build());

NotificationActivité

public class NotificationActivity extends Activity {

    public static final String NOTIFICATION_ID = "NOTIFICATION_ID";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(getIntent().getIntExtra(NOTIFICATION_ID, -1));
        finish(); // since finish() is called in onCreate(), onDestroy() will be called immediately
    }

    public static PendingIntent getDismissIntent(int notificationId, Context context) {
        Intent intent = new Intent(context, NotificationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.putExtra(NOTIFICATION_ID, notificationId);
        PendingIntent dismissIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        return dismissIntent;
    }

}

AndroidManifest.xml (attributs requis pour empêcher SystemUI de se concentrer sur une pile arrière)

<activity
    android:name=".NotificationActivity"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>

J'ai plusieurs notifications d'une application et la notification est définie sur notification continue. Je veux effacer la notification lorsque l'addaction s'exécute sur la notification relative
Prasad

3
Ne serait-il pas plus efficace d'utiliser un BroadcastReceiver ici pour rejeter la notification à la place? Voici un bon exemple qui montre l'implémentation, mais il peut être encore réduit: stackoverflow.com/a/19745745/793150
alice.harrison

1
Les solutions fonctionnent, sauf que les extras sont envoyés avec l'intention. Ils ne sont pas transmis à onCreate. Une façon consiste à utiliser des variables statiques. Quelqu'un sait-il pourquoi les extras d'intention ne sont pas transmis?
Baschi

Pourquoi getDismissIntent ne fonctionne-t-il que lorsqu'il est placé dans NotificationActivity? L'intention de rejet ne fonctionne pas si le code de création PendingIntent est placé dans la classe de générateur de notification. Je viens de passer 2 heures sur ce problème et je ne peux pas comprendre pourquoi l'intention en attente DOIT être créée dans l'activité. Quelqu'un peut-il expliquer pourquoi c'est le cas?
Ray Li

getDismissIntent () est une fonction "d'assistance" statique qui construit l'intention correcte à utiliser pour communiquer avec NotificationActivity. En tant que tels, ils sont généralement regroupés avec l'activité. Mais je ne vois pas pourquoi cette fonction statique n'a pas pu être placée dans la classe du générateur de notification, tant que vous faites attention à définir correctement NOTIFICATION_ID et le contexte.
Mike

17

J'ai trouvé que lorsque vous utilisez les boutons d'action dans les notifications étendues, vous devez écrire du code supplémentaire et vous êtes plus contraint.

Vous devez annuler manuellement votre notification lorsque l'utilisateur clique sur un bouton d'action. La notification n'est annulée automatiquement que pour l'action par défaut.

De plus, si vous démarrez un récepteur de diffusion à partir du bouton, le tiroir de notification ne se ferme pas.

J'ai fini par créer une nouvelle NotificationActivity pour résoudre ces problèmes. Cette activité intermédiaire sans interface utilisateur annule la notification, puis démarre l'activité que je voulais vraiment démarrer à partir de la notification.

J'ai publié un exemple de code dans un article connexe. Cliquer sur Actions de notification Android ne ferme pas le tiroir de notification .


2
Dommage qu'ils n'aient toujours pas intégré cela dans l'API ... C'est assez hackish de le faire comme ça. Mais toujours le seul moyen, surtout si vous n'avez aucun contrôle sur l'intention de destination, comme afficher une URL.
Bogdan Zurac

Merci pour l'info, vous avez raison. Cependant, j'utiliserais un intentservice plutôt qu'une activité intermédiaire
Tim

7

Vous pouvez toujours cancel()le Notificationde tout ce qui est invoqué par l'action (par exemple, dans onCreate()de l'activité liée à celle que PendingIntentvous fournissez addAction()).


2
Mais comment accéder à la notification dans l'activité qui a été appelée?
endowzoner

@FleshWound: cancel()prend l'ID du Notification, que vous avez utilisé lorsque vous avez appelé notify(). Vous n'avez pas besoin de l' Notificationobjet.
CommonsWare

@CommonsWare cancel (id) a cessé de fonctionner si le setGroup est défini et qu'il y a une notification de résumé de groupe. Dans ce cas, l'annulation ne fait rien pour une raison quelconque. Sans le résumé du groupe, l'annulation fonctionne bien
Kushan

si mon intention en attente est ACTION_VIEWet que le type est image/jpeg(pour partager une image avec une autre application), comment cette annulation est-elle censée être déclenchée? IMO Android devrait s'annuler automatiquement, je suis perplexe quant à la raison pour laquelle Android ne s'en occupe pas seulement?!
Someone Somewhere le

@SomeoneSomewhere: "alors comment cette annulation est-elle censée être déclenchée?" - ça ne peut pas. Bien que rien ne vous empêche de pointer vers une application tierce dans un Notification-related PendingIntent, ce n'est pas vraiment la façon dont elle a été conçue pour fonctionner, et vous rencontrerez donc des problèmes comme celui-ci. "IMO Android devrait s'annuler automatiquement" - Je pourrais voir offrir un drapeau pour cela sur l'action, mais cela ne devrait pas être une chose permanente. Si c'était le cas, sauter une piste dans une notification de lecteur de musique fermerait la notification.
CommonsWare

7

À mon avis, utiliser un BroadcastReceiverest un moyen plus propre d'annuler une notification:

Dans AndroidManifest.xml:

<receiver 
    android:name=.NotificationCancelReceiver" >
    <intent-filter android:priority="999" >
         <action android:name="com.example.cancel" />
    </intent-filter>
</receiver>

Dans le fichier java:

Intent cancel = new Intent("com.example.cancel");
PendingIntent cancelP = PendingIntent.getBroadcast(context, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);

NotificationCompat.Action actions[] = new NotificationCompat.Action[1];

NotificationCancelReceiver

public class NotificationCancelReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //Cancel your ongoing Notification
    };
}

1
C'est ce que je fais mais comment obtenir l'ID de notification (dans cet exemple, 0) de la méthode onReceive? Ce n'est pas dans l'intention, car il n'y a pas été ajouté. J'ai essayé de l'ajouter en supplément mais il semble que le véritable ID de notification ne soit pas celui que j'ajoutais en tant que supplément dans l'activité de création ...: - /
Marco Zanetti

J'aime vraiment cette approche consistant à utiliser les services de diffusion au lieu des activités, c'est une approche beaucoup plus légère à mon humble avis.
Christophe Moine

Mais j'ai dû utiliser <intent.setAction (Integer.toString (notificationId));> dans une addition pour pouvoir ignorer l'une des notifications affichées.
Christophe Moine

1
@MarcoZanetti vous devez générer un identifiant de notification que vous transmettez à l'intention en attente et également à la méthode de notification lors de l'envoi de la notification. Si vous faites cela, lorsque l'utilisateur clique sur l'action pour annuler, il appellera le récepteur de diffusion et vous pourrez ensuite obtenir l'ID de notification des extras.
Ray Hunter

@ChristopheMoine vous pouvez mettre votre identifiant via intent.putExtra()et l'obtenirBroadcastReceiver
Vadim Kotov

5

Dans les nouvelles API, n'oubliez pas TAG:

notify(String tag, int id, Notification notification)

et en conséquence

cancel(String tag, int id) 

au lieu de:

cancel(int id)

https://developer.android.com/reference/android/app/NotificationManager


Tu avais raison! bien que la cancel()fonction ait 2 implémentations; un avec TAG et un sans. Mais nous devons fournir un fichier TAG. Voici la cancelfonction de la documentation public void cancel(@Nullable String tag, int id). Dernière vérification sur Android Q
sud007 le

1

Mettez simplement cette ligne:

 builder.setAutoCancel(true);

Et le code complet est:

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.in/"));
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    builder.setContentIntent(pendingIntent);
    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.misti_ic));
    builder.setContentTitle("Notifications Title");
    builder.setContentText("Your notification content here.");
    builder.setSubText("Tap to view the website.");
    Toast.makeText(getApplicationContext(), "The notification has been created!!", Toast.LENGTH_LONG).show();

    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    builder.setAutoCancel(true);
    // Will display the notification in the notification bar
    notificationManager.notify(1, builder.build());

L'annulation automatique semble n'avoir aucun effet lorsque vous ciblez Android 9 (a bien fonctionné lorsque vous ciblez Android 8.1)
Alix

la distinction ici est avec l'action
Someone Somewhere

0

Vous devrez exécuter le code suivant après le déclenchement de votre intention pour supprimer la notification.

NotificationManagerCompat.from(this).cancel(null, notificationId);

NB: notificationId est le même id passé pour exécuter votre notification


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.