Korzystanie z biblioteki aplikacji Android for Cars

Biblioteka aplikacji Android for Cars umożliwia zabranie w samochodzie aplikacji do nawigacji, ciekawych miejsc i internetu (IOT). Zawiera zestaw szablonów zaprojektowany z myślą o wymaganiach dotyczących rozpraszania uwagi kierowcy oraz uwzględniający takie szczegóły jak różne czynniki wyświetlane w samochodzie i różne sposoby wprowadzania danych.

Ten przewodnik zawiera omówienie najważniejszych funkcji i zagadnień związanych z biblioteką oraz zawiera omówienie procesu konfigurowania prostej aplikacji. Pełne wprowadzenie znajdziesz w ćwiczeniu z programowania.

Zanim zaczniesz

  1. Przejrzyj strony Projektowanie do samochodów dotyczące biblioteki aplikacji Car.
  2. Zapoznaj się z kluczowymi terminami i pojęciami w kolejnej sekcji.
  3. Zapoznaj się z interfejsem systemu Android Auto i projektem systemu operacyjnego Android Automotive.
  4. Zapoznaj się z informacjami o wersji.
  5. Przejrzyj Sample.

Kluczowe terminy i koncepcje

Modele i szablony
Interfejs jest reprezentowany przez wykres obiektów modelu, które można umieszczać w różnych miejscach zgodnie z szablonem, do którego należą. Szablony to podzbiór modeli, które mogą stanowić podstawę dla tych wykresów. Modele obejmują informacje, które mają być wyświetlane użytkownikowi w postaci tekstu i obrazów, a także atrybuty określające aspekty wizualnego wyglądu takich informacji, np. kolory tekstu lub rozmiary obrazów. Gospodarz konwertuje modele na widoki zaprojektowane tak, aby spełniały standardy w zakresie rozpraszania uwagi kierowcy, i dba o takie szczegóły jak różnorodne parametry ekranu samochodu i modalności danych wejściowych.
Host
Host to komponent backendu, który implementuje funkcje oferowane przez interfejsy API biblioteki, aby umożliwić działanie aplikacji w samochodzie. Obowiązki gospodarza są różne: od odkrycia aplikacji i zarządzania jej cyklem życia po przekształcanie modeli w widoki i powiadamianie aplikacji o interakcjach użytkowników. Na urządzeniach mobilnych ten host jest implementowany przez Androida Auto. W systemie operacyjnym Android Automotive ten host jest instalowany jako aplikacja systemowa.
Ograniczenia szablonów
Różne szablony wymuszają ograniczenia dotyczące treści modeli. Na przykład szablony list mają ograniczoną liczbę elementów, które można przedstawić użytkownikowi. Szablony mają też ograniczenia związane z ich łączeniem w celu utworzenia przepływu zadań. Na przykład aplikacja może przekazać maksymalnie 5 szablonów do stosu ekranu. Więcej informacji znajdziesz w sekcji Ograniczenia dotyczące szablonów.
Screen
Screen to klasa udostępniana przez bibliotekę, którą wdraża aplikacje w celu zarządzania prezentowanym użytkownikowi. Element Screen ma cykl życia i umożliwia aplikacji wysyłanie szablonu do wyświetlenia, gdy ekran jest widoczny. Instancje (Screen) można też przenosić do stosu Screen lub z niego łączyć, dzięki czemu są one zgodne z ograniczeniami przepływu szablonów.
CarAppService
CarAppService to abstrakcyjna klasa Service, którą musi wdrożyć i wyeksportować Twoja aplikacja, aby umożliwić jej wykrywanie i zarządzanie przez hosta. Klucz CarAppService Twojej aplikacji odpowiada za sprawdzanie, czy połączenie z hostem jest godne zaufania, za pomocą createHostValidator, a następnie za udostępnianie instancji Session dla każdego połączenia z wykorzystaniem onCreateSession.
Session

Session to klasa abstrakcyjna, którą aplikacja musi wdrożyć i zwrócić przy użyciu CarAppService.onCreateSession. Służy jako punkt dostępu do wyświetlania informacji na ekranie samochodu. Zawiera on cykl życia, który informuje o bieżącym stanie aplikacji na ekranie samochodu, np. o tym, kiedy jest widoczna lub ukryta.

