Korzystanie z biblioteki aplikacji Android for Cars

Biblioteka aplikacji Android for Cars umożliwia korzystanie z aplikacji do nawigacji, informacji o miejscach i Internetu rzeczy w samochodzie. Udostępnia on zestaw szablonów zaprojektowanych zgodnie ze standardami dotyczącymi rozpraszania uwagi kierowcy i uwzględniający takie szczegóły, jak różnorodność czynników związanych z ekranem w samochodzie i metodami wprowadzania danych.

Z tego przewodnika dowiesz się, jak skonfigurować podstawową aplikację, a także poznasz najważniejsze funkcje i koncepcje biblioteki.

Zanim zaczniesz

  1. Zapoznaj się z artykułem Projektowanie dla kierowców Strony obejmujące bibliotekę aplikacji samochodowych
  2. Zapoznaj się z kluczowymi terminami i pojęciami w tym artykule .
  3. Zapoznaj się z systemem Android Auto Interfejs i system operacyjny Android Automotive projektu.
  4. Zapoznaj się z informacjami o wersji.
  5. Przejrzyj przykłady.

Najważniejsze terminy i koncepcje

Modele i szablony
Interfejs użytkownika jest reprezentowany przez graf obiektów modelu, które można układać na różne sposoby w ramach możliwości danego szablonu. Szablony są podzbiorem modeli, które mogą stanowić podstawę wykresy. Modele zawierają informacje, które mają być wyświetlane użytkownikowi w formy tekstu i obrazów, a także atrybuty służące do konfigurowania wygląd takich informacji, np. kolory tekstu lub obrazy rozmiarów reklam Google Ads. Host konwertuje modele na widoki, które spełniają standardy dotyczące rozpraszania uwagi kierowcy, i dba o szczegóły, takie jak różnorodność czynników ekranu samochodowego i modalności wprowadzania danych.
Zorganizuj
Host to komponent backendu, który implementuje funkcje oferowane przez interfejsy API biblioteki, aby aplikacja mogła działać w samochodzie. obowiązkiem gospodarza jest znalezienie aplikacji i zarządzanie nią, jego cyklu życia, przekształcania modeli w widoki i powiadamiania aplikacji interakcji użytkowników. Na urządzeniach mobilnych host jest implementowany przez Androida. W systemie operacyjnym Android Automotive ten host jest instalowany jako aplikacja systemowa.
Ograniczenia dotyczące szablonów
Różne szablony nakładają ograniczenia na zawartość modeli. Dla: Na przykład szablony list mają ograniczoną liczbę elementów, które można umieścić przedstawiane użytkownikowi. Szablony mają też ograniczenia dotyczące sposobu ich łączenia w ramach procesu wykonania zadania. Na przykład aplikacja może przesłać do stosu ekranów maksymalnie 5 szablonów. Zobacz Więcej informacji znajdziesz w artykule Ograniczenia szablonów.
Screen
Screen to zajęcia prowadzone przez biblioteka implementowana przez aplikacje do zarządzania interfejsem prezentowanym użytkownika. Screen ma cykl życia i zapewnia mechanizm wysłać szablon do wyświetlenia, gdy ekran jest widoczny. Można również przekazać Screen instancję i przechodził do i z stosu Screen, który zapewnia, że są one zgodne z ograniczeniach przepływu szablonów.
CarAppService
CarAppService to abstrakcyjna klasa Service, którą Twoja aplikacja musi zaimplementować i wyeksportować, aby była wykrywana i zarządzana przez hosta. CarAppService w Twojej aplikacji to odpowiedzialny za weryfikację, czy połączenie z hostem jest zaufane, przy użyciu createHostValidator. a potem udostępniając Session instancji dla każdego połączenia za pomocą onCreateSession.
Session

Session jest klasą abstrakcyjną, która aplikacja musi wdrożyć i zwrócić za pomocą CarAppService.onCreateSession Jest punktem wejścia do wyświetlania informacji na ekranie samochodu. it ma cykl życia, na podstawie którego bieżący stan aplikacji na ekranie samochodu, np. gdy aplikacja jest widoczne lub ukryte.

Gdy Session jest uruchamiany, np. podczas pierwszego uruchamiania aplikacji, host prosi o wyświetlenie początkowego Screen za pomocą metody onCreateScreen.

Instalowanie biblioteki aplikacji w samochodzie

Zobacz bibliotekę Jetpack stronie wersji usługi instrukcje dodawania biblioteki do aplikacji.

Konfigurowanie plików manifestu aplikacji

Zanim utworzysz aplikację samochodową, skonfiguruj pliki manifestu aplikacji w ten sposób:

Deklarowanie usługi CarAppService

Host łączy się z Twoją aplikacją przez CarAppService. Ty zadeklaruj tę usługę w pliku manifestu, aby host mógł wykryć i nawiązać połączenie do Twojej aplikacji.

Kategorię aplikacji musisz też zadeklarować w <category> elementu aplikacji filtr intencji. Zobacz listę obsługiwanych kategorii aplikacji w przypadku wartości dozwolonych w przypadku wartości ten element.

Ten fragment kodu pokazuje, jak w pliku manifestu zadeklarować usługę aplikacji samochodowej dla aplikacji typu punkt zainteresowania:

<application>
    ...
   <service
       ...
        android:name=".MyCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService"/>
        <category android:name="androidx.car.app.category.POI"/>
      </intent-filter>
    </service>

    ...
<application>

Obsługiwane kategorie aplikacji

Określ kategorię aplikacji, dodając co najmniej jedną z tych kategorii wartości w filtrze intencji po zadeklarowaniu CarAppService w sposób opisany w poprzedniej sekcji:

  • androidx.car.app.category.NAVIGATION: aplikacja, która wyświetla wskazówki dojazdu zakręt po zakręcie. Więcej informacji o tej kategorii znajdziesz w dokumentacji Tworzenie aplikacji do nawigacji dla samochodów.
  • androidx.car.app.category.POI: aplikacja, która oferuje funkcje przydatne podczas wyszukiwania. do znajdowania ciekawych miejsc, takich jak miejsca parkingowe, stacje ładowania stacji paliw. Aby uzyskać więcej informacji o tej kategorii, zapoznaj się z artykułem Tworzenie aplikacji z punktami zainteresowania dla samochodów.
  • androidx.car.app.category.IOT: aplikacja umożliwiająca użytkownikom podejmowanie odpowiednich działań na połączonych urządzeniach z poziomu samochodu. Wymelduj się Tworzenie internetu rzeczy dla samochodów zapoznaj się z dodatkowymi materiałami dotyczącymi tej kategorii.

