Applications permanentes et mode ambiant du système

Ce guide explique comment rendre votre application toujours active, comment réagir aux transitions d'état de l'alimentation et comment gérer le comportement de l'application pour offrir une bonne expérience utilisateur tout en économisant la batterie.

Rendre une application constamment visible a un impact significatif sur l'autonomie de la batterie. Par conséquent, tenez-en compte lorsque vous ajoutez cette fonctionnalité.

Concepts clés

Lorsqu'une application Wear OS s'affiche en plein écran, elle se trouve dans l'un des deux états d'alimentation suivants :

  • Interactif : état de forte puissance où l'écran est à pleine luminosité, ce qui permet une interaction complète de l'utilisateur.
  • Veille : état de faible consommation d'énergie dans lequel l'écran s'assombrit pour économiser de l'énergie. Dans cet état, l'UI de votre application occupe toujours tout l'écran, mais le système peut modifier son apparence en la floutant ou en affichant du contenu en superposition, comme l'heure. Il s'agit également du mode Veille.

Le système d'exploitation contrôle la transition entre ces états.

Une application toujours activée est une application qui affiche du contenu dans les états Interactif et Veille.

Lorsqu'une application always-on continue d'afficher sa propre UI alors que l'appareil est en état de veille ambiante (faible consommation d'énergie), elle est décrite comme étant en mode ambiactif.

Transitions système et comportement par défaut

Lorsqu'une application est au premier plan, le système gère les transitions d'état d'alimentation en fonction de deux délais d'inactivité de l'utilisateur.

  • Délai d'inactivité 1 : état interactif à état ambiant : après une période d'inactivité de l'utilisateur, l'appareil passe à l'état Ambiant.
  • Délai d'inactivité 2 : retour au cadran : après une nouvelle période d'inactivité, le système peut masquer l'application en cours et afficher le cadran.

Immédiatement après que le système passe à l'état Ambient, le comportement par défaut dépend de la version de Wear OS et de la configuration de votre application :

  • Sur Wear OS 5 et versions antérieures, le système affiche une capture d'écran floutée de votre application en pause, avec l'heure en superposition. Cet état est représenté par le nœud "AOD Lite" dans l'organigramme suivant.
  • Sur Wear OS 6 et versions ultérieures, si une application cible le SDK 36 ou une version ultérieure, elle est considérée comme always-on. L'écran est assombri, mais l'application continue de s'exécuter et reste visible. (Les mises à jour peuvent être aussi peu fréquentes qu'une fois par minute.) Cet état est représenté par le nœud "Global AOD" dans l'organigramme suivant.

Personnaliser le comportement pour l'état ambiant

Quel que soit le comportement par défaut du système, vous pouvez personnaliser l'apparence ou le comportement de votre application dans l'état Ambient sur toutes les versions de Wear OS en utilisant LocalAmbientModeManager pour observer les transitions d'état dans Jetpack Compose sur Wear OS. Cet état est représenté par le nœud "Mode Ambiactive" dans l'organigramme suivant.

Observer l'état ambiant

Pour réagir aux événements du mode Veille dans Jetpack Compose sur Wear OS :

  1. Utilisez LocalAmbientModeManager pour observer les changements d'état du mode Veille du système et ajuster vos composables en conséquence. Configurez votre composant pour qu'il s'adapte à un mode basse consommation dans l'état AmbientMode.Ambient et restaurez-le pour qu'il s'affiche en mode interactif dans l'état AmbientMode.Interactive.

    // In a production application, the AmbientModeManager should be instantiated and provided at
    // the highest level of the Compose hierarchy (typically in the host Activity's setContent
    // block) using a CompositionLocalProvider. This ensures proper lifecycle management and
    // broad accessibility.
    
    // For this self-contained demo, AmbientModeManager is created and provided locally:
    val activityAmbientModeManager = rememberAmbientModeManager()
    CompositionLocalProvider(LocalAmbientModeManager provides activityAmbientModeManager) {
        val ambientModeManager = LocalAmbientModeManager.current
        val ambientMode = ambientModeManager?.currentAmbientMode
    
        if (ambientModeManager != null) {
            ambientModeManager.AmbientTickEffect {
                // While device is in ambient mode, update properties every minute or so
                // ...
            }
        }
    
        // ...
            val ambientModeName =
                when (ambientMode) {
                    is AmbientMode.Interactive -> "Interactive"
                    is AmbientMode.Ambient -> "Ambient"
                    else -> "Unknown"
                }
    
            Text(text = "$ambientModeName Mode")
            // ...
    }

