Activité en cours

Dans Wear OS, l'association d'une activité en cours à une notification en cours ajoute cette notification à d'autres surfaces de l'interface utilisateur de Wear OS. Les utilisateurs peuvent ainsi continuer à être impliqués dans des activités de longue durée.

Les notifications en cours sont généralement utilisées pour indiquer qu'une notification comporte une tâche d'arrière-plan dans laquelle l'utilisateur est activement impliqué ou est en attente d'une manière ou d'une autre et qui occupe donc l'appareil.

Par exemple, un utilisateur de Wear OS peut utiliser une application d'entraînement physique pour enregistrer une course à partir d'une activité, puis quitter cette application pour lancer une autre tâche. Lorsque l'utilisateur quitte l'application d'entraînement, celle-ci effectue se transforme généralement en une notification en cours liée à une tâche en arrière-plan (par exemple, les services ou les gestionnaires d'alarmes) qui tient l'utilisateur informé de sa course. La notification fournit aux utilisateurs des informations et est un moyen simple de revenir sur l'application en un geste.

Toutefois, pour afficher la notification, l'utilisateur doit balayer l'écran jusqu'à la barre de notification sous le cadran et trouver la notification appropriée. L'action n'est donc pas aussi pratique que sur les autres surfaces.

Avec l'API "Activité en cours", la notification continue d'une application peut afficher les informations sur plusieurs nouvelles surfaces pratiques sur Wear OS afin de maintenir les utilisateurs impliqués.

Par exemple, dans cette application d'entraînement physique, les informations peuvent s'afficher sur le cadran de l'utilisateur sous la forme d'une icône tactile de course :

icône-de-course

Image 1. Indicateur d'activité

La section Récents du lanceur d'applications global liste également les activités en cours :

lanceur d'applications

Image 2. Lanceur d'applications global

Quelques exemples de situations dans lesquelles il est conseillé d'utiliser une notification en cours liée à une activité en cours :

minuteur

Image 3. Minuteur : compte à rebours actif qui se termine lorsque le minuteur est mis en pause ou arrêté.

carte

Image 4. Navigation détaillée : annonce les instructions de navigation vers une destination. Se termine lorsque l'utilisateur atteint la destination ou arrête la navigation.

musique

Image 5. Multimédia : lit de la musique pendant une période. Se termine immédiatement lorsque l'utilisateur met la session en pause.

Wear OS crée automatiquement des activités en cours pour les applications multimédias. Consultez l'atelier de programmation "Activité en cours" sur GitHub pour obtenir un exemple détaillé de création d'activités en cours pour d'autres types d'applications.

Configuration

Pour commencer à utiliser l'API "Activité en cours" dans votre application, ajoutez les dépendances suivantes au fichier build.gradle de votre application :

dependencies {
  implementation "androidx.wear:wear-ongoing:1.0.0"
  // Includes LocusIdCompat and new Notification categories for Ongoing Activity.
  implementation "androidx.core:core:1.6.0"
}

Démarrer une activité en cours

Commencez par une activité en cours.

Notification en cours

Comme mentionné précédemment, les activités en cours sont étroitement liées à une notification en cours.

Elles fonctionnent ensemble pour informer les utilisateurs d'une tâche dans laquelle ils sont activement impliqués ou en attente d'une manière ou d'une autre, et qui occupe donc l'appareil.

Vous devez associer une activité en cours à une notification en cours.

Associer votre activité en cours à une notification présente de nombreux avantages, parmi lesquels :

  • Les notifications sont des créations de remplacement sur des appareils non compatibles avec les activités en cours. La notification est la seule surface affichée par votre application lorsqu'elle s'exécute en arrière-plan.
  • Sur Android version 11 et ultérieures, Wear OS masque la notification dans la zone de notification lorsque l'application est visible en tant qu'activité en cours sur d'autres surfaces.
  • La procédure actuelle d'intégration utilise Notification comme mécanisme de communication.