Zobacz jakość aplikacji na Androida dla samochodów – szczegółowe opisy poszczególnych kategorii i kryteriów, według których dana aplikacja należy do nich.

Podaj nazwę i ikonę aplikacji

Musisz podać nazwę i ikonę aplikacji, których host może używać do reprezentowania aplikacji w interfejsie systemu.

Nazwę i ikonę aplikacji, która będzie reprezentować Twoją aplikację, możesz określić za pomocą atrybutów labelicon:

...
<service
   android:name=".MyCarAppService"
   android:exported="true"
   android:label="@string/my_app_name"
   android:icon="@drawable/my_app_icon">
   ...
</service>
...

Jeśli etykieta lub ikona nie są zadeklarowane w element <service>, host zwraca wartości określone dla argumentu Element <application>.

Ustawianie motywu niestandardowego

Aby ustawić niestandardowy motyw dla aplikacji samochodowej, dodaj element <meta-data> do pliku manifestu w ten sposób:

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

Następnie zadeklaruj zasób stylu ustaw te atrybuty niestandardowego motywu aplikacji samochodowej:

<resources>
  <style name="MyCarAppTheme">
    <item name="carColorPrimary">@layout/my_primary_car_color</item>
    <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item>
    <item name="carColorSecondary">@layout/my_secondary_car_color</item>
    <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item>
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

Poziom interfejsu API aplikacji samochodu

Biblioteka aplikacji samochodowych definiuje własne poziomy interfejsu API, aby można było sprawdzić, które funkcje biblioteki są obsługiwane przez hosta szablonu w samochodzie. Aby pobrać najwyższy poziom interfejsu API aplikacji samochodowej obsługiwany przez hosta, użyj getCarAppApiLevel() .

Zadeklaruj minimalny poziom interfejsu API aplikacji samochodowej obsługiwany przez Twoją aplikację w Plik AndroidManifest.xml:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

W dokumentacji dotyczącej adnotacji RequiresCarApi znajdziesz szczegółowe informacje o zachowaniu zgodności wstecznej i deklarowaniu minimalnego poziomu interfejsu API wymaganego do korzystania z funkcji. Definicja interfejsu API jest wymagany, aby można było korzystać z określonej funkcji biblioteki aplikacji samochodowej, sprawdź dokumentacja dla CarAppApiLevels

Tworzenie usługi CarAppService i sesji

Aplikacja musi rozszerzać klasę CarAppService i implementować jej metodę onCreateSession, która zwraca instancję Session odpowiadającą bieżącemu połączeniu z hostem:

Kotlin

class HelloWorldService : CarAppService() {
    ...
    override fun onCreateSession(): Session {
        return HelloWorldSession()
    }
    ...
}

Java

public final class HelloWorldService extends CarAppService {
    ...
    @Override
    @NonNull
    public Session onCreateSession() {
        return new HelloWorldSession();
    }
    ...
}

Instancja Session jest odpowiedzialna za przez zwrócenie instancji Screen, aby można było użyć przy pierwszym uruchomieniu aplikacji:

Kotlin

class HelloWorldSession : Session() {
    ...
    override fun onCreateScreen(intent: Intent): Screen {
        return HelloWorldScreen(carContext)
    }
    ...
}

Java

public final class HelloWorldSession extends Session {
    ...
    @Override
    @NonNull
    public Screen onCreateScreen(@NonNull Intent intent) {
        return new HelloWorldScreen(getCarContext());
    }
    ...
}

aby obsługiwać sytuacje, w których aplikacja samochodu musi uruchamiać się na ekranie, który nie jest ekran główny lub ekran docelowy aplikacji, np. obsługa precyzyjnych linków, możesz aby wstępnie zapełnić tylny stos ekranów za pomocą ScreenManager.push przed powrót z onCreateScreen Wstępna selekcja umożliwia użytkownikom przechodzenie do poprzednich ekranów z pierwszego ekranu wyświetlanego przez aplikację.

Tworzenie ekranu startowego

Ekrany wyświetlane przez aplikację tworzysz, definiując klasy, które rozszerzają klasę Screen, i wdrażając metodę onGetTemplate, która zwraca instancję Template reprezentującą stan interfejsu użytkownika do wyświetlenia na ekranie samochodu.

Ten fragment kodu pokazuje, jak zadeklarować element Screen, który używa szablonu PaneTemplate do wyświetlania prostego ciągu znaków „Hello world!”:

Kotlin

class HelloWorldScreen(carContext: CarContext) : Screen(carContext) {
    override fun onGetTemplate(): Template {
        val row = Row.Builder().setTitle("Hello world!").build()
        val pane = Pane.Builder().addRow(row).build()
        return PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build()
    }
}

Java

public class HelloWorldScreen extends Screen {
    @NonNull
    @Override
    public Template onGetTemplate() {
        Row row = new Row.Builder().setTitle("Hello world!").build();
        Pane pane = new Pane.Builder().addRow(row).build();
        return new PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build();
    }
}

Klasa CarContext

Klasa CarContext to Podklasa ContextWrapper dostępne na urządzeniach Session i Screen instancji. Zapewnia dostęp do usług samochodowych, takich jak ScreenManager do zarządzania strukturą ekranu, AppManager do ogólnych funkcji aplikacji, takich jak dostęp do obiektu Surface do rysowania map, oraz NavigationManager używany przez aplikacje nawigacji z naprowadzaniem do przesyłania metadanych nawigacji i innych zdarzeń związanych z nawigacją do hosta.

Patrz: Dostęp do nawigacji szablonów obszerna lista funkcji biblioteki dostępnych w aplikacjach do nawigacji.

CarContext oferuje też inne funkcje, takie jak możliwość wczytywania zasobów do wyświetlania za pomocą konfiguracji z ekranu samochodu, uruchamianie aplikacji w samochodzie za pomocą intencji oraz sygnalizowanie, czy aplikacja ma wyświetlać mapę w ciemnym motywie.

Wdróż nawigację po ekranie

