Wyświetlanie trwających aktywności

Urządzenia z Wear OS są często używane do długotrwałych działań, takich jak śledzenie treningu. Stwarza to problem związany z wygodą użytkowania: jeśli użytkownik rozpocznie zadanie, a następnie przejdzie do tarczy zegarka, jak może wrócić do aplikacji? Powrót do aplikacji za pomocą Menu z aplikacjami może być trudny, zwłaszcza w ruchu, co powoduje niepotrzebne utrudnienia.

Rozwiązaniem jest połączenie powiadomienia o trwającej aktywności z OngoingActivity. Dzięki temu urządzenie może wyświetlać informacje o długotrwałej aktywności w interfejsie użytkownika, co umożliwia korzystanie z funkcji takich jak ikona, którą można kliknąć u dołu tarczy zegarka. Dzięki temu użytkownicy są świadomi zadania działającego w tle i mogą jednym kliknięciem wrócić do aplikacji.

Dzięki Ongoing Activity Twoja aplikacja jest też dłużej widoczna, co uniemożliwia systemowi powrót do tarczy zegarka po okresie braku aktywności. Więcej informacji znajdziesz w artykule Zapewnianie widoczności aplikacji na Wear.

Na przykład w tej aplikacji do treningu informacje mogą być wyświetlane na tarczy zegarka użytkownika jako ikona biegu, którą można kliknąć:

ikona biegania

Rysunek 1. Wskaźnik aktywności.

Powiadomienie o trwającej aktywności wyświetla też informacje w sekcji Ostatnie w Menu z aplikacjami. Dzięki temu użytkownicy mają kolejne wygodne miejsce, w którym mogą sprawdzić stan zadania i ponownie zaangażować się w aplikację:

launcher

Rysunek 2. Menu z aplikacjami.

Oto kilka sytuacji, w których warto użyć powiadomienia o trwającej aktywności powiązanego z Ongoing Activity:

licznik czasu

Rysunek 3. Minutnik: aktywnie odlicza czas i kończy się, gdy minutnik zostanie wstrzymany lub zatrzymany.

mapa

Rysunek 4. Szczegółowa nawigacja: podaje wskazówki dojazdu do miejsca docelowego. Kończy się, gdy użytkownik dotrze do miejsca docelowego lub zatrzyma nawigację.

muzyka

Rysunek 5. Multimedia: odtwarza muzykę przez całą sesję. Kończy się natychmiast po wstrzymaniu sesji przez użytkownika.

Wear automatycznie tworzy Ongoing Activity dla aplikacji multimedialnych.

Szczegółowy przykład tworzenia Ongoing Activity dla innych rodzajów aplikacji znajdziesz w ćwiczeniach z programowania dotyczących Ongoing Activity.

Konfiguracja

Aby zacząć korzystać z interfejsu Ongoing Activity API w swojej aplikacji, dodaj te zależności do pliku build.gradle aplikacji:

dependencies {
  implementation "androidx.wear:wear-ongoing:1.1.0"
  implementation "androidx.core:core:1.18.0"
}

Tworzenie Ongoing Activity

Ten proces obejmuje 3 kroki:

  1. Utwórz standardowy NotificationCompat.Builder i skonfiguruj go jako trwający.
  2. Utwórz i skonfiguruj obiekt OngoingActivity, przekazując do niego narzędzie do tworzenia powiadomień.
  3. Zastosuj trwającą aktywność do narzędzia do tworzenia powiadomień i opublikuj wynikowe powiadomienie.

Tworzenie i konfigurowanie powiadomienia

Zacznij od utworzenia NotificationCompat.Builder. Kluczowym krokiem jest wywołanie setOngoing(true), aby oznaczyć je jako powiadomienie o trwającej aktywności. Na tym etapie możesz też ustawić inne właściwości powiadomienia, takie jak mała ikona i kategoria.

// Create a PendingIntent to pass to the notification builder
val pendingIntent =
    PendingIntent.getActivity(
        this,
        0,
        Intent(this, AlwaysOnActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
        },
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
    )

val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("Always On Service")
    .setContentText("Service is running in background")
    .setSmallIcon(R.drawable.animated_walk)
    // Category helps the system prioritize the ongoing activity
    .setCategory(NotificationCompat.CATEGORY_WORKOUT)
    .setContentIntent(pendingIntent)
    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
    .setOngoing(true) // Important!

Tworzenie OngoingActivity

Następnie utwórz instancję OngoingActivity za pomocą jej narzędzia do tworzenia. OngoingActivity.Builder wymaga Context, identyfikatora powiadomienia i NotificationCompat.Builder utworzonego w poprzednim kroku.