Activité en cours

Commencer une activité en cours après avoir reçu une notification est un jeu d'enfant.

L'exemple de code suivant comporte des commentaires qui vous aideront à comprendre le sens de chaque propriété :

Kotlin

var builder = NotificationCompat.Builder(this, CHANNEL_ID)
      …
      .setSmallIcon(..)
      .setOngoing(true)

val ongoingActivityStatus = Status.Builder()
    // Sets the text used across various surfaces.
    .addTemplate(mainText)
    .build()

val ongoingActivity =
    OngoingActivity.Builder(
        applicationContext, NOTIFICATION_ID, notificationBuilder
    )
        // Sets the animated icon that will appear on the watch face in
        // active mode.
        // If it isn't set, the watch face will use the static icon in
        // active mode.
        .setAnimatedIcon(R.drawable.ic_walk)
        // Sets the icon that will appear on the watch face in ambient mode.
        // Falls back to Notification's smallIcon if not set.
        // If neither is set, an Exception is thrown.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap/touch event, so users can re-enter your app from the
        // other surfaces.
        // Falls back to Notification's contentIntent if not set.
        // If neither is set, an Exception is thrown.
        .setTouchIntent(activityPendingIntent)
        // In our case, sets the text used for the Ongoing Activity (more
        // options are available for timers and stopwatches).
        .setStatus(ongoingActivityStatus)
        .build()

ongoingActivity.apply(applicationContext)

notificationManager.notify(NOTIFICATION_ID, builder.build())

Java

NotificationCompat.Builder builder = NotificationCompat.Builder(this, CHANNEL_ID)
      …
      .setSmallIcon(..)
      .setOngoing(true);

OngoingActivityStatus ongoingActivityStatus = OngoingActivityStatus.Builder()
    // Sets the text used across various surfaces.
    .addTemplate(mainText)
    .build();

OngoingActivity ongoingActivity =
    OngoingActivity.Builder(
        applicationContext, NOTIFICATION_ID, notificationBuilder
    )
        // Sets the animated icon that will appear on the watch face in
        // active mode.
        // If it isn't set, the watch face will use the static icon in
        // active mode.
        .setAnimatedIcon(R.drawable.ic_walk)
        // Sets the icon that will appear on the watch face in ambient mode.
        // Falls back to Notification's smallIcon if not set.
        // If neither is set, an Exception is thrown.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap/touch event, so users can re-enter your app from the
        // other surfaces.
        // Falls back to Notification's contentIntent if not set.
        // If neither is set, an Exception is thrown.
        .setTouchIntent(activityPendingIntent)
        // In our case, sets the text used for the Ongoing Activity (more
        // options are available for timers and stopwatches).
        .setStatus(ongoingActivityStatus)
        .build();

ongoingActivity.apply(applicationContext);

notificationManager.notify(NOTIFICATION_ID, builder.build());