Po uruchomieniu Session, np. przy pierwszym uruchomieniu aplikacji, host wysyła żądanie wyświetlenia początkowego Screen za pomocą metody onCreateScreen.

Instalowanie biblioteki aplikacji samochodu

Instrukcje dodawania biblioteki do aplikacji znajdziesz na stronie wersji biblioteki Jetpack.

Skonfiguruj pliki manifestu aplikacji

Zanim utworzysz aplikację samochodową, skonfiguruj jej pliki manifestu w następujący sposób.

Deklarowanie CarAppService

Host łączy się z Twoją aplikacją przez implementację CarAppService. Tę usługę deklarujesz w pliku manifestu, aby host mógł wykrywać Twoją aplikację i się z nią łączyć.

Musisz też zadeklarować kategorię aplikacji w elemencie <category> w filtrze intencji aplikacji. Wartości dozwolone w przypadku tego elementu znajdziesz na liście obsługiwanych kategorii aplikacji.

Ten fragment kodu pokazuje, jak w pliku manifestu zadeklarować usługę samochodową dla aplikacji z ciekawych miejsc:

<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

Zadeklaruj kategorię aplikacji, dodając co najmniej 1 z tych wartości kategorii w filtrze intencji podczas zadeklarowania CarAppService w sposób opisany w poprzedniej sekcji:

  • androidx.car.app.category.NAVIGATION: aplikacja ze szczegółowymi wskazówkami nawigacji. Więcej informacji o tej kategorii znajdziesz w artykule o tworzeniu aplikacji nawigacyjnych do samochodów.
  • androidx.car.app.category.POI: aplikacja, która umożliwia znajdowanie ciekawych miejsc, takich jak miejsca parkingowe, stacje ładowania i stacje paliw. Dodatkową dokumentację na temat tej kategorii znajdziesz w aplikacjach do tworzenia ciekawych miejsc w samochodach.
  • androidx.car.app.category.IOT: aplikacja, która umożliwia użytkownikom wykonywanie odpowiednich działań na połączonych urządzeniach z poziomu samochodu. Więcej informacji o tej kategorii znajdziesz w artykule Tworzenie internetu rzeczy w samochodach.

W artykule Jakość aplikacji na Androida w samochodach znajdziesz szczegółowe opisy poszczególnych kategorii i kryteriów, do których aplikacje mają należeć.

Określ nazwę i ikonę aplikacji

Musisz podać nazwę i ikonę aplikacji, za pomocą których host może ją reprezentować w interfejsie systemu.

Możesz określić nazwę i ikonę aplikacji, które będą reprezentować Twoją aplikację za pomocą atrybutów label i icon CarAppService:

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

Jeśli w elemencie <service> nie zadeklarowano etykiety ani ikony, host wraca do wartości określonych dla elementu <application>.

Ustawianie motywu niestandardowego

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

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

Następnie zadeklaruj zasób stylu, aby ustawić 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 Car App API

Biblioteka aplikacji samochodowych definiuje własne poziomy interfejsu API, dzięki czemu można sprawdzić, które funkcje biblioteki są obsługiwane przez hosta szablonu w pojeździe. Aby pobrać najwyższy poziom interfejsu Car App API obsługiwany przez hosta, użyj metody getCarAppApiLevel().

W pliku AndroidManifest.xml zadeklaruj minimalny poziom interfejsu Car App API obsługiwany przez Twoją aplikację:

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

Szczegółowe informacje o tym, jak zachować zgodność wsteczną i zadeklarować minimalny poziom interfejsu API wymagany do używania funkcji, znajdziesz w dokumentacji adnotacji RequiresCarApi. Definicję poziomu interfejsu API wymaganego do korzystania z danej funkcji biblioteki aplikacji samochodowych znajdziesz w dokumentacji referencyjnej CarAppApiLevels.

Tworzenie usługi CarAppService i sesji

