Always-on-Apps und Inaktivmodus des Systems

In diesem Leitfaden wird erläutert, wie Sie Ihre App immer aktiv halten, wie Sie auf Änderungen des Energiestatus reagieren und wie Sie das Verhalten der Anwendung verwalten, um eine gute Nutzer erfahrung zu bieten und gleichzeitig den Akku zu schonen.

Wenn eine App ständig sichtbar ist, wirkt sich das erheblich auf die Akkulaufzeit aus. Berücksichtigen Sie daher die Auswirkungen auf den Energieverbrauch, wenn Sie diese Funktion hinzufügen.

Schlüsselkonzepte

Wenn eine Wear OS-App im Vollbildmodus angezeigt wird, befindet sie sich in einem von zwei Energiestatus:

  • Interaktiv: Ein Status mit hohem Energieverbrauch, bei dem der Bildschirm mit voller Helligkeit angezeigt wird, die vollständige Nutzerinteraktion möglich ist.
  • Inaktiv: Ein Status mit niedrigem Energieverbrauch, bei dem das Display gedimmt wird, um Energie zu sparen. In diesem Status nimmt die UI Ihrer App weiterhin den gesamten Bildschirm ein, aber das System kann ihr Aussehen ändern, indem es sie unscharf macht oder Overlay-Inhalte wie die Uhrzeit anzeigt. Dieser Status wird auch als Inaktivmodus bezeichnet.

Das Betriebssystem steuert den Übergang zwischen diesen Status.

Eine immer aktive App ist eine Anwendung, die Inhalte sowohl im Status Interaktiv als auch im Status Inaktiv anzeigt.

Wenn eine immer aktive App ihre eigene UI weiterhin anzeigt, während sich das Gerät im Inaktivmodus mit niedrigem Energieverbrauch befindet, wird sie als im Ambiactive-Modus bezeichnet.

Systemübergänge und Standardverhalten

Wenn sich eine App im Vordergrund befindet, verwaltet das System die Übergänge des Energiestatus basierend auf zwei Zeitlimits, die durch Nutzerinaktivität ausgelöst werden.

  • Zeitlimit 1: Übergang vom interaktiven Status zum inaktiven Status:Nach einer bestimmten Zeit der Nutzerinaktivität wechselt das Gerät in den Status Inaktiv.
  • Zeitlimit 2: Rückkehr zum Zifferblatt:Nach einer weiteren Zeit der Inaktivität kann das System die aktuelle App ausblenden und das Zifferblatt anzeigen.

Unmittelbar nachdem das System den ersten Übergang in den Status Inaktiv durchlaufen hat, hängt das Standardverhalten von der Wear OS-Version und der Konfiguration Ihrer App ab:

  • Unter Wear OS 5 und niedriger zeigt das System einen unscharfen Screenshot Ihrer pausierten Anwendung an, über dem die Uhrzeit eingeblendet wird. Dieser Status wird im folgenden Flussdiagramm durch den Knoten „AOD Lite“ dargestellt.
  • Unter Wear OS 6 und höher gilt eine App, die auf SDK 36 oder höher ausgerichtet ist, als immer aktiv. Das Display wird gedimmt, aber die Anwendung wird weiter ausgeführt und bleibt sichtbar. Aktualisierungen können nur einmal pro Minute erfolgen. Dieser Status wird im folgenden Flussdiagramm durch den Knoten „Global AOD“ dargestellt.

Verhalten für den inaktiven Status anpassen

Unabhängig vom Standardverhalten des Systems können Sie unter allen Wear OS-Versionen das Aussehen oder Verhalten Ihrer App im Status Inaktiv anpassen, indem Sie LocalAmbientModeManager verwenden, um Statusübergänge in Jetpack Compose unter Wear OS zu beobachten. Dieser Status wird im folgenden Flussdiagramm durch den Knoten „Ambiactive-Modus“ dargestellt.

Inaktiven Status beobachten