Skonfiguruj kluczowe właściwości, które będą wyświetlane w nowych interfejsach:

  • Animowane i statyczne ikony: podaj ikony, które będą wyświetlane na tarczy zegarka w trybie aktywnym i nieaktywnym.
  • Intencja dotknięcia: PendingIntent która przenosi użytkownika z powrotem do Twojej aplikacji gdy kliknie ikonę Ongoing Activity. Możesz ponownie użyć pendingIndent utworzonego w poprzednim kroku.

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // Sets the icon that appears on the watch face in active mode.
        .setAnimatedIcon(R.drawable.animated_walk)
        // Sets the icon that appears on the watch face in ambient mode.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap target to bring the user back to the app.
        .setTouchIntent(pendingIntent)
        .build()

Zastosowanie do powiadomienia i opublikowanie

Ostatnim krokiem jest powiązanie OngoingActivity z powiadomieniem, a następnie opublikowanie go. Metoda ongoingActivity.apply() modyfikuje oryginalne narzędzie do tworzenia powiadomień, dodając niezbędne dane, aby system mógł wyświetlać je w dodatkowych interfejsach. Po zastosowaniu możesz utworzyć i opublikować powiadomienie jak zwykle.

// This call modifies notificationBuilder to include the ongoing activity data.
ongoingActivity.apply(applicationContext)

// Post the notification.
startForeground(NOTIFICATION_ID, notificationBuilder.build())

Dodawanie dynamicznego tekstu stanu do Menu z aplikacjami

Powyższy kod dodaje ikonę, którą można kliknąć, do tarczy zegarka. Aby zapewnić jeszcze bogatsze aktualizacje w czasie rzeczywistym w sekcji Ostatnie w Menu z aplikacjami, utwórz obiekt Status i dołącz go do OngoingActivity. Jeśli nie podasz niestandardowego Status, system domyślnie użyje tekstu treści powiadomienia (ustawionego za pomocą setContentText()). Aby wyświetlać tekst dynamiczny, użyj Status.Builder. Możesz zdefiniować ciąg szablonu z symbolami zastępczymi i podać obiekty Status.Part, aby wypełnić te symbole zastępcze. Status.Part może być dynamiczny, np. stoper lub minutnik.

Poniższy przykład pokazuje, jak utworzyć stan, który wyświetla „Bieg przez [stoper]”:

// Define a template with placeholders for the activity type and the timer.
val statusTemplate = "#type# for #time#"

// Set the start time for a stopwatch.
// Use SystemClock.elapsedRealtime() for time-based parts.
val runStartTime = SystemClock.elapsedRealtime()

val ongoingActivityStatus = Status.Builder()
    // Sets the template string.
    .addTemplate(statusTemplate)
    // Fills the #type# placeholder with a static text part.
    .addPart("type", Status.TextPart("Run"))
    // Fills the #time# placeholder with a stopwatch part.
    .addPart("time", Status.StopwatchPart(runStartTime))
    .build()

Na koniec połącz ten Status z OngoingActivity, wywołując setStatus() w OngoingActivity.Builder.

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // ...
        // Add the status to the OngoingActivity.
        .setStatus(ongoingActivityStatus)
        .build()

Dodatkowe dostosowania

Oprócz Status możesz dostosować Ongoing Activity lub powiadomienia na te sposoby. Jednak w zależności od implementacji OEM te dostosowania mogą nie być używane.

Trwające powiadomienie

  • Ustawiona kategoria określa priorytet Ongoing Activity.
    • CATEGORY_CALL: przychodzące połączenie głosowe lub wideo albo podobne synchroniczne żądanie komunikacji.
    • CATEGORY_NAVIGATION: mapa lub szczegółowa nawigacja.
    • CATEGORY_TRANSPORT: sterowanie odtwarzaniem multimediów.
    • CATEGORY_ALARM: alarm lub minutnik.
    • CATEGORY_WORKOUT: trening.
    • CATEGORY_LOCATION_SHARING: tymczasowa kategoria udostępniania lokalizacji.
    • CATEGORY_STOPWATCH: stoper.