Aplikacja musi rozszerzyć klasę CarAppService i zaimplementować jej metodę onCreateSession, która zwraca wystąpienie Session odpowiadające 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 zwrot instancji Screen w celu użycia 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 radzić sobie w sytuacjach, w których aplikacja samochodowa musi się uruchamiać na innym ekranie (np. w przypadku obsługi precyzyjnych linków), możesz wstępnie wypełnić wsteczny stos ekranów za pomocą funkcji ScreenManager.push, a potem wrócić z onCreateScreen. Wstępne wypełnianie umożliwia użytkownikom przechodzenie do poprzednich ekranów z pierwszego ekranu, na którym wyświetla się aplikacja.

Utwórz ekran startowy

Ekrany wyświetlane w aplikacji tworzysz, definiując klasy, które rozszerzają klasę Screen, i implementując jej metodę onGetTemplate, która zwraca wystąpienie Template reprezentujące stan interfejsu wyświetlany na ekranie w samochodzie.

Ten fragment kodu pokazuje, jak zadeklarować Screen, który korzysta z 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 jest podklasą ContextWrapper dostępną do instancji Session i Screen. Zapewnia dostęp do usług samochodowych, takich jak ScreenManager do zarządzania stosem ekranu, AppManager do ogólnych funkcji związanych z aplikacjami, takich jak dostęp do obiektu Surface, np. do rysowania mapy aplikacji do nawigacji, oraz NavigationManager do komunikacji z hostami nawigacji zakręt po zakręcie do komunikacji i innych metadanych.

Pełną listę funkcji biblioteki dostępnych dla aplikacji nawigacyjnych znajdziesz w artykule Uzyskiwanie dostępu do szablonów nawigacji.

CarContext oferuje też inne funkcje, takie jak ładowanie możliwych do rysowania zasobów przy użyciu konfiguracji na ekranie samochodu, uruchamianie aplikacji w samochodzie przy użyciu intencji czy sygnalizowanie, czy aplikacja do nawigacji powinna wyświetlić swoją mapę w trybie ciemnym.

Wdrażanie nawigacji po ekranie

Aplikacje często mają wiele różnych ekranów, z których każdy może korzystać z odmiennych szablonów, z których użytkownik może korzystać podczas interakcji z wyświetlanym interfejsem.

Klasa ScreenManager udostępnia stos ekranu, który umożliwia otwieranie ekranów automatycznie po kliknięciu przez użytkownika przycisku Wstecz na ekranie samochodu lub przy użyciu sprzętowego przycisku Wstecz, który jest dostępny w niektórych samochodach.

Ten fragment kodu pokazuje, jak dodać działanie wsteczne do szablonu wiadomości oraz działanie, które po wybraniu przez użytkownika powoduje wypchnięcie nowego ekranu:

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 ScreenManager.pop. To działanie można zastąpić za pomocą instancji OnBackPressedDispatcher dostępnej w CarContext.

Aby można było bezpiecznie używać aplikacji podczas jazdy, stos ekranu może mieć maksymalnie 5 ekranów. Więcej informacji znajdziesz w sekcji Ograniczenia szablonu.

Odświeżanie zawartości szablonu

Aplikacja może zażądać unieważnienia zawartości pola Screen, wywołując metodę Screen.invalidate. Następnie host łączy się z metodą Screen.onGetTemplate Twojej aplikacji, aby pobrać szablon z nową zawartością.

Podczas odświeżania elementu Screen ważne jest, aby poznać konkretną zawartość szablonu, którą można aktualizować, aby host nie wliczał nowego szablonu do limitu szablonów. Więcej informacji znajdziesz w sekcji Ograniczenia dotyczące szablonów.

Zalecamy uporządkowanie ekranów w taki sposób, aby istniało mapowanie 1:1 między obiektem Screen a typem szablonu, który zwraca w ramach implementacji onGetTemplate.

Interakcja z użytkownikiem

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

Obsługa danych wejściowych użytkownika

Aplikacja może reagować na działania użytkowników, przekazując odpowiednie detektory do modeli, które je obsługują. Ten fragment kodu pokazuje, jak utworzyć model Action, który ustawia OnClickListener, który wywołuje metodę określoną 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 następnie uruchomić domyślną aplikację do nawigacji za pomocą metody 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 intencji ACTION_NAVIGATE, znajdziesz w sekcji Uruchamianie aplikacji samochodowej z intencją.