Organigramme du comportement ambiant

L'organigramme suivant illustre la façon dont le système détermine le comportement ambiant en fonction de la version Wear OS de l'appareil, du targetSdkVersion de votre application et de la façon dont elle observe les transitions d'état ambiant (à l'aide de LocalAmbientModeManager ou AmbientLifecycleCallback).

Organigramme illustrant la logique de décision pour le mode ambiant Wear OS. Il montre comment la version de l'OS de l'appareil et la configuration de l'application déterminent l'un des trois résultats suivants : une superposition floue, le mode Always-on global ou le mode Ambiactive géré par l'application.
Figure 1 : Organigramme illustrant la logique de décision pour le mode Veille de Wear OS.

Contrôler la durée d'activation de l'écran

Les sections suivantes décrivent comment gérer la durée d'affichage de votre application à l'écran.

Empêcher le retour au cadran avec une activité en cours ou une mise à jour en direct

Après un certain temps passé dans l'état Ambient (délai d'inactivité 2), le système revient généralement au cadran de la montre. L'utilisateur peut configurer la durée du délai avant expiration dans les paramètres système. Dans certains cas d'utilisation, comme le suivi d'un entraînement par un utilisateur, une application peut avoir besoin de rester visible plus longtemps.

Sur Wear OS 5 et versions ultérieures, vous pouvez éviter cela en implémentant une activité en cours. Si votre application affiche des informations sur une tâche utilisateur en cours, comme une séance d'entraînement, vous pouvez utiliser l'API Ongoing Activity pour que votre application reste visible jusqu'à la fin de la tâche. Si un utilisateur revient manuellement au cadran, l'indicateur d'activité en cours lui permet de revenir à votre application en un seul geste.

Sur Wear OS 7 ou version ultérieure, vous pouvez également utiliser une mise à jour en direct à la place d'une activité en cours. Pour assurer la rétrocompatibilité, continuez à prendre en charge l'activité en cours sur les appareils équipés de Wear OS 6 ou d'une version antérieure.

Pour ce faire, l'intent tactile de la notification d'activité en cours doit pointer vers votre activité toujours activée, comme indiqué dans l'extrait de code suivant :

val activityIntent =
    Intent(this, AlwaysOnActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
    }

val pendingIntent =
    PendingIntent.getActivity(
        this,
        0,
        activityIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
    )

val notificationBuilder =
    NotificationCompat.Builder(this, CHANNEL_ID)
        // ...
        // ...
        .setOngoing(true)

// ...

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // ...
        // ...
        .setTouchIntent(pendingIntent)
        .build()

ongoingActivity.apply(applicationContext)

val notification = notificationBuilder.build()

Garder l'écran allumé et empêcher l'état ambiant

Dans de rares cas, vous devrez peut-être empêcher complètement l'appareil de passer à l'état Veille. Autrement dit, pour éviter le délai d'inactivité 1. Pour ce faire, vous pouvez utiliser le modificateur keepScreenOn. Cela fonctionne comme un wakelock, qui maintient l'appareil dans l'état Interactive. Utilisez cette option avec une extrême prudence, car elle a un impact important sur l'autonomie de la batterie.

Recommandations pour le mode Veille