So reagieren Sie in Jetpack Compose unter Wear OS auf Ereignisse im Inaktivmodus:

  1. Verwenden Sie LocalAmbientModeManager, um Änderungen am Status des Inaktivmodus des Systems zu beobachten und Ihre Composables entsprechend anzupassen. Konfigurieren Sie Ihre Komponente so, dass sie sich im Status AmbientMode.Ambient an einen Modus mit geringerem Energieverbrauch anpasst und im Status AmbientMode.Interactive wieder auf eine vollständige interaktive Anzeige umstellt.

    // 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")
            // ...
    }

Entwickler, die Jetpack Compose verwenden, können LocalAmbientModeManager nutzen, das die Implementierung dieses Musters vereinfacht.

Flussdiagramm für das Verhalten im Inaktivmodus

Das folgende Flussdiagramm veranschaulicht, wie das System das Verhalten im Inaktivmodus basierend auf der Wear OS-Version des Geräts, dem targetSdkVersion Ihrer App und der Implementierung von AmbientLifecycleCallback bestimmt.

Ein Flussdiagramm, das die Entscheidungslogik für den Wear OS-Umgebungsmodus veranschaulicht. Es wird gezeigt, wie die Betriebssystemversion des Geräts und die Konfiguration der App eines von drei Ergebnissen bestimmen: ein verschwommenes Overlay, Global AOD oder der von der App verwaltete Ambiactive-Modus.
Abbildung 1.: Ein Flussdiagramm, das die Entscheidungslogik für den Inaktivmodus von Wear OS veranschaulicht.

Anzeigedauer steuern

In den folgenden Abschnitten wird beschrieben, wie Sie festlegen, wie lange Ihre App auf dem Bildschirm angezeigt wird.

Mit einer laufenden Aktivität oder einem Live-Update verhindern, dass zum Zifferblatt zurückgekehrt wird

Nach einer bestimmten Zeit im Status Inaktiv (Zeitlimit 2) kehrt das System in der Regel zum Zifferblatt zurück. Der Nutzer kann die Zeitlimitdauer in den Systemeinstellungen konfigurieren. In bestimmten Anwendungsfällen, z. B. wenn ein Nutzer ein Training aufzeichnet, muss eine App möglicherweise länger sichtbar bleiben.

Unter Wear OS 5 und höher können Sie dies verhindern, indem Sie eine laufende Aktivität implementieren. Wenn Ihre App Informationen zu einer laufenden Nutzeraufgabe anzeigt, z. B. einer Trainingseinheit, können Sie mit der Ongoing Activity API dafür sorgen, dass Ihre App so lange sichtbar bleibt, bis die Aufgabe beendet ist. Wenn ein Nutzer manuell zum Zifferblatt zurückkehrt, kann er mit der Anzeige für laufende Aktivitäten mit einem Tippen zu Ihrer App zurückkehren.

Alternativ können Sie unter Wear OS 7 und höher anstelle einer laufenden Aktivität ein Live-Update verwenden. Aus Gründen der Abwärtskompatibilität sollten Sie laufende Aktivitäten weiterhin auf Geräten mit Wear OS 6 oder niedriger unterstützen.

Dazu muss die Touch-Intent der laufenden Benachrichtigung auf Ihre immer aktive Aktivität verweisen, wie im folgenden Code-Snippet gezeigt:

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()

Display aktiviert lassen und inaktiven Status verhindern

In seltenen Fällen müssen Sie möglicherweise verhindern, dass das Gerät in den Status Inaktiv wechselt. Das heißt, Sie müssen Zeitlimit 1 vermeiden. Dazu können Sie den keepScreenOn Modifikator verwenden. Dieser fungiert als Wakelock und hält das Gerät im Status Interaktiv. Verwenden Sie diese Funktion mit äußerster Vorsicht, da sie sich erheblich auf die Akkulaufzeit auswirkt.

Empfehlungen für den Inaktivmodus