Aplikacje często zawierają wiele różnych ekranów, z których każdy może używać różnych szablonów, po których użytkownik może się poruszać, korzystając z interfejsu wyświetlanego na ekranie.

Klasa ScreenManager udostępnia zestaw ekranów, które możesz przesuwać, aby wyświetlać ekrany, które mogą być automatycznie wyświetlane, gdy użytkownik kliknie przycisk Wstecz na ekranie samochodu lub użyje przycisku Wstecz na sprzęcie (dostępnego w niektórych samochodach).

Ten fragment kodu pokazuje, jak dodać do szablonu wiadomości działanie wstecz, a także działanie, które powoduje wyświetlenie nowego ekranu po wybraniu przez użytkownika:

Kotlin

val template = MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener { screenManager.push(NextScreen(carContext)) }
            .build())
    .build()

Java

MessageTemplate template = new MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        new Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener(
                () -> getScreenManager().push(new NextScreen(getCarContext())))
            .build())
    .build();

Obiekt Action.BACK to standardowy obiekt Action, który automatycznie wywołuje obiekt ScreenManager.pop. To zachowanie można zastąpić, używając instancji OnBackPressedDispatcher dostępnej w CarContext.

Aby można było bezpiecznie używać aplikacji podczas jazdy, stos ekranów może mieć maksymalnie dzięki głębokości 5 ekranów. Więcej informacji znajdziesz w sekcji Ograniczenia dotyczące szablonów.

Odświeżanie zawartości szablonu

Aplikacja może prosić o dostęp do treści Screen do unieważnienia przez wywołanie metody Metoda Screen.invalidate. Następnie host nawiązuje połączenie z adresem Twojej aplikacji Screen.onGetTemplate , aby pobrać szablon z nową zawartością.

Gdy odświeżasz Screen, ważne jest zrozumienie, jakie treści w szablonie można aktualizować więc host nie wlicza nowego szablonu do limitu szablonów. Więcej informacji znajdziesz w sekcji Ograniczenia dotyczące szablonów.

Zalecamy zorganizowanie ekranów w taki sposób, aby były one dobrze dopasowane mapowanie między elementem Screen a typem który jest zwracany przez implementację onGetTemplate.

Rysuj mapy

Aplikacje do nawigacji i ciekawych miejsc, korzystające z poniższych szablonów, mogą rysuj mapy, korzystając z Surface:

Szablon Uprawnienia szablonu Wskazówki dotyczące kategorii
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES Nawigacja
MapWithContentTemplate androidx.car.app.NAVIGATION_TEMPLATES LUB
androidx.car.app.MAP_TEMPLATES
Nawigacja, miejsca docelowego
MapTemplate (wycofane) androidx.car.app.NAVIGATION_TEMPLATES Nawigacja
PlaceListNavigationTemplate (wycofane) androidx.car.app.NAVIGATION_TEMPLATES Nawigacja
RoutePreviewNavigationTemplate (wycofane) androidx.car.app.NAVIGATION_TEMPLATES Nawigacja

Zadeklaruj uprawnienie do wyświetlania

Oprócz uprawnień wymaganych w przypadku szablonu, z którego korzysta Twoja aplikacja, aplikacja musi zadeklarować uprawnienie androidx.car.app.ACCESS_SURFACE w swoim AndroidManifest.xml plik, aby uzyskać dostęp do platformy:

<manifest ...>
  ...
  <uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
  ...
</manifest>

Dostęp do powierzchni

Aby uzyskać dostęp do Surface, który udostępnia host, musisz wdrożyć SurfaceCallback i udostępnić tę implementację usłudze AppManagercar. Bieżąca wartość Surface jest przekazywana do funkcji SurfaceCallback w parametrze SurfaceContainer funkcji onSurfaceAvailable()onSurfaceDestroyed().

Kotlin

carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)

Java

carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);

Poznaj widoczny obszar powierzchni

Host może rysować elementy interfejsu dla szablonów na mapę. Host komunikuje się na powierzchni, która ma być nieprzesłonięty i w pełni widoczny dla użytkownika przez wywołanie metody SurfaceCallback.onVisibleAreaChanged . Aby zminimalizować liczbę zmian, gospodarz wywołuje metodę SurfaceCallback.onStableAreaChanged z najmniejszym prostokątem, który jest zawsze widoczny na podstawie argumentu obecny szablon.

Jeśli na przykład aplikacja do nawigacji korzysta z elementu NavigationTemplatepaskiem akcji u góry ekranu, pasek akcji może się ukryć, gdy użytkownik przez jakiś czas nie wchodzi w interakcję z ekranem, aby zrobić więcej miejsca na mapę. W tym przypadku jest wywołanie funkcji onStableAreaChangedonVisibleAreaChanged z tym samym prostokątem. Gdy pasek działań jest ukryty, wywoływana jest tylko funkcja onVisibleAreaChanged z większym obszarem. Jeśli użytkownik wejdzie w interakcję z ekranem, po czym ponownie zostanie wywołany tylko element onVisibleAreaChanged z pierwszego prostokąta.

Obsługa ciemnego motywu

Aplikacje muszą ponownie narysować mapę na instancji Surface w odpowiednim kolorze ciemnego gdy host określi odpowiednie warunki, zgodnie z opisem w Jakość aplikacji na Androida dla samochodów.

Aby zdecydować, czy chcesz narysować ciemną mapę, możesz użyć metody CarContext.isDarkMode. Po każdej zmianie stanu ciemnego motywu otrzymasz połączenie z Session.onCarConfigurationChanged

Umożliwienie użytkownikom interakcji z mapą

Korzystając z podanych niżej szablonów, możesz umożliwić użytkownikom interakcję z rysowanymi przez Ciebie mapami, np. przeglądanie różnych części mapy przez powiększanie i przesuwanie.

Szablon Obsługa interaktywności od poziomu interfejsu Car App API
NavigationTemplate 2
PlaceListNavigationTemplate (wycofane) 4
RoutePreviewNavigationTemplate (wycofane) 4
MapTemplate (wycofane) 5 (wprowadzenie szablonu)
MapWithContentTemplate 7 (wprowadzenie szablonu)

Wdrażanie interaktywnych wywołań zwrotnych