Pour offrir la meilleure expérience utilisateur possible et économiser de l'énergie en mode Veille, suivez ces consignes de conception. Ces recommandations privilégient une expérience utilisateur claire en évitant les informations trompeuses et en réduisant l'encombrement visuel, tout en optimisant la puissance d'affichage.

  • Réduisez l'encombrement visuel et affichez la puissance. Une UI épurée et minimaliste indique à l'utilisateur que l'application est en mode basse consommation et permet d'économiser beaucoup de batterie en limitant les pixels lumineux.
    • Laissez au moins 85% de l'écran noir (ratio de pixels allumés de 15% ou moins).
    • N'affichez que les informations les plus importantes et déplacez les détails secondaires vers l'écran interactif.
    • Utilisez des contours pour les grandes icônes ou les grands boutons plutôt que des fonds pleins. Ajustez le contraste des contours pour que les éléments restent lisibles sans risquer de provoquer un scintillement ou une brûlure de l'écran.
    • Évitez les grands blocs de couleur unie, ainsi que les images de marque ou d'arrière-plan non fonctionnelles.
  • Gérer les données dynamiques et les animations obsolètes
    • Le rappel AmbientTickEffect n'est invoqué que périodiquement (généralement une fois par minute) pour économiser de l'énergie. En raison de cette limitation, toutes les données qui changent fréquemment (comme un chronomètre, la fréquence cardiaque ou la distance d'entraînement) deviennent obsolètes entre les mises à jour. Pour éviter d'afficher des informations trompeuses et incorrectes, remplacez ces valeurs dynamiques par du contenu d'espace réservé statique, tel que --.
    • Supprimez les indicateurs de progression qui nécessitent des mises à jour fréquentes pour être utiles au contexte ou à la situation actuels de l'utilisateur, tels que les anneaux de progression pour les sessions multimédias courtes. Vous pouvez conserver les indicateurs de progression lorsque les mises à jour une fois par minute sont toujours utiles, par exemple pour les longs minuteurs.
    • Mettre en pause ou supprimer toutes les animations en mode Veille, y compris les indicateurs de progression animés et le texte défilant.
  • Maintenir une mise en page cohérente
    • Conservez les éléments à la même position dans les modes Interactif et Veille pour créer une transition fluide. Les éléments d'UI interactifs tels que les boutons peuvent rester visibles, car les appareils Wear OS modernes sont compatibles avec les entrées tactiles pendant les sessions ambiantes.
    • Afficher toujours l'heure actuelle. Dans Jetpack Compose pour Wear OS, TimeText (inclus par défaut dans ScreenScaffold) est sensible à la luminosité ambiante et se met à jour automatiquement une fois par minute en mode Veille.
  • Tenez compte du contexte
    • Si l'utilisateur se trouvait sur un écran de paramètres ou de configuration lorsque l'appareil est passé en mode Veille, envisagez d'afficher un écran plus pertinent de votre application au lieu de la vue des paramètres.
  • Gérer les exigences spécifiques aux appareils
    • Lorsque currentAmbientMode renvoie AmbientMode.Ambient :
      • Si isLowBitAmbientSupported est défini sur true, l'écran prend en charge moins de bits par couleur en mode Veille. Désactivez l'anticrénelage (par exemple, dans les opérations de dessin Canvas ou Paint personnalisées) et évitez les dégradés de couleurs dans la mesure du possible.
      • Si isBurnInProtectionRequired est défini sur true, le système déplace régulièrement le contenu de l'écran pour éviter la brûlure d'écran. Ne déplacez pas manuellement les éléments d'interface utilisateur dans votre application. Évitez plutôt les zones blanches unies et placez les éléments d'interface utilisateur essentiels à au moins 10 pixels du bord de l'écran pour qu'ils ne soient pas coupés lorsque le système déplace l'affichage. (Les mises en page Wear Compose standards telles que ScreenScaffold fournissent déjà une marge intérieure suffisante.)

Débogage et test

Ces commandes adb peuvent être utiles pour développer ou tester le comportement de votre application lorsque l'appareil est en mode Veille :

# put device in ambient mode if the always on display is enabled in settings
# (and not disabled by other settings, such as theatre mode)
$ adb shell input keyevent KEYCODE_SLEEP

# put device in interactive mode
$ adb shell input keyevent KEYCODE_WAKEUP

Exemple : application d'entraînement

Prenons l'exemple d'une application d'entraînement qui doit afficher des métriques à l'utilisateur pendant toute la durée de sa séance d'exercice. L'application doit rester visible lors des transitions d'état Ambient et ne pas être remplacée par la clock face.

Pour ce faire, le développeur doit procéder comme suit :

  1. Utilisez LocalAmbientModeManager pour gérer les modifications de l'UI entre les états Interactive et Ambient, comme la diminution de la luminosité de l'écran et la suppression des données non essentielles.
  2. Créez une mise en page basse consommation pour l'état Ambient qui suit les bonnes pratiques.
  3. Utilisez l'API Ongoing Activity (ou Mises à jour en direct sur Wear OS 7 et versions ultérieures) pendant toute la durée de l'entraînement pour empêcher le système de revenir au cadran de la montre.

Pour obtenir une implémentation complète, consultez l'exemple d'exercice basé sur Compose sur GitHub. Cet exemple montre également comment utiliser le composable LocalAmbientModeManager pour simplifier la gestion du mode Veille dans Compose.