Niektóre działania, na przykład te, które wymagają polecenia użytkownikowi kontynuowania interakcji na urządzeniu mobilnym, są dozwolone tylko wtedy, gdy samochód jest zaparkowany. Do wykonania tych działań możesz użyć elementu ParkedOnlyOnClickListener. Jeśli samochód nie jest zaparkowany, host wyświetla użytkownikowi informację, że w tym przypadku dana czynność jest niedozwolona. Gdy samochód jest zaparkowany, kod działa normalnie. Ten fragment kodu pokazuje, jak za pomocą ParkedOnlyOnClickListener 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świetl powiadomienia

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

Ten fragment kodu pokazuje, jak wysłać na ekran samochodu powiadomienie z innym tytułem niż ten wyświetlany 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ą mieć wpływ na następujące części interfejsu użytkownika:

  • Użytkownik może zobaczyć powiadomienie z ostrzeżeniem (HUN).
  • W centrum powiadomień można dodać wpis wraz z plakietką widoczną na pasku powiadomień.
  • W przypadku aplikacji nawigacyjnych powiadomienie może być wyświetlane w widżecie linii kolejowej zgodnie z opisem w sekcji Powiadomienia zakręt po zakręcie.

Możesz określić, jak powiadomienia aplikacji mają wpływać na każdy z tych elementów interfejsu, korzystając z priorytetu powiadomienia, zgodnie z opisem w dokumentacji CarAppExtender.

Jeśli funkcja NotificationCompat.Builder.setOnlyAlertOnce zostanie wywołana z wartością true, powiadomienie o wysokim priorytecie wyświetla się tylko raz.

Więcej informacji o projektowaniu powiadomień z aplikacji samochodowej znajdziesz w przewodniku Google Design for Driving na temat powiadomień.

Wyświetlaj powiadomienia

Aplikacja może wyświetlać tost za pomocą parametru CarToast, tak 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ń objętych ograniczeniami – np. do lokalizacji – obowiązują standardowe reguły uprawnień Androida. Aby poprosić o uprawnienia, możesz użyć metody CarContext.requestPermissions().

Zaletą użycia CarContext.requestPermissions() w przeciwieństwie do standardowych interfejsów API Androida jest to, że nie musisz uruchamiać własnego Activity, aby utworzyć okno uprawnień. Możesz też użyć tego samego kodu w systemie operacyjnym Android Auto i Android Automotive, zamiast tworzyć procesy 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 za oknem nie ma tła. Aby ustawić niestandardowe tło, zadeklaruj motyw aplikacji samochodowej w pliku AndroidManifest.xml 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 samochodu:

<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ć jedno z tych działań:

Z przykładu poniżej dowiesz się, jak utworzyć powiadomienie z działaniem powodującym otwarcie aplikacji i wyświetlenie ekranu ze szczegółami rezerwacji miejsca parkingowego. Rozszerzasz wystąpienie powiadomienia za pomocą intencji treści, która zawiera element PendingIntent pakujący intencję w stosunku do działania 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 też zadeklarować obiekt BroadcastReceiver, który jest wywoływany do przetworzenia intencji, gdy użytkownik wybierze działanie w interfejsie powiadomień i wywoła 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)));
        }
    }
}

Wreszcie metoda Session.onNewIntent w aplikacji obsługuje tę intencję, wypychając ekran rezerwacji miejsca parkingowego na stos, jeśli jeszcze nie znajduje się na wierzchu:

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łudze powiadomień z aplikacji samochodowej znajdziesz w sekcji Wyświetlanie powiadomień.

Ograniczenia szablonów

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

Pamiętaj, że ten limit dotyczy liczby szablonów, a nie liczby instancji Screen w stosie. Jeśli na przykład aplikacja wyśle 2 szablony na ekranie A, a potem wyświetli ekran B, może wysłać 3 kolejne szablony. Jeśli każdy ekran ma strukturę umożliwiającą wysyłanie 1 szablonu, aplikacja może też umieścić 5 instancji ekranu na stos ScreenManager.