Interfejs SurfaceCallback udostępnia kilka metod wywołania, które możesz zastosować, aby dodać interaktywność do map utworzonych za pomocą szablonów z poprzedniej sekcji:

Interakcja SurfaceCallback metoda Obsługiwane od poziomu interfejsu Car App API
Kliknij onClick 5
Ściągnij, aby powiększyć onScale 2
Przeciąganie jednym dotknięciem onScroll 2
Przesuwanie jednym kliknięciem onFling 2
Kliknij dwukrotnie onScale (z współczynnikiem skalowania określonym przez hosta szablonu) 2
Posuw obrotowy w trybie przesuwania onScroll (ze współczynnikiem odległości określanym przez hosta szablonu) 2

Dodaj pasek działań na mapie

Te szablony mogą zawierać pasek działań związanych z mapą, np. powiększanie i pomniejszanie, ponowne wyśrodkowywanie, wyświetlanie kompasu i inne działania, które wybierzesz do wyświetlenia. Pasek czynności na mapie może zawierać maksymalnie 4 przyciski z ikonami, które można odświeżać bez wpływu na głębokość zadania. Ukrywa się w stanie bezczynności i pojawia się ponownie w stanie aktywności.

Aby otrzymywać wywołania zwrotne interakcji z mapą, musisz dodać przycisk Action.PAN do paska działań na mapie. Gdy użytkownik naciśnie przycisk przesuwania, host przejdzie w tryb przesuwania, jak opisano w .

Jeśli Twoja aplikacja pomija przycisk Action.PAN na pasku działań na mapie, nie otrzymuje danych wejściowych od użytkownika z metod SurfaceCallback, a gospodarz opuszcza wcześniej aktywowany tryb panoramowania.

Na ekranie dotykowym przycisk przesuwania nie jest wyświetlany.

Informacje o trybie przesuwania

W trybie przesuwania host szablonu tłumaczy dane wejściowe użytkownika bez użycia dotykowego wprowadzania danych takich jak kontrolery obrotowe i touchpady, SurfaceCallback metody. Odpowiedź na działanie użytkownika polegające na wejściu w tryb panoramowania lub wyjściu z niego za pomocą metody setPanModeListener w komponencie NavigationTemplate.Builder. Host może ukryć inny interfejs w szablonie, gdy użytkownik jest w trybie przesuwania.

Interakcja z użytkownikiem

Aplikacja może wchodzić w interakcję z użytkownikiem za pomocą wzorców podobnych do aplikacji mobilnej.

Obsługa danych wejściowych użytkownika

Aplikacja może reagować na dane wejściowe użytkownika, przekazując odpowiednie odbiorniki do modeli, które je obsługują. Ten fragment kodu pokazuje, jak utworzyć model Action, który ustawia zmienną OnClickListener wywołującą metodę zdefiniowaną w kodzie aplikacji:

Kotlin

val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()

Java

Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

Metoda onClickNavigate może wtedy uruchomić metodę domyślna aplikacja do nawigacji za pomocą CarContext.startCarApp :

Kotlin

private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}

Java

private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

Więcej informacji o uruchamianiu aplikacji, w tym o formacie intencjonalnego wywołania ACTION_NAVIGATE, znajdziesz w sekcji Uruchamianie aplikacji samochodowej za pomocą intencjonalnego wywołania.

Niektóre działania, takie jak te, które wymagają od użytkownika kontynuowania interakcji na urządzeniu mobilnym, są dozwolone tylko wtedy, gdy samochód jest zaparkowany. Aby wdrożyć te działania, możesz użyć interfejsu ParkedOnlyOnClickListener. Jeśli samochód nie jest zaparkowany, gospodarz wyświetla komunikat aby poinformować użytkownika, że dane działanie jest w danym przypadku niedozwolone. Jeśli samochód jest zaparkowany, kod jest wykonywany normalnie. Ten fragment kodu pokazuje, jak użyć przycisku ParkedOnlyOnClickListener, aby otworzyć ekran ustawień na urządzeniu mobilnym:

Kotlin

val row = Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone))
    .build()

Java

Row row = new Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone))
    .build();

Wyświetlanie powiadomień

Powiadomienia wysyłane na urządzenie mobilne wyświetlają się na ekranie samochodu tylko wtedy, gdy są rozszerzone o CarAppExtender Niektóre atrybuty powiadomień, takie jak tytuł treści, tekst, ikona i działania, można ustawić w CarAppExtender, zastępując atrybuty powiadomienia gdy pojawią się na ekranie samochodu.

Ten fragment kodu pokazuje, jak wysłać powiadomienie na ekran samochodu, który zawiera inny tytuł niż na urządzeniu mobilnym:

Kotlin

val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build()

Java

Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build();

Powiadomienia mogą wpływać na te części interfejsu użytkownika:

  • Użytkownik może zobaczyć powiadomienie o zbliżającym się terminie.
  • W centrum powiadomień można dodać wpis, opcjonalnie z plakietką widoczne na szynie.
  • W przypadku aplikacji nawigacyjnych powiadomienie może być wyświetlane w widżecie kolei jako opisane w Powiadomienia zakręt po zakręcie

Możesz wybrać sposób konfigurowania powiadomień aplikacji, aby wpływać na te elementy interfejsu użytkownika, używając priorytetu powiadomienia zgodnie z opisem w dokumentacji CarAppExtender.

Jeśli NotificationCompat.Builder.setOnlyAlertOnce jest wywoływane z wartością true, powiadomienie o wysokim priorytecie jest wyświetlane jako HUN tylko raz.

Więcej informacji o projektowaniu powiadomień aplikacji samochodowej znajdziesz w przewodniku Google Design for Driving dotyczącym powiadomień.

Wyświetlanie komunikatów

Aplikacja może wyświetlać toast za pomocą CarToast jak w tym fragmencie:

Kotlin

CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()

Java

CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();

Poproś o uprawnienia

Jeśli aplikacja wymaga dostępu do danych lub działań podlegających ograniczeniom, na przykład lokalizacja – standardowe reguły Androida, uprawnienia zastosuj. Aby poprosić o uprawnienia, możesz użyć metody CarContext.requestPermissions().

Zaletą korzystania z interfejsu CarContext.requestPermissions() w porównaniu z używaniem standardowych interfejsów API Androida jest to, że nie musisz uruchamiać własnego interfejsu Activity, aby utworzyć okno z uprawnieniami. Co więcej, możesz używać tego samego kodu zarówno w Android Auto, jak i w systemie operacyjnym Android Automotive, zamiast tworzyć przepływy zależne od platformy.

