1

Donc, depuis quelques jours, je travaille sur une appli qui fait des trucs pas bien. On va dire, par soucis de CYA, "télécharger un fichier" Le code fonctionnait très bien mais l'avancée du téléchargement était gérée par une ProgressDialog, ce qui n'est pas extra étant donné que ça bloquait l'interface utilisateur le temps que les fichiers soient téléchargés.

J'ai donc pris le parti de convertir tout ça en notifications. C'est super, ça fonctionne bien. Et puis je me dis qu'ajouter la possibilité d'annuler le téléchargement serait une bonne idée. Et c'est là que la rage commence.

Mon programme télécharge les fichiers via des AsyncTask. Dans le constructeur, j'initialise ma notification (NotificationCompat), et le manager (NotificationManager). Un peu de code vaut mieux qu'un pavé, alors voici.
public DownloaderTask(Context ctx, SearchMatch trackInfo) { _context = ctx; _trackInfo = trackInfo; _notification = new NotificationCompat.Builder(_context); _notificationManager = (NotificationManager)_context.getSystemService(Context.NOTIFICATION_SERVICE); if (ImageCache.HasImage(_trackInfo.album.id)) _notification.setLargeIcon(ImageCache.GetImageBitmap(_trackInfo.album.id)); _notification.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Cancel", GetCancelIntent()); } protected PendingIntent GetCancelIntent() { Intent buttonIntent = new Intent("org.warpten.yadda.stopdownload"); buttonIntent.putExtra("notificationId", _trackInfo.id); return PendingIntent.getBroadcast(_context, 1, buttonIntent, PendingIntent.FLAG_ONE_SHOT); }public class CancelReceiver extends BroadcastReceiver { interface ICancelReceiver { void CancelDownload(int trackId); } public static ICancelReceiver Listener; @Override public void onReceive(Context context, Intent intent) { int notificationId = intent.getIntExtra("notificationId", -1); if (Listener != null && notificationId != -1) Listener.CancelDownload(notificationId); } }
Le receiver est déclaré dans AndroidManifest.xml avec le bon filtre.
Ici ICancelReceiver est implémenté par l'activité qui lance les tâches asynchrones, c'est elle qui gère leur cycle de vie (elle les interrompt, et l'interruption de la tâche conduit à la suppression de la notification). L'implémentation de l'interface ressemble à ça:
@Override public void CancelDownload(int trackId) { if (!_tasks.containsKey(trackId)) return; _tasks.get(trackId).cancel(true); _tasks.remove(trackId); }
Alors ça donne quoi? Ma notification s'affiche, c'est nickel, mais je ne peux pas déclencher ma PendingIntent: mes "clics" passent à travers, et si je change le fonctionnement pour assigner la PendingIntent au contenu (Notification.Builder.setContentIntent) au lieu d'une action, alors tout fonctionne très bien.

Il n'y a qu'un seul moment où je peux interagir avec l'action définie: quand la notification n'est plus mise à jour avec la progression du téléchargement. Ce qui est bien sûr inutile puisqu'à ce stade, le téléchargement est terminé et le fichier est sauvegardé.

Quelqu'un a une solution à ce comportement?