Obowiązują szczególne przypadki, w których obowiązują te ograniczenia: odświeżanie szablonu oraz operacje przywracania i resetowania.

Odświeżanie szablonu

Niektóre aktualizacje treści nie wliczają się do limitu szablonów. Ogólnie, jeśli aplikacja przesyła nowy szablon tego samego typu i zawierający tę samą główną treść co poprzedni szablon, nowy szablon nie jest wliczany do limitu. Na przykład zaktualizowanie stanu przełączania wiersza w elemencie ListTemplate nie powoduje wliczania się do limitu. W dokumentacji poszczególnych szablonów dowiesz się, jakie typy aktualizacji treści można uznać za odświeżone.

Operacje wstecz

Aby włączyć procesy podrzędne w ramach zadania, host wykrywa, kiedy aplikacja wyrzuca Screen ze stosu ScreenManager, i aktualizuje pozostały limit na podstawie liczby szablonów, o które aplikacja cofa się do poprzedniego kroku.

Jeśli na przykład na ekranie A aplikacja wyśle 2 szablony, a potem przesunie ekran B i wyśle jeszcze 2 szablony, aplikacja będzie mieć jeszcze 1 limit. Jeśli aplikacja wróci do ekranu A, host resetuje limit do 3, ponieważ aplikacja cofnęła się o 2 szablony.

Pamiętaj, że po powrocie na ekran aplikacja musi wysłać szablon tego samego typu co ostatni wysłany przez ten ekran. Wysyłanie innego typu szablonu powoduje błąd. Dopóki jednak typ pozostaje taki sam podczas operacji wstecz, aplikacja może dowolnie modyfikować zawartość szablonu bez wpływu na limit.

Operacje resetowania

Niektóre szablony mają specjalną semantykę, która oznacza koniec zadania. Na przykład widok NavigationTemplate powinien pozostawać na ekranie i odświeżać się za pomocą nowych, szczegółowych instrukcji wykorzystania przez użytkownika. Gdy dojdzie do jednego z tych szablonów, host resetuje limit szablonów, traktując go jako pierwszy krok nowego zadania. Dzięki temu aplikacja będzie mogła rozpocząć nowe zadanie. W dokumentacji poszczególnych szablonów możesz sprawdzić, które z nich powodują resetowanie na hoście.

Jeśli host otrzyma zamiar uruchomienia aplikacji z poziomu powiadomienia lub programu uruchamiającego, limit też zostanie zresetowany. Ten mechanizm umożliwia aplikacji rozpoczynanie nowego przepływu zadań z poziomu powiadomień i działa nawet wtedy, gdy aplikacja jest już powiązana i działa na pierwszym planie.

Więcej informacji o tym, jak wyświetlać powiadomienia z aplikacji na ekranie samochodu, znajdziesz w sekcji Wyświetlanie powiadomień. Informacje o tym, jak uruchomić aplikację z poziomu powiadomienia, znajdziesz w sekcji Uruchamianie aplikacji samochodowej z intencją.

Interfejs API połączenia

Aby sprawdzić, czy Twoja aplikacja działa na systemie operacyjnym Android Auto czy Android Automotive, pobierz informacje o połączeniu w czasie działania za pomocą interfejsu CarConnection API.

Na przykład w Session aplikacji samochodowej zainicjuj CarConnection i zasubskrybuj aktualizacje LiveData:

Kotlin

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

Java

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

Korzystając z obserwatora, możesz 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();
}

Interfejs API ograniczeń

Różne samochody mogą zezwalać na wyświetlanie użytkownikowi różnych instancji Item naraz. Aby sprawdzić limit treści w czasie działania i ustawić odpowiednią liczbę elementów w szablonach, użyj komponentu ConstraintManager.

Zacznij od uzyskania ConstraintManager od: CarContext:

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 określić odpowiedni limit treści. Aby na przykład uzyskać liczbę elementów, które można wyświetlić w siatce, wywołaj metodę getContentLimit z parametrem 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 Twoja aplikacja umożliwia logowanie się użytkowników, możesz używać szablonów takich jak SignInTemplate i LongMessageTemplate z interfejsem Car App API na poziomie 2 lub wyższym, aby logować się w niej na konsoli centralnej samochodu.

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