Określanie stylu okna uprawnień w Androidzie Auto

W Androidzie Auto na telefonie pojawi się okno uprawnień użytkownika. Domyślnie tło nie będzie widoczne za oknem dialogowym. Aby ustawić niestandardowe tło, w pliku AndroidManifest.xml zadeklaruj motyw aplikacji samochodowej i ustaw atrybut carPermissionActivityLayout dla motywu aplikacji samochodowej.

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

Następnie ustaw atrybut carPermissionActivityLayout dla motywu aplikacji samochodowej:

<resources>
  <style name="MyCarAppTheme">
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

Uruchamianie aplikacji samochodowej z zamiarem

Możesz wywołać metodę CarContext.startCarApp, aby wykonać jedną z tych czynności:

  • Aby zadzwonić, otwórz aplikację Telefon.
  • Rozpocznij szczegółową nawigację do lokalizacji za pomocą domyślna aplikacja do nawigacji.
  • Uruchom własną aplikację z intencją.

Przykład poniżej pokazuje, jak utworzyć powiadomienie z działaniem, otwiera aplikację na ekranie ze szczegółami rezerwacji parkingu. Rozszerzasz instancję powiadomienia o intencję dotyczącą treści, która zawiera PendingIntent Opakowywanie elementu dla pełnoletnich zamiar związany z działaniem Twojej aplikacji:

Kotlin

val notification = notificationBuilder
    ...
    .extend(
        CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(ComponentName(context, MyNotificationReceiver::class.java)),
                    0))
            .build())

Java

Notification notification = notificationBuilder
    ...
    .extend(
        new CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    new Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(new ComponentName(context, MyNotificationReceiver.class)),
                    0))
            .build());

Aplikacja musi również zadeklarować BroadcastReceiver, czyli wywołana w celu przetworzenia intencji, gdy użytkownik wybierze działanie w interfejsu powiadomień i wywołuje CarContext.startCarApp z intencją zawierającą identyfikator URI danych:

Kotlin

class MyNotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val intentAction = intent.action
        if (ACTION_VIEW_PARKING_RESERVATION == intentAction) {
            CarContext.startCarApp(
                intent,
                Intent(Intent.ACTION_VIEW)
                    .setComponent(ComponentName(context, MyCarAppService::class.java))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)))
        }
    }
}

Java

public class MyNotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) {
            CarContext.startCarApp(
                intent,
                new Intent(Intent.ACTION_VIEW)
                    .setComponent(new ComponentName(context, MyCarAppService.class))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)));
        }
    }
}

Pamiętaj też, że Session.onNewIntent w aplikacji obsługuje tę intencję, przesuwając ekran rezerwacji parkingu. w grupie, jeśli jeszcze nie ma jej na górze:

Kotlin

override fun onNewIntent(intent: Intent) {
    val screenManager = carContext.getCarService(ScreenManager::class.java)
    val uri = intent.data
    if (uri != null
        && MY_URI_SCHEME == uri.scheme
        && MY_URI_HOST == uri.schemeSpecificPart
        && ACTION_VIEW_PARKING_RESERVATION == uri.fragment
    ) {
        val top = screenManager.top
        if (top !is ParkingReservationScreen) {
            screenManager.push(ParkingReservationScreen(carContext))
        }
    }
}

Java

@Override
public void onNewIntent(@NonNull Intent intent) {
    ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
    Uri uri = intent.getData();
    if (uri != null
        && MY_URI_SCHEME.equals(uri.getScheme())
        && MY_URI_HOST.equals(uri.getSchemeSpecificPart())
        && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment())
    ) {
        Screen top = screenManager.getTop();
        if (!(top instanceof ParkingReservationScreen)) {
            screenManager.push(new ParkingReservationScreen(getCarContext()));
        }
    }
}

Więcej informacji o obsługiwaniu powiadomień z aplikacji samochodowej znajdziesz w sekcji Wyświetlanie powiadomień.

Ograniczenia dotyczące szablonów

Host ogranicza liczbę szablonów wyświetlanych w przypadku danego zadania do maksymalnie 5. Ostatni z nich musi być jednym z tych typów:

Pamiętaj, że ten limit dotyczy liczby szablonów, a nie liczby instancji Screen w zestawie. Dla: Jeśli na przykład aplikacja wysyła 2 szablony na ekranie A, a następnie przesyła ekran B, można wysłać 3 kolejne szablony. Jeśli natomiast każdy ekran jest sformatowany w taki sposób, aby wysyłać pojedynczy szablon, aplikacja może przesłać 5 ekranów do stosu ScreenManager.

Istnieją specjalne przypadki tych ograniczeń: odświeżanie szablonów oraz operacje przywracania i resetowania.

Odświeżanie szablonów

Niektóre aktualizacje treści nie są wliczane do limitu szablonów. Ogólnie rzecz biorąc, jeśli aplikacja przekazuje nowy szablon, który jest tego samego typu i zawiera zawiera tę samą główną zawartość co poprzedni, nowy szablon nie jest wliczane do limitu. Na przykład zaktualizowanie stanu przełączania wiersza w ListTemplate nie liczy się do osiągnięcia limitu. Więcej informacji znajdziesz w dokumentacji poszczególnych szablonów o typach aktualizacji treści, które można uznać za odświeżenie.

Operacje wsteczne

Aby włączyć podprzepływy w ramach zadania, host wykrywa, kiedy aplikacja wyciąga Screen z poziomu ScreenManager, i aktualizuje pozostałą pulę na podstawie liczby szablonów, o które aplikacja się cofa.

Jeśli na przykład aplikacja wysyła 2 szablony na ekranie A, a następnie przekazuje ekranu B i wyśle 2 kolejne szablony, aplikacji pozostanie 1 limit. Jeśli aplikacja wraca do ekranu A, host resetuje limit do trzech, ponieważ aplikacja została cofnięta o 2 szablony.

Pamiętaj, że po powrocie na ekran aplikacja musi wysłać szablon, który jest tego samego typu co ostatnio wysłane przez ten ekran. Wysyłanie innego typu szablonu powoduje błąd. Dopóki jednak ten typ pozostanie tak samo podczas operacji cofania, aplikacja może dowolnie modyfikować zawartość bez wpływu na limit.

