Aktywne aktywności

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

Rozwiązaniem jest połączenie trwałego powiadomienia z OngoingActivity. Umożliwia to urządzeniu wyświetlanie informacji o długotrwałej aktywności w interfejsie użytkownika, co pozwala na korzystanie z funkcji takich jak ikona, w którą można kliknąć u dołu tarczy zegarka. Dzięki temu użytkownicy będą wiedzieć, że zadanie jest wykonywane w tle, i będą mogli jednym kliknięciem wrócić do aplikacji.

Trwająca aktywność sprawia też, że aplikacja jest widoczna dłużej, co zapobiega powrotowi systemu do tarczy zegarka po okresie bezczynności. Więcej informacji znajdziesz w artykule Zapewnianie widoczności aplikacji na urządzeniach Wear.

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

ikona biegania

Rysunek 1. Wskaźnik aktywności.

Trwałe powiadomienie wyświetla też informacje w sekcji Ostatnie globalnego programu uruchamiającego aplikacje. 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. Globalny program uruchamiający.

Oto przykłady sytuacji, w których warto użyć ciągłego powiadomienia powiązanego z ciągłą aktywnością:

licznik czasu

Rysunek 3. Minutnik: aktywnie odlicza czas i kończy się, gdy 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 ciągłe 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ącej aktywności.

Konfiguracja

Aby zacząć używać interfejsu Ongoing Activity API w 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.17.0"
}

Tworzenie działania ciągłego

Proces ten obejmuje 3 etapy:

  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ść w konstruktorze powiadomień i opublikuj wynikowe powiadomienie.

Tworzenie i konfigurowanie powiadomienia

Zacznij od utworzenia NotificationCompat.Builder. Kluczowym krokiem jest wywołanie funkcji setOngoing(true), aby oznaczyć powiadomienie jako bieżące. 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 obiektu OngoingActivity

Następnie utwórz instancję OngoingActivity za pomocą jej kreatora. Wymaga OngoingActivity.Builder, identyfikatora powiadomienia i NotificationCompat.Builder utworzonego w poprzednim kroku.Context

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

  • Animowane i statyczne ikony: udostępnij ikony, które będą wyświetlane na tarczy zegarka w trybie aktywnym i w trybie otoczenia.
  • Intencja dotknięcia: PendingIntent, która po dotknięciu ikony trwającej aktywności przenosi użytkownika z powrotem do aplikacji. 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()

Zastosuj do powiadomienia i posta

Ostatnim krokiem jest połączenie OngoingActivity z powiadomieniem, a następnie opublikowanie go. Metoda ongoingActivity.apply() modyfikuje oryginalny konstruktor powiadomień, dodając niezbędne dane, aby system mógł wyświetlać je na dodatkowych powierzchniach. Po zastosowaniu tego ustawienia możesz utworzyć i opublikować powiadomienie w zwykły sposób.

// 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 programu uruchamiającego

Powyższy kod dodaje ikonę, którą można kliknąć, do tarczy zegarka. Aby udostępniać jeszcze bardziej szczegółowe aktualizacje w czasie rzeczywistym w sekcji Ostatnie w programie uruchamiającym, utwórz obiekt Status i dołącz go do OngoingActivity. Jeśli nie podasz niestandardowego parametru Status, system domyślnie użyje tekstu powiadomienia (ustawionego za pomocą parametru setContentText()). Aby wyświetlić tekst dynamiczny, użyj parametru Status.Builder. Możesz zdefiniować ciąg szablonu z symbolami zastępczymi i podać Status.Part obiektów, aby je wypełnić. Status.Part może być dynamiczny, np. stoper lub minutnik.

Poniższy przykład pokazuje, jak utworzyć stan, który wyświetla „Biegaj 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 urządzeniem OngoingActivity, dzwoniąc pod numer setStatus() na 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ć bieżącą aktywność lub powiadomienia w następujący sposób: Jednak w zależności od implementacji producenta OEM te dostosowania mogą nie być używane.

Powiadomienie ciągłe

  • Ustawiona kategoria określa priorytet trwającej aktywności.
    • CATEGORY_CALL: przychodzące połączenie głosowe lub wideo albo podobna prośba o komunikację synchroniczną;
    • CATEGORY_NAVIGATION: mapę lub szczegółowe wskazówki nawigacyjne.
    • CATEGORY_TRANSPORT: sterowanie odtwarzaniem multimediów;
    • CATEGORY_ALARM: alarm lub minutnik.
    • CATEGORY_WORKOUT: trening
    • CATEGORY_LOCATION_SHARING: kategoria tymczasowego udostępniania lokalizacji
    • CATEGORY_STOPWATCH: stoper