Aby np. wdrożyć szablon zbierający hasło użytkownika, zacznij od utworzenia InputCallback do przetwarzania i weryfikowania danych wejściowych 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.
    }
};

Wymagany jest element InputCallback dla elementu: InputSignInMethod Builder.

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 urządzenia InputSignInMethod do utworzenia 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();

Użyj menedżera konta

Aplikacje na system operacyjny Android Automotive, które mają uwierzytelnianie, muszą używać usługi AccountManager z tych powodów:

  • Większa wygoda użytkowania i łatwiejsze zarządzanie kontem: użytkownicy mogą łatwo zarządzać wszystkimi swoimi kontami za pomocą menu kont w ustawieniach systemu. Obejmuje to logowanie się i wylogowywanie.
  • Funkcje „Gość”: samochody są urządzeniami współdzielonymi, dlatego OEM może włączyć w pojeździe funkcje obsługi gości, których kont nie można dodawać.

Dodawanie wariantów ciągu tekstowego

Na ekranach różnych urządzeń w samochodzie może wyświetlać się różna ilość tekstu. Interfejs Car App API na poziomie 2 lub wyższym pozwala określić wiele wariantów ciągu tekstowego, które najlepiej pasują do ekranu. Aby dowiedzieć się, gdzie akceptowane są warianty tekstu, znajdź szablony i komponenty, które akceptują CarText.

Do elementu CarText możesz dodać warianty ciągu tekstowego za pomocą 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 elementu CarText, np. jako głównego tekstu strony GridItem.

Kotlin

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

Java

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

Dodaj ciągi znaków w kolejności od największej do najmniejszej, np. od najdłuższego do najkrótszego. Gospodarz wybiera ciąg znaków o odpowiedniej długości w zależności od ilości miejsca dostępnego na ekranie w samochodzie.

Dodaj wbudowane obiekty CarIcon dla wierszy

Za pomocą CarIconSpan możesz dodawać ikony w tekście, aby uatrakcyjnić wygląd aplikacji. Więcej informacji o tworzeniu tych spanów znajdziesz w dokumentacji CarIconSpan.create. Informacje o tym, jak działają style tekstu za pomocą rozpiętości, znajdziesz w artykule o stylizowaniu tekstu ze spacjami za pomocą zakresów.

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 do sprzętu samochodowego

Począwszy od poziomu 3 interfejsu Car App API, Biblioteka aplikacji samochodowych zawiera interfejsy API umożliwiające dostęp do właściwości pojazdu i czujników.

Wymagania

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

Dodatkowo w pliku AndroidManifest.xml musisz zadeklarować odpowiednie uprawnienia potrzebne do wysłania prośby o dostęp do danych samochodu, których chcesz użyć. Pamiętaj, że te uprawnienia musi Ci też przyznać użytkownik. Zamiast tworzyć procesy zależne od platformy, możesz użyć tego samego kodu zarówno w systemie operacyjnym Android Auto, jak i Android Automotive. Potrzebne są jednak inne uprawnienia.

Informacje o samochodzie

W tej tabeli opisujemy właściwości udostępniane przez interfejsy CarInfo API oraz uprawnienia, których potrzebujesz, aby ich używać:

Metody Właściwości Uprawnienia Androida Auto Uprawnienia systemu operacyjnego Android Automotive
fetchModel Marka, model, rok produkcji android.car.permission.CAR_INFO
fetchEnergyProfile Typy złączy EV, typy paliwa com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO
addTollListener
removeTollListener
Stan karty płatnej, typ karty płatnej
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
addSpeedListener
removeSpeedListener
Prędkość nieprzetworzona i prędkość wyświetlania (widoczne na wyświetlaczu klastra w samochodzie) com.google.android.gms.permission.CAR_SPEED android.car.permission.CAR_SPEED,
android.car.permission.READ_CAR_DISPLAY_UNITS
addMileageListener
removeMileageListener
Odległość drogomierza com.google.android.gms.permission.CAR_MILEAGE Te dane nie są dostępne w systemie operacyjnym Android Automotive w aplikacjach zainstalowanych ze Sklepu Play.