Les étapes suivantes décrivent la partie la plus importante de l'exemple précédent :

  1. Appelez .setOngoing(true) sur NotificationCompat.Builder et déterminez les champs facultatifs.

  2. Créez un élément OngoingActivityStatus pour afficher le texte. (Les autres options d'état sont détaillées dans la section suivante.)

  3. Créez un élément OngoingActivity et définissez un identifiant de notification (obligatoire).

  4. Appelez apply() sur OngoingActivity avec le contexte.

  5. Appelez notificationManager.notify() et entrez le même identifiant de notification que l'activité en cours pour les lier.

État

L'élément Status permet aux développeurs d'afficher l'état actuel en direct de l'élément OngoingActivity à l'utilisateur sur les nouvelles surfaces, comme la section "Récents" du lanceur d'applications. Pour utiliser cette fonctionnalité, utilisez la méthode Status.Builder.

Dans la plupart des cas, les développeurs n'ont qu'à ajouter un modèle qui affiche le texte qu'ils souhaitent voir apparaître dans la section Récents du lanceur d'applications.

Les développeurs peuvent personnaliser la manière dont le texte s'affiche avec des segments à l'aide de la méthode addTemplate() et en spécifiant n'importe quelle partie dynamique du texte sous forme de Status.Part.

L'exemple suivant montre comment afficher le mot "heure" en rouge. Cet exemple utilise un objet Status.TimerPart qui nous permet d'afficher un minuteur, ou Status.StopwatchPart pour afficher un chronomètre dans la section Récents du lanceur d'applications.

Kotlin

val htmlStatus =
        "<p>The <font color=\"red\">time</font> on your current #type# is #time#.</p>"

val statusTemplate =
        Html.fromHtml(
                htmlStatus,
                Html.FROM_HTML_MODE_COMPACT
        )

// Creates a 5 minute timer.
// Note the use of SystemClock.elapsedRealtime(), not System.currentTimeMillis()
val runStartTime = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(5)

val status = new Status.Builder()
   .addTemplate(statusTemplate)
   .addPart("type", Status.TextPart("run"))
   .addPart("time", Status.StopwatchPart(runStartTime)
   .build()

Java

String htmlStatus =
        "<p>The <font color=\"red\">time</font> on your current #type# is #time#.</p>";

Spanned statusTemplate =
        Html.fromHtml(
                htmlStatus,
                Html.FROM_HTML_MODE_COMPACT
        );

// Creates a 5 minute timer.
// Note the use of SystemClock.elapsedRealtime(), not System.currentTimeMillis()
Long runStartTime = SystemClock.elapsedRealtime() + TimeUnit.MINUTES.toMillis(5);

Status status = new Status.Builder()
   .addTemplate(statusTemplate)
   .addPart("type", new Status.TextPart("run"))
   .addPart("time", new Status.StopwatchPart(runStartTime)
   .build();

Pour faire référence à une partie du modèle, utilisez le nom encadré par #. Pour obtenir # en sortie, utilisez ## dans le modèle.

L'exemple précédent utilise HTMLCompat pour générer un élément CharSequence à soumettre au modèle, ce qui est plus facile que de définir manuellement un objet Spannable.

Autres personnalisations

Outre Status, les développeurs peuvent personnaliser leur activité ou leurs notifications en cours comme suit. Ces personnalisations peuvent ou non être utilisées en fonction de l'intégration de l'OEM.

Notification en cours

  • Les options de catégories déterminent la priorité de l'activité en cours.
    • CATEGORY_CALL : appel entrant (vocal ou vidéo) ou demande de communication synchrone similaire.
    • CATEGORY_NAVIGATION : carte ou navigation détaillée.
    • CATEGORY_TRANSPORT : commande de transport multimédia pour la lecture.
    • CATEGORY_ALARM : alarme ou minuteur.
    • CATEGORY_WORKOUT : séance d'entraînement physique (nouveau).
    • CATEGORY_LOCATION_SHARING : partage temporaire de localisation (nouveau).
    • CATEGORY_STOPWATCH : chronomètre (nouveau) \.

Activité en cours

  • Icône animée : vecteur noir et blanc, de préférence avec un arrière-plan transparent. S'affiche sur le cadran en mode actif. Si cette valeur n'est pas définie, l'icône de notification par défaut est utilisée.

  • Icône statique : icône de vecteur sur fond transparent. S'affiche sur le cadran en mode Bruit ambiant. Si l'icône animée n'est pas définie, l'icône statique est utilisée sur le cadran pour le mode actif. Si cette valeur n'est pas définie, l'icône de notification est utilisée. Si aucune de ces valeurs n'est définie, une exception est générée. (L'icône du lanceur d'applications utilisera toujours l'icône de l'application.)

  • OngoingActivityStatus : texte brut ou chronomètre. S'affiche dans la section "Récents" du lanceur d'applications. Si cette valeur n'est pas définie, la notification "Texte contextuel" est utilisée.

  • Intent tactile : PendingIntent qui permet de revenir à l'application si l'utilisateur appuie sur l'icône d'activité en cours. S'affiche sur le cadran ou sur l'élément du lanceur d'applications. Il peut être différent de l'intent d'origine utilisé pour lancer l'application. S'il n'est pas fourni, l'intent de contenu de la notification est utilisé. Si aucun de ces éléments n'est défini, une exception est générée. \

  • LocusId : identifiant qui attribue le raccourci du lanceur d'applications auquel l'activité en cours correspond. S'affiche dans le lanceur d'applications dans la section "Récents" lorsque l'activité est en cours. Si ce n'est pas le cas, le lanceur d'applications masquera tous les éléments de l'application présents dans la section "Récents" dans le même package et n'affichera que l'activité en cours. \

  • Identifiant d'activité en cours : identifiant qui permet de faire la distinction entre les appels à fromExistingOngoingActivityfromExistingOngoingActivity() si plusieurs activités sont en cours sur une application.

Mettre à jour une activité en cours

Dans la plupart des cas, les développeurs créent une nouvelle notification en cours et une nouvelle activité en cours lorsqu'ils doivent mettre à jour les données à l'écran. Cependant, l'API "Activité en cours" propose aussi des méthodes pour mettre à jour un élément OngoingActivity si vous souhaitez conserver une instance plutôt que de la recréer.

Si l'application s'exécute en arrière-plan, elle peut envoyer des mises à jour à l'API "Activité en cours", mais ceci doit rester exceptionnel. La méthode de mise à jour peut ignorer les appels trop proches les uns des autres. Quelques mises à jour par minute suffisent.

Pour mettre à jour l'activité en cours et la notification publiée, utilisez l'objet que vous avez créé précédemment et appelez update(), comme l'illustre l'exemple suivant :

Kotlin

ongoingActivity.update(context, newStatus)

Java

ongoingActivity.update(context, newStatus);

Pour plus de confort, il existe une méthode statique permettant de créer une activité en cours.

Kotlin

OngoingActivity.recoverOngoingActivity(context)
               .update(context, newStatus)

Java

OngoingActivity.recoverOngoingActivity(context)
               .update(context, newStatus);

Arrêter une activité en cours

Lorsque l'exécution de l'application est terminée en tant qu'activité en cours, il suffit d'annuler la notification en cours.

Il appartient à l'application d'annuler la notification ou l'activité en cours qui s'exécute au premier plan, puis de la recréer lorsqu'elle repasse à l'arrière-plan.

Suspendre une activité en cours

Si votre application dispose d'une action Stop claire, poursuivez l'activité en cours après sa réactivation. Cependant, les applications qui ne disposent pas d'une action Stop claire doivent mettre fin à l'activité suspendue.

Bonnes pratiques

Gardez les points suivants en tête lorsque vous utilisez l'API Activité en cours :

  • Appelez toujours ongoingActivity.apply(context) avant d'appeler notificationManager.notify(...).
  • Définissez toujours une icône statique pour votre activité en cours, soit de manière claire, soit en création de remplacement via la notification. Sinon, vous serez confronté à une IllegalArgumentException.

  • Les icônes doivent être des vecteurs noir et blanc sur un arrière-plan transparent.

  • Définissez toujours un intent tactile pour votre activité en cours, soit de manière claire, soit en création de remplacement via la notification. Sinon, vous serez confronté à une IllegalArgumentException.

  • Pour NotificationCompat, utilisez la bibliothèque AndroidX principale (core:1.5.0-alpha05+), qui inclut les LocusIdCompat et les nouvelles catégories (entraînement physique, chronomètre ou partage de localisation).

  • Si votre application comporte plusieurs activités MAIN LAUNCHER déclarées dans le fichier manifeste, publiez un raccourci dynamique et associez-le à votre activité en cours à l'aide de LocusId.