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. Te działania mogą też dostarczać ważne informacje, na których zależy użytkownikowi i do których potrzebuje on szybkiego dostępu.

Stwarza to wyzwanie związane z wygodą użytkowania: jeśli użytkownik rozpocznie zadanie, a następnie przejdzie do tarczy zegarka, powinien nadal mieć możliwość wykonania każdej z tych czynności:

  • otrzymywania ważnych aktualizacji;
  • powrotu do zadania jednym kliknięciem.

Powrót do aplikacji za pomocą Menu z aplikacjami może być trudny, zwłaszcza w ruchu, co powoduje niepotrzebne utrudnienia.

W Wear OS 7 rozwiązaniem jest powiązanie powiadomienia o trwającej aktywności z OngoingActivity lub powiadomieniem o aktualizacji na żywo. 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. Ten wskaźnik informuje użytkowników o zadaniu działającym w tle i umożliwia powrót do aplikacji jednym kliknięciem.

Trwająca aktywność lub aktualizacja na żywo sprawia też, że Twoja aplikacja jest widoczna dłużej, 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.

Używaj trwającej aktywności lub powiadomienia o aktualizacji na żywo w przypadku działań, które prawdopodobnie potrwają dłużej niż minutę, lub w sytuacjach, gdy użytkownik prawdopodobnie opuści Twoją aplikację przed zakończeniem zadania.

Odpowiednie zastosowania: śledzone treningi, minutniki, aktywne śledzenie przejazdu, dłuższe nagrywanie głosu, np. podczas spotkania, oraz listy zakupów, które muszą być dostępne, gdy użytkownik jest w sklepie.

Nieodpowiednie zastosowania: nagrywanie krótkich wiadomości głosowych, promocje, stan aktualizacji aplikacji i nadchodzące wydarzenia w kalendarzu.

Ważne: korzystanie z OngoingActivity lub aktualizacji na żywo w tych scenariuszach jest wymagane zgodnie z wskazówkami dotyczącymi jakości aplikacji na Wear OS WO-V4.

Na przykład w tej aplikacji do ćwiczeń 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 globalnym Menu z aplikacjami. Jest to kolejne wygodne miejsce, w którym użytkownicy mogą sprawdzić stan swojego 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 trwającą aktywnością:

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 trwające aktywności w przypadku aplikacji multimedialnych.

Szczegółowy przykład tworzenia trwających aktywności w przypadku innych rodzajów aplikacji znajdziesz w ćwiczeniach z programowania dotyczących trwających aktywności.

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.19.0"
}

Tworzenie trwającej aktywności

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. Narzędzie OngoingActivity.Builder wymaga Context, identyfikatora powiadomienia i narzędzia NotificationCompat.Builder utworzonego w poprzednim kroku.

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

  • Ikony animowane i statyczne: 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 dotknie on ikony trwającej aktywności. 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ć trwającą aktywność 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 trwającej aktywności.
    • 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.

Trwająca aktywność

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

  • Ikona statyczna: grafika wektorowa z przezroczystym tłem. Wyświetla się na tarczy zegarka w trybie nieaktywnym. Jeśli nie ustawisz ikony animowanej, ikona statyczna będzie używana na tarczy zegarka w trybie aktywnym. Jeśli nie podasz ikony statycznej, użyta zostanie ikona powiadomienia. Jeśli nie ustawisz żadnej z tych ikon, 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 wartości, użyty zostanie powiadomienie „tekst kontekstowy”.

  • Intencja dotknięcia: PendingIntent używana do przełączania się z powrotem do aplikacji, gdy użytkownik dotknie ikony trwającej aktywności. 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 wartości, użyta zostanie intencja treści powiadomienia. Jeśli nie ustawisz żadnej z tych intencji, zostanie zgłoszony wyjątek.

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

  • Identyfikator trwającej aktywności: identyfikator używany do rozróżniania wywołań fromExistingOngoingActivity(), gdy aplikacja ma więcej niż 1 trwającą aktywność.

Aktualizowanie trwającej aktywności

Gdy musisz zmienić stan, zaktualizuj trwającą aktywność w przypadku istniejącego powiadomienia, zamiast tworzyć nowe powiadomienie i trwającą aktywność. Aby zaktualizować trwającą aktywność 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 trwającej aktywności, istnieje metoda statyczna umożliwiająca jej odzyskanie. Jest to jednak mniej preferowane rozwiązanie:

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

Zatrzymywanie trwającej aktywności

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

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

Wstrzymywanie trwającej aktywności

Jeśli Twoja aplikacja ma wyraźne działanie zatrzymania, kontynuuj trwającą aktywność 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 ikonę statyczną 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 w manifeście zadeklarowaną więcej niż 1 aktywność MAIN LAUNCHER, opublikuj skrót dynamiczny i powiąż go z trwającą aktywnością 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ą trwającą aktywność.

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.