Bieżąca aktywność

  • Animowana ikona: czarno-biała grafika wektorowa, najlepiej na przezroczystym tle. 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 różni się w zależności od aplikacji.

  • Statyczna ikona: ikona wektorowa z przezroczystym tłem. Wyświetla się na tarczy zegarka w trybie nieaktywnym. Jeśli animowana ikona nie jest ustawiona, w trybie aktywnym na tarczy zegarka jest używana ikona statyczna. Jeśli nie zostanie podana, użyta zostanie ikona powiadomienia. Jeśli nie jest ustawiona żadna z tych wartości, zgłaszany jest wyjątek. (Program uruchamiający aplikacje nadal używa ikony aplikacji).

  • OngoingActivityStatus: zwykły tekst lub Chronometer. Wyświetla się w sekcji Ostatnio używane w menu z aplikacjami. Jeśli nie zostanie podany, użyty zostanie „tekst kontekstowy” powiadomienia.

  • Touch Intent: PendingIntent używany do powrotu do aplikacji, jeśli użytkownik kliknie ikonę trwającej aktywności. Wyświetla się na tarczy zegarka lub w elemencie programu uruchamiającego. Może się różnić od pierwotnego zamiaru użytego do uruchomienia aplikacji. Jeśli nie zostanie podany, używany jest zamiar treści powiadomienia. Jeśli nie ustawisz żadnej z tych wartości, zostanie zgłoszony wyjątek.

  • LocusId: identyfikator przypisujący skrót launchera, do którego odnosi się trwająca aktywność. Wyświetla się w launcherze w sekcji Ostatnie podczas trwania aktywności. Jeśli nie podasz tej wartości, program uruchamiający ukryje wszystkie elementy aplikacji w sekcji Ostatnie z tego samego pakietu i wyświetli tylko trwającą aktywność.

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

Aktualizowanie trwającej aktywności

W większości przypadków, gdy deweloperzy chcą zaktualizować dane na ekranie, tworzą nowe powiadomienie ciągłe i nową aktywność ciągłą. Interfejs Ongoing Activity API udostępnia też metody pomocnicze do aktualizowania obiektu OngoingActivity, jeśli chcesz zachować instancję zamiast tworzyć ją od nowa.

Jeśli aplikacja działa w tle, może wysyłać aktualizacje do interfejsu Ongoing Activity API. Nie rób tego jednak zbyt często, ponieważ metoda aktualizacji ignoruje wywołania, które są zbyt blisko siebie. Kilka aktualizacji na minutę to rozsądna liczba.

Aby zaktualizować trwające działanie i opublikowane powiadomienie, użyj utworzonego wcześniej obiektu i wywołaj metodę update(), jak pokazano w tym przykładzie:

ongoingActivity.update(context, newStatus)

Dla wygody istnieje statyczna metoda tworzenia trwającej aktywności.

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

Zatrzymywanie trwającej aktywności

Gdy aplikacja zakończy działanie jako aktywność w toku, wystarczy, że anuluje powiadomienie o aktywności w toku.

Możesz też anulować powiadomienie lub trwającą aktywność, gdy przechodzi na pierwszy plan, a potem odtworzyć je, gdy wraca w tle, ale nie jest to wymagane.

Wstrzymywanie trwającej aktywności

Jeśli aplikacja ma wyraźną akcję zatrzymania, kontynuuj bieżącą aktywność po jej wznowieniu. W przypadku aplikacji bez wyraźnego działania zatrzymującego zakończ aktywność, gdy zostanie wstrzymana.

Sprawdzone metody

Podczas korzystania z interfejsu Ongoing Activity API pamiętaj o tych kwestiach:

  • Ustaw statyczną ikonę dla trwającej aktywności, jawnie lub jako rezerwę za pomocą powiadomienia. Jeśli nie, otrzymasz IllegalArgumentException.

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

  • Ustaw intencję dotyku dla bieżącej aktywności, jawnie lub jako rezerwę za pomocą powiadomienia. Jeśli nie, otrzymasz IllegalArgumentException.

  • Jeśli w pliku manifestu aplikacji zadeklarowano więcej niż 1 MAIN LAUNCHER aktywność, opublikuj dynamiczny skrót i powiąż go z bieżącą aktywnością za pomocą LocusId.

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

Jeśli na urządzeniu z Wear OS są odtwarzane multimedia, opublikuj powiadomienie o multimediach. Dzięki temu system może utworzyć odpowiednią aktywność ciągłą.

Jeśli używasz Media3, powiadomienie jest publikowane automatycznie. Jeśli tworzysz powiadomienie ręcznie, powinno ono korzystać z MediaStyleNotificationHelper.MediaStyle, a odpowiedni element MediaSession powinien zawierać aktywność sesji.