Aby np. uzyskać pozostały zakres, utwórz instancję obiektu CarInfo, a następnie 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ą przez cały czas dostępne. Jeśli pojawi się błąd, sprawdź stan żądanej wartości, aby lepiej zrozumieć, dlaczego nie udało się pobrać żądanych danych. Pełną definicję klasy CarInfo znajdziesz w dokumentacji referencyjnej.

Czujniki samochodowe

Klasa CarSensors zapewnia dostęp do danych z akcelerometru, żyroskopu, kompasu i lokalizacji pojazdu. Dostępność tych wartości może zależeć od producenta OEM. Format danych z akcelerometru, żyroskopu i kompasu jest taki sam jak w przypadku interfejsu API SensorManager. Na 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 uprawnienia android.permission.ACCESS_FINE_LOCATION.

Testowanie

Aby symulować dane z czujników podczas testowania na Androidzie Auto, zapoznaj się z sekcjami dotyczącymi czujników i konfiguracji czujników w przewodniku po jednostce głównej na komputerze. Aby symulować dane z czujników podczas testowania w systemie operacyjnym Android Automotive, zapoznaj się z sekcją Emuluj stan sprzętu w przewodniku po emulatorze systemu operacyjnego Android Automotive.

Cykle życia usług CarAppService i sesji oraz ekranu

Klasy Session i Screen implementują interfejs LifecycleOwner. Gdy użytkownik wchodzi w interakcję z aplikacją, wywoływane są wywołania zwrotne cyklu życia obiektów Session i Screen, zgodnie z opisem na tych diagramach.

Cykle życia usług CarAppService i sesji

Rysunek 1. Cykl życia Session.

Szczegółowe informacje znajdziesz w dokumentacji metody Session.getLifecycle.

Cykl życia ekranu

Rysunek 2. Cykl życia Screen.

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

Nagrywanie z mikrofonu w samochodzie

Za pomocą CarAppService i interfejsu API CarAudioRecord możesz przyznać aplikacji dostęp do mikrofonu samochodowego użytkownika. Użytkownicy muszą zezwolić aplikacji na dostęp do mikrofonu w samochodzie. Aplikacja może rejestrować i przetwarzać dane wejściowe użytkownika.

Uprawnienia do nagrywania

Przed nagraniem dźwięku musisz najpierw zadeklarować, że masz pozwolenie na nagrywanie w urządzeniu AndroidManifest.xml, i poprosić o to użytkownika.

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

Musisz poprosić o uprawnienia do nagrywania w czasie działania. W sekcji Prośba o uprawnienia znajdziesz szczegółowe informacje o tym, jak poprosić o uprawnienia w aplikacji samochodowej.

Nagrywanie dźwięku

Gdy użytkownik zezwoli na nagrywanie, będziesz mieć możliwość nagrywania dźwięku i przetwarzania nagrania.

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 z mikrofonu w samochodzie musisz najpierw włączyć fokus, aby mieć pewność, że bieżące multimedia zostaną zatrzymane. Jeśli dźwięk nie jest już aktywny, zatrzymaj nagrywanie.

Oto przykład, jak uzyskać koncentrację 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 testowania

Biblioteka testowania Androida dla samochodów zawiera klasy pomocnicze, których możesz używać do weryfikowania działania aplikacji w środowisku testowym. Na przykład SessionController pozwala symulować połączenie z hostem i sprawdzić, czy utworzone i zwrócone są prawidłowe Screen oraz Template.

Przykłady użycia znajdziesz w sekcji Przykłady.

Zgłaszanie problemu z biblioteką aplikacji Android for Cars

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

Utwórz nowy numer

Zanim zgłosisz nowe wydanie, sprawdź, czy nie ma go w informacjach o wersjach biblioteki lub czy nie ma go na liście problemów. Możesz zasubskrybować problem i głosować na nie, klikając gwiazdkę w narzędziu do śledzenia błędów. Więcej informacji znajdziesz w artykule Subskrybowanie problemu.