Um die bestmögliche Nutzererfahrung zu bieten und im Inaktivmodus Energie zu sparen, sollten Sie diese Designrichtlinien befolgen. Diese Empfehlungen legen den Schwerpunkt auf eine klare Nutzererfahrung, indem sie irreführende Informationen verhindern und visuelles Durcheinander reduzieren und gleichzeitig den Energieverbrauch des Displays optimieren.

  • Visuelles Durcheinander und Energieverbrauch des Displays reduzieren Eine übersichtliche, minimalistische UI signalisiert dem Nutzer, dass sich die App im Status mit niedrigem Energieverbrauch befindet, und spart erheblich Akku, indem die Anzahl der hellen Pixel begrenzt wird.
    • Mindestens 85% des Bildschirms sollten schwarz sein.
    • Zeigen Sie nur die wichtigsten Informationen an und verschieben Sie sekundäre Details auf das interaktive Display.
    • Verwenden Sie für große Symbole oder Schaltflächen Umrisse anstelle von durchgehenden Füllungen.
    • Vermeiden Sie große Blöcke mit durchgehender Farbe und nicht funktionale Branding- oder Hintergrundbilder.
  • Veraltete dynamische Daten verarbeiten
    • Der Callback AmbientTickEffect wird nur in regelmäßigen Abständen aufgerufen, in der Regel einmal pro Minute, um Energie zu sparen. Aufgrund dieser Einschränkung werden alle Daten, die sich häufig ändern, z. B. eine Stoppuhr, die Herzfrequenz oder die Trainingsdistanz, zwischen den Aktualisierungen veraltet. Um irreführende und falsche Informationen zu vermeiden, ersetzen Sie diese Live-Werte durch statische Platzhalterinhalte, z. B. --.
  • Einheitliches Layout beibehalten
    • Platzieren Sie Elemente in den Modi Interaktiv und Inaktiv an derselben Position, um einen reibungslosen Übergang zu ermöglichen.
    • Zeigen Sie immer die Uhrzeit an.
  • Kontext berücksichtigen
    • Wenn sich der Nutzer auf einem Einstellungs- oder Konfigurationsbildschirm befand, als das Gerät in den Inaktivmodus wechselte, sollten Sie anstelle der Einstellungen einen relevanteren Bildschirm aus Ihrer App anzeigen.
  • Gerätespezifische Anforderungen berücksichtigen
    • Im AmbientMode-Objekt, das von currentAmbientMode zurückgegeben wird:
      • Wenn isLowBitAmbientSupported true ist, deaktivieren Sie nach Möglichkeit das Antialiasing.
      • Wenn isBurnInProtectionRequired true ist, verschieben Sie die UI-Elemente regelmäßig leicht und vermeiden Sie durchgehende weiße Bereiche, um ein Einbrennen des Bildschirms zu verhindern.

Fehlerbehebung und Tests

Diese adb-Befehle können bei der Entwicklung oder beim Testen des Verhaltens Ihrer App im Inaktivmodus hilfreich sein:

# 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

Beispiel: Trainings-App

Nehmen wir als Beispiel eine Trainings-App, die dem Nutzer während der gesamten Trainingseinheit Messwerte anzeigen muss. Die App muss während der Übergänge in den Inaktivmodus sichtbar bleiben und darf nicht durch das Zifferblatt ersetzt werden.

Dazu sollte der Entwickler Folgendes tun:

  1. LocalAmbientModeManager verwenden, um UI-Änderungen zwischen den Modi Interaktiv und Inaktiv zu verarbeiten, z. B. das Dimmen des Bildschirms und das Entfernen nicht benötigter Daten.
  2. Ein neues Layout mit geringem Energieverbrauch für den Status Inaktiv erstellen, das den Best Practices entspricht.
  3. Die Ongoing Activity API (oder Live-Updates unter Wear OS 7 und höher) während des Trainings verwenden, um zu verhindern, dass das System zum Zifferblatt zurückkehrt.

Eine vollständige Implementierung finden Sie im Compose-basierten Trainingsbeispiel auf GitHub. In diesem Beispiel wird auch die Verwendung des LocalAmbientModeManager Composables veranschaulicht, um die Verarbeitung des Inaktivmodus in Compose zu vereinfachen.