Ongoing Activity

  • Animowana ikona: czarno-biała grafika wektorowa, najlepiej z przezroczystym tłem. Wyświetla się na tarczy zegarka w trybie aktywnym. Jeśli nie podasz animowanej ikony, użyta zostanie domyślna ikona powiadomienia. Domyślna ikona powiadomienia jest inna w każdej aplikacji.

  • Statyczna ikona: grafika wektorowa z przezroczystym tłem. Wyświetla się na tarczy zegarka w trybie nieaktywnym. Jeśli nie ustawisz animowanej ikony, statyczna ikona będzie używana na tarczy zegarka w trybie aktywnym. Jeśli nie podasz tej ikony, użyta zostanie ikona powiadomienia. Jeśli nie ustawisz żadnej z nich, zostanie zgłoszony wyjątek. (Menu z aplikacjami nadal używa ikony aplikacji).

  • OngoingActivityStatus: zwykły tekst lub Chronometer. Wyświetla się w sekcji Ostatnie w Menu z aplikacjami. Jeśli nie podasz tej ikony, użyty zostanie powiadomienie „tekst kontekstowy”.

  • Intencja dotknięcia: PendingIntent używana do przełączania się z powrotem do aplikacji, gdy użytkownik kliknie ikonę Ongoing Activity. Wyświetla się na tarczy zegarka lub w elemencie Menu z aplikacjami. Może się różnić od pierwotnej intencji użytej do uruchomienia aplikacji. Jeśli nie podasz tej ikony, użyta zostanie intencja treści powiadomienia. Jeśli nie ustawisz żadnej z nich, zostanie zgłoszony wyjątek.

  • LocusId: identyfikator, który przypisuje skrót do Menu z aplikacjami, z którym powiązana jest Ongoing Activity. Wyświetla się w Menu z aplikacjami w sekcji Ostatnie podczas trwania aktywności. Jeśli nie podasz tej ikony, Menu z aplikacjami ukryje wszystkie elementy aplikacji z tego samego pakietu w sekcji Ostatnie i wyświetli tylko Ongoing Activity.

  • Identyfikator Ongoing Activity: identyfikator używany do rozróżniania wywołań fromExistingOngoingActivity(), gdy aplikacja ma więcej niż 1 Ongoing Activity.

Aktualizowanie Ongoing Activity

Gdy musisz zmienić stan, zaktualizuj Ongoing Activity dla istniejącego powiadomienia, zamiast tworzyć nowe powiadomienie i Ongoing Activity. Aby zaktualizować Ongoing Activity i opublikowane powiadomienie, użyj utworzonego wcześniej obiektu i wywołaj update(), jak pokazano w tym przykładzie:

ongoingActivity.update(context, newStatus)

W przypadkach, gdy nie można zapisać odniesienia do Ongoing Activity, istnieje metoda statyczna, która umożliwia odzyskanie Ongoing Activity. Jest to jednak mniej preferowane rozwiązanie:

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

Zatrzymywanie Ongoing Activity

Gdy aplikacja zakończy działanie jako Ongoing Activity, wystarczy, że anuluje powiadomienie o trwającej aktywności.

Możesz też anulować powiadomienie lub Ongoing Activity, gdy przejdzie na pierwszy plan, a następnie utworzyć je ponownie, gdy wróci na drugi plan, ale nie jest to wymagane.

Wstrzymywanie Ongoing Activity

Jeśli Twoja aplikacja ma wyraźne działanie zatrzymania, kontynuuj Ongoing Activity po jej wznowieniu. W przypadku aplikacji bez wyraźnego działania zatrzymania zakończ aktywność, gdy zostanie wstrzymana.

Najważniejsze kwestie

Podczas pracy z interfejsem Ongoing Activity API pamiętaj o tych kwestiach:

  • Ustaw statyczną ikonę dla trwającej aktywności, albo bezpośrednio lub jako rezerwę za pomocą powiadomienia. W przeciwnym razie otrzymasz IllegalArgumentException.

  • Używaj czarno-białych ikon wektorowych z przezroczystym tłem.

  • Ustaw intencję dotknięcia dla trwającej aktywności, albo bezpośrednio lub jako rezerwę za pomocą powiadomienia. W przeciwnym razie otrzymasz IllegalArgumentException.

  • Jeśli Twoja aplikacja ma więcej niż 1 aktywność MAIN LAUNCHER zadeklarowaną w pliku manifestu, opublikuj skrót dynamiczny i powiąż go z Ongoing Activity za pomocą LocusId.

Publikowanie powiadomień multimedialnych podczas odtwarzania multimediów na urządzeniach z Wear OS

Jeśli na urządzeniu z Wear OS odtwarzane są treści multimedialne, opublikuj powiadomienie multimedialne. Dzięki temu system może utworzyć odpowiednią Ongoing Activity.

Jeśli używasz Media3, powiadomienie jest publikowane automatycznie. Jeśli tworzysz powiadomienie ręcznie, powinno ono używać MediaStyleNotificationHelper.MediaStyle, a odpowiednia MediaSession powinna mieć wypełnioną aktywność sesji.