Reset operations

Niektóre szablony mają specjalną semantykę, która oznacza koniec zadania. Na przykład NavigationTemplate to widok, który powinien pozostać na ekranie i być odświeżany o nowe szczegółowe wskazówki dla użytkownika. Gdy dotrze do jednego z tych szablonów, host resetuje limit szablonów, traktując ten szablon jak pierwszy krok nowego zadania. Dzięki temu aplikacja będzie mogła rozpocząć nowe zadanie. W dokumentacji poszczególnych szablonów znajdziesz informacje o tym, które z nich powodują resetowanie hosta.

jeśli host otrzymuje intencję uruchomienia aplikacji w wyniku działania powiadomienia lub z Menu z aplikacjami limit też zostanie zresetowany. Ten mechanizm umożliwia aplikacji rozpoczęcie nowego procesu działania na podstawie powiadomień. Działa on nawet wtedy, gdy aplikacja jest już związana i znajduje się na pierwszym planie.

Więcej informacji o wyświetlaniu powiadomień z aplikacji na ekranie samochodu znajdziesz w sekcji Wyświetlanie powiadomień. Aby dowiedzieć się, jak uruchomić aplikację z działania powiadomienia, przeczytaj sekcję Uruchamianie aplikacji samochodowej za pomocą intencji.

Connection API

Możesz sprawdzić, czy aplikacja działa na Androidzie Auto czy na Androidzie Automotive OS przy użyciu CarConnection API do pobierania informacji o połączeniu w czasie działania.

Na przykład w Session aplikacji samochodu zainicjuj CarConnection i subskrybuj aktualizacje kanału LiveData:

Kotlin

CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)

Java

new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);

Można w nim reagować na zmiany stanu połączenia:

Kotlin

fun onConnectionStateUpdated(connectionState: Int) {
  val message = when(connectionState) {
    CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit"
    CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS"
    CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto"
    else -> "Unknown car connection type"
  }
  CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show()
}

Java

private void onConnectionStateUpdated(int connectionState) {
  String message;
  switch(connectionState) {
    case CarConnection.CONNECTION_TYPE_NOT_CONNECTED:
      message = "Not connected to a head unit";
      break;
    case CarConnection.CONNECTION_TYPE_NATIVE:
      message = "Connected to Android Automotive OS";
      break;
    case CarConnection.CONNECTION_TYPE_PROJECTION:
      message = "Connected to Android Auto";
      break;
    default:
      message = "Unknown car connection type";
      break;
  }
  CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show();
}

Constraints API

Różne samochody mogą pozwalać na różną liczbę Item instancji do wyświetlenia jednego użytkownika. Użyj funkcji ConstraintManager, aby sprawdzić limit treści w czasie działania, i ustaw odpowiednią liczbę elementów w swoich szablonach.

Na początek pobierz ConstraintManagerCarContext:

Kotlin

val manager = carContext.getCarService(ConstraintManager::class.java)

Java

ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);

Następnie możesz przesłać zapytanie do pobranego obiektu ConstraintManager, aby znaleźć odpowiednie limitu treści. Aby na przykład uzyskać liczbę produktów, które można wyświetlić siatka, wywołanie getContentLimit z CONTENT_LIMIT_TYPE_GRID:

Kotlin

val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)

Java

int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);

Dodaj proces logowania

Jeśli aplikacja umożliwia logowanie się użytkownikom, możesz użyć takich szablonów jak SignInTemplate i LongMessageTemplate używając interfejsu Car App API poziomu 2 lub nowszego, aby obsługiwać logowanie się w aplikacji w konsoli centralnej samochodu.

Aby utworzyć SignInTemplate, zdefiniuj SignInMethod. Biblioteka aplikacji samochodowych obsługuje obecnie te metody logowania:

  • InputSignInMethod do logowania się przy użyciu nazwy użytkownika i hasła.
  • PinSignInMethod w przypadku logowania za pomocą kodu PIN, gdy użytkownik łączy konto z telefonu za pomocą kodu PIN wyświetlanego na jednostce głównej.
  • ProviderSignInMethod dla logowania się u dostawcy, takiego jak Zaloguj się przez GoogleJedno dotknięcie.
  • QRCodeSignInMethod dla logowania się przy użyciu kodu QR, w którym użytkownik skanuje kod QR, aby dokończyć logowanie na telefonie. Ta funkcja jest dostępna w interfejsie Car API na poziomie 4 lub nowszym.

Aby na przykład wdrożyć szablon, który zbiera hasło użytkownika, zacznij od utworzenia InputCallback, aby przetworzyć i sprawdzić dane wejściowe użytkownika:

Kotlin

val callback = object : InputCallback {
    override fun onInputSubmitted(text: String) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    override fun onInputTextChanged(text: String) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
}

Java

InputCallback callback = new InputCallback() {
    @Override
    public void onInputSubmitted(@NonNull String text) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    @Override
    public void onInputTextChanged(@NonNull String text) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
};

InputSignInMethod Builder wymaga podania wartości InputCallback.

Kotlin

val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()

Java

InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

Na koniec użyj nowego InputSignInMethod, aby utworzyć SignInTemplate.

Kotlin

SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()

Java

new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();

Korzystanie z usługi AccountManager

Aplikacje na system operacyjny Android Automotive, które wymagają uwierzytelniania, muszą używać interfejsu AccountManager z tych powodów:

  • Lepsze wrażenia użytkowników i łatwe zarządzanie kontami: użytkownicy mogą łatwo zarządzać wszystkimi swoimi kontami w menu kont w ustawieniach systemu, w tym logować się i wylogowywać.
  • Funkcje „gościa”: ponieważ samochody są urządzeniami współdzielonymi, producenci OEM mogą włączyć w nich funkcje „gościa”, w których nie można dodawać kont.

Dodawanie wariantów ciągu tekstowego

Różne rozmiary ekranów w samochodach mogą wyświetlać różne ilości tekstu. Z interfejsem Car App API na poziomie 2 i wyższym, możesz określić wiele wariantów ciągu tekstowego, dopasowują się do ekranu. Aby sprawdzić, gdzie akceptowane są warianty tekstu, poszukaj szablonów komponenty, które przyjmują CarText.

Aby dodać warianty ciągu tekstowego do CarText, użyj metody CarText.Builder.addVariant():

Kotlin

val itemTitle = CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build()

Java

CarText itemTitle = new CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build();

Następnie możesz użyć tego CarText, na przykład jako głównego tekstu GridItem.

Kotlin

GridItem.Builder()
    .addTitle(itemTitle)
    ...
    .build()

Java

new GridItem.Builder()
    .addTitle(itemTitle)
    ...
    build();

Dodawaj ciągi znaków w kolejności od najbardziej do najmniej preferowanych, np. od najdłuższego do najkrótszego. Gospodarz wybiera ciąg o odpowiedniej długości w zależności od tagu ilość miejsca dostępnego na ekranie samochodu.

Dodaj wbudowane CarIcon dla wierszy

Aby wzbogacić wizualnie swoją aplikację, możesz dodać ikony w tekstach za pomocą CarIconSpan. Zobacz dokumentację: CarIconSpan.create , aby dowiedzieć się więcej o tworzeniu tych spanów. Zobacz Świetne stylu tekstu za pomocą Spansów, aby dowiedzieć się, jak działają style tekstu ze spanami.

Kotlin

  
val rating = SpannableString("Rating: 4.5 stars")
rating.setSpan(
    CarIconSpan.create(
        // Create a CarIcon with an image of four and a half stars
        CarIcon.Builder(...).build(),
        // Align the CarIcon to the baseline of the text
        CarIconSpan.ALIGN_BASELINE
    ),
    // The start index of the span (index of the character '4')
    8,
    // The end index of the span (index of the last 's' in "stars")
    16,
    Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

val row = Row.Builder()
    ...
    .addText(rating)
    .build()
  
  

Java

  
SpannableString rating = new SpannableString("Rating: 4.5 stars");
rating.setSpan(
        CarIconSpan.create(
                // Create a CarIcon with an image of four and a half stars
                new CarIcon.Builder(...).build(),
                // Align the CarIcon to the baseline of the text
                CarIconSpan.ALIGN_BASELINE
        ),
        // The start index of the span (index of the character '4')
        8,
        // The end index of the span (index of the last 's' in "stars")
        16,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
);
Row row = new Row.Builder()
        ...
        .addText(rating)
        .build();
  
  

Interfejsy API sprzętu samochodowego

Począwszy od interfejsu Car App API poziomu 3, biblioteka aplikacji w samochodzie zawiera interfejsy API, których może używać, aby uzyskać dostęp do właściwości i czujników pojazdu.

Wymagania

Aby używać interfejsów API z Androidem Auto, zacznij od dodania zależności androidx.car.app:app-projected do pliku build.gradle w module Androida Auto. W przypadku systemu operacyjnego Android Automotive dodaj zależność od pliku androidx.car.app:app-automotive do pliku build.gradle w module systemu operacyjnego Android Automotive.

Dodatkowo w pliku AndroidManifest.xml musisz: zadeklarować odpowiednie uprawnienia niezbędne do tego, żądania danych o samochodzie, których chcesz użyć. Pamiętaj, że te uprawnienia muszą być też przyznany przez użytkownika. Za pomocą ten sam kod w systemie operacyjnym Android Auto i Android Automotive, a nie niż tworzenie przepływów zależnych od platformy. Jednak wymagane uprawnienia różnią się od siebie.

CarInfo

W tej tabeli opisano właściwości wywoływane przez Interfejsy API CarInfo oraz uprawnienia, których potrzebujesz, aby z nich korzystać:

Metody Właściwości Uprawnienia Androida Auto Uprawnienia systemu operacyjnego Android Automotive Obsługiwane od poziomu interfejsu API Car App
fetchModel Marka, model, rok android.car.permission.CAR_INFO 3
fetchEnergyProfile Typy złączy EV, rodzaje paliwa com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO 3
fetchExteriorDimensions

Te dane są dostępne tylko w niektórych pojazdach z systemem operacyjnym Android Automotive z uruchomionym interfejsem API w wersji 30 lub nowszej

Wymiary zewnętrzne Nie dotyczy android.car.permission.CAR_INFO 7
addTollListener
removeTollListener
Stan karty płatności, typ karty płatności 3
addEnergyLevelListener
removeEnergyLevelListener
Poziom baterii, poziom paliwa, niski poziom paliwa, pozostały zasięg com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_ENERGY,
android.car.permission.CAR_ENERGY_PORTS,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addSpeedListener
removeSpeedListener
Prędkość ogólna, wyświetlanie (widoczne na wyświetlaczu w samochodzie) com.google.android.gms.permission.CAR_SPEED android.car.permission.CAR_SPEED,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addMileageListener
removeMileageListener
Odległość z drogomierza com.google.android.gms.permission.CAR_MILEAGE Te dane nie są dostępne w systemie operacyjnym Android Automotive w przypadku aplikacji zainstalowanych ze Sklepu Play. 3

Aby na przykład uzyskać pozostały zakres, utwórz wystąpienie CarInfo obiekt, a potem utwórz i zarejestruj OnCarDataAvailableListener:

Kotlin

val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo

val listener = OnCarDataAvailableListener<EnergyLevel> { data ->
    if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) {
      val rangeRemaining = data.rangeRemainingMeters.value
    } else {
      // Handle error
    }
  }

carInfo.addEnergyLevelListener(carContext.mainExecutor, listener)
…
// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener)

Java

CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo();

OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
  if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) {
    float rangeRemaining = data.getRangeRemainingMeters().getValue();
  } else {
    // Handle error
  }
};

carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener);
…
// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener);

Nie zakładaj, że dane z samochodu są dostępne przez cały czas. Jeśli pojawi się błąd, sprawdź stan wartości, o którą Ci chodzi, aby dowiedzieć się, dlaczego nie udało się pobrać żądanych danych. Zapoznaj się z dokumentacji referencyjnej dotyczącej pełną definicję klasy CarInfo.

CarSensors

Zajęcia CarSensors umożliwia dostęp do akcelerometru, żyroskopu, kompasu i dane o lokalizacji. Dostępność tych wartości może zależeć od OEM. Format danych z akcelerometru, żyroskopu i kompasu to taka sama jak w przypadku strony SensorManager API. Przykład: aby sprawdzić kierunek pojazdu:

Kotlin

val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors

val listener = OnCarDataAvailableListener<Compass> { data ->
    if (data.orientations.status == CarValue.STATUS_SUCCESS) {
      val orientation = data.orientations.value
    } else {
      // Data not available, handle error
    }
  }

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener)
…
// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener)

Java

CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors();

OnCarDataAvailableListener<Compass> listener = (data) -> {
  if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) {
    List<Float> orientations = data.getOrientations().getValue();
  } else {
    // Data not available, handle error
  }
};

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(),
    listener);
…
// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener);

Aby uzyskać dostęp do danych o lokalizacji z samochodu, musisz też zadeklarować i poprosić o dostęp do android.permission.ACCESS_FINE_LOCATION.

Testowanie

Aby symulować dane z czujników podczas testowania w Androidzie Auto, zapoznaj się z sekcjami CzujnikiKonfiguracja czujników w przewodniku dotyczącym konsoli na komputer stacjonarny. Aby symulować dane czujników podczas testowania w systemie operacyjnym Android Automotive, zapoznaj się z sekcją Symulowanie stanu sprzętu w przewodniku dotyczącym emulatora systemu operacyjnego Android Automotive.

Cykl życia usługi CarAppService, sesji i ekranu

Klasy SessionScreen implementują interfejs LifecycleOwner. Jako gdy użytkownik wchodzi w interakcję z aplikacją oraz obiektami Session i Screen cykl życia wywołania zwrotne są wywoływane w sposób opisany na diagramach poniżej.

Cykle życia sesji CarAppService i sesji

Rysunek 1. Sessioncykl życia
.

Pełne informacje znajdziesz w dokumentacji metody Session.getLifecycle.

Cykl życia ekranu

Rysunek 2. Screencykl życia
.

Szczegółowe informacje znajdziesz w dokumentacji Screen.getLifecycle.

Nagrywanie z mikrofonu w samochodzie

Za pomocą interfejsu CarAppService i interfejsu CarAudioRecord możesz przyznać aplikacji dostęp do mikrofonu w samochodzie użytkownika. Użytkownicy muszą zezwolić aplikacji na dostęp do mikrofonu samochodowego. Aplikacja może nagrywać przetwarzania danych wejściowych użytkownika w aplikacji.

Uprawnienia do nagrywania

Zanim nagrasz dźwięk, musisz najpierw zadeklarować uprawnienie do nagrywania w swojej aplikacji (AndroidManifest.xml) i poprosić użytkownika o jego przyznanie.

<manifest ...>
   ...
   <uses-permission android:name="android.permission.RECORD_AUDIO" />
   ...
</manifest>

Musisz poprosić o uprawnienia do nagrywania w czasie działania. Więcej informacji o tym, jak poprosić o uprawnienia w aplikacji samochodowej, znajdziesz w sekcji Poproś o uprawnienia.

Nagrywanie dźwięku

Gdy użytkownik udzieli zgody na nagrywanie, możesz nagrać dźwięk i przetworzyć nagranie.

Kotlin

val carAudioRecord = CarAudioRecord.create(carContext)
        carAudioRecord.startRecording()

        val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE)
        while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording()
 

Java

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        carAudioRecord.startRecording();

        byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE];
        while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording();
 

Aktywność audio

Podczas nagrywania za pomocą mikrofonu w samochodzie najpierw uzyskaj fokus dźwiękowy, aby zatrzymać wszystkie trwające multimedia. Jeśli utracisz aktywność audio, Zatrzymaj nagrywanie.

Oto przykład uzyskania aktywności audio:

Kotlin

 
val carAudioRecord = CarAudioRecord.create(carContext)
        
        // Take audio focus so that user's media is not recorded
        val audioAttributes = AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
            // Use the most appropriate usage type for your use case
            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
            .build()
        
        val audioFocusRequest =
            AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                .setAudioAttributes(audioAttributes)
                .setOnAudioFocusChangeListener { state: Int ->
                    if (state == AudioManager.AUDIOFOCUS_LOSS) {
                        // Stop recording if audio focus is lost
                        carAudioRecord.stopRecording()
                    }
                }
                .build()
        
        if (carContext.getSystemService(AudioManager::class.java)
                .requestAudioFocus(audioFocusRequest)
            != AudioManager.AUDIOFOCUS_REQUEST_GRANTED
        ) {
            // Don't record if the focus isn't granted
            return
        }
        
        carAudioRecord.startRecording()
        // Process the audio and abandon the AudioFocusRequest when done

Java

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        // Take audio focus so that user's media is not recorded
        AudioAttributes audioAttributes =
                new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        // Use the most appropriate usage type for your use case
                        .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
                        .build();

        AudioFocusRequest audioFocusRequest =
                new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                        .setAudioAttributes(audioAttributes)
                        .setOnAudioFocusChangeListener(state -> {
                            if (state == AudioManager.AUDIOFOCUS_LOSS) {
                                // Stop recording if audio focus is lost
                                carAudioRecord.stopRecording();
                            }
                        })
                        .build();

        if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest)
                != AUDIOFOCUS_REQUEST_GRANTED) {
            // Don't record if the focus isn't granted
            return;
        }

        carAudioRecord.startRecording();
        // Process the audio and abandon the AudioFocusRequest when done
 

Biblioteka testów

Biblioteka testów Androida dla samochodów udostępnia dodatkowe klasy, których możesz używać do sprawdzania zachowania aplikacji w środowisku testowym. Na przykład funkcja SessionController pozwala na symulowanie połączenia z hostem i sprawdzanie, czy zostały utworzone i zwrócone prawidłowe wartości ScreenTemplate.

Zapoznaj się z Sample .

Zgłaszanie problemu z biblioteką aplikacji Android do samochodu

Jeśli znajdziesz problem z biblioteką, zgłoś go za pomocą Google Issue Tracker. Pamiętaj, aby podać wszystkie wymagane informacje w szablonie problemu.

Tworzenie nowego numeru

Zanim zgłosisz nowy numer, sprawdź, czy jest on uwzględniony w wersji biblioteki notatki lub raporty na liście problemów. Możesz subskrybować problemy i głosować na nie, klikając gwiazdkę obok problemu w śledzeniu. Więcej informacji znajdziesz w artykule Subskrybowanie problemu.