Na tej stronie znajdziesz szczegółowe informacje o różnych funkcjach biblioteki aplikacji samochodowych, których możesz używać do wdrażania funkcji aplikacji do nawigacji krok po kroku.
Zadeklaruj obsługę nawigacji w pliku manifestu
Aplikacja do nawigacji musi zadeklarować androidx.car.app.category.NAVIGATION
kategorię aplikacji samochodowej w filtrze intencji CarAppService:
<application>
...
<service
...
android:name=".MyNavigationCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.NAVIGATION"/>
</intent-filter>
</service>
...
</application>
Obsługa intencji nawigacyjnych
Różne formaty intencji umożliwiają aplikacjom do nawigacji współpracę z innymi aplikacjami, takimi jak aplikacje z informacjami o interesujących miejscach czy asystenci głosowi.
Aby obsługiwać te formaty intencji, najpierw zadeklaruj obsługę, dodając filtry intencji w pliku manifestu aplikacji. Lokalizacja tych filtrów intencji zależy od platformy:
- Android Auto: w elemencie manifestu
<activity>dlaActivity, który służy do obsługi intencji, gdy użytkownik nie korzysta z Androida Auto. - System operacyjny Android Automotive: w elemencie manifestu
<activity>dlaCarAppActivity.
Następnie odczytaj i obsłuż intencje w wywołaniach zwrotnych onCreateScreen() i onNewIntent() w implementacji Session w swojej aplikacji.
Wymagane formaty intencji
Aby spełnić wymagania dotyczące jakości NF-6, aplikacja musi obsługiwać intencje nawigacyjne.
Opcjonalne formaty intencji
Możesz też obsługiwać te formaty intencji, aby zwiększyć interoperacyjność aplikacji:
Dostęp do szablonów nawigacji
Aplikacje nawigacyjne mają dostęp do tych szablonów, które wyświetlają powierzchnię w tle z mapą, a podczas aktywnej nawigacji – wskazówki zakręt po zakręcie.
NavigationTemplate: Szablon, który podczas aktywnej nawigacji wyświetla opcjonalną wiadomość informacyjną i szacunkowe dane dotyczące podróży.MapWithContentTemplate: szablon, który umożliwia aplikacji renderowanie kafelków mapy z określonymi treściami (np. listą). Treści są zwykle renderowane jako nakładka na kafelki mapy, przy czym widoczne i stabilne obszary mapy dostosowują się do treści.
Więcej informacji o projektowaniu interfejsu aplikacji nawigacyjnej za pomocą tych szablonów znajdziesz w artykule Aplikacje nawigacyjne.
Aby uzyskać dostęp do szablonów nawigacji, aplikacja musi zadeklarować uprawnienie androidx.car.app.NAVIGATION_TEMPLATES w pliku AndroidManifest.xml:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
...
</manifest>
Do rysowania map wymagane jest dodatkowe uprawnienie.
Migracja do szablonu MapWithContentTemplate
Od poziomu 7 interfejsu Car App API funkcje
MapTemplate,
PlaceListNavigationTemplate,
i RoutePreviewNavigationTemplate
są wycofane. Wycofane szablony będą nadal obsługiwane, ale zdecydowanie zalecamy przejście na MapWithContentTemplate.
Funkcje udostępniane przez te szablony można zaimplementować za pomocą MapWithContentTemplate. Przykłady znajdziesz w tych fragmentach kodu:
MapTemplate
// MapTemplate (deprecated) val templateDeprecated = MapTemplate.Builder() .setPane(paneBuilder.build()) .setActionStrip(actionStrip) .setHeader(header) .setMapController(mapController) .build() // MapWithContentTemplate val template = MapWithContentTemplate.Builder() .setContentTemplate( PaneTemplate.Builder(paneBuilder.build()) .setHeader(header) .build() ) .setActionStrip(actionStrip) .setMapController(mapController) .build()
PlaceListNavigationTemplate
// PlaceListNavigationTemplate (deprecated) val templateDeprecated = PlaceListNavigationTemplate.Builder() .setItemList(itemListBuilder.build()) .setHeader(header) .setActionStrip(actionStrip) .setMapActionStrip(mapActionStrip) .build() // MapWithContentTemplate val template = MapWithContentTemplate.Builder() .setContentTemplate( ListTemplate.Builder() .setSingleList(itemListBuilder.build()) .setHeader(header) .build() ) .setActionStrip(actionStrip) .setMapController( MapController.Builder() .setMapActionStrip(mapActionStrip) .build() ) .build()
RoutePreviewNavigationTemplate
// RoutePreviewNavigationTemplate (deprecated) val templateDeprecated = RoutePreviewNavigationTemplate.Builder() .setItemList( ItemList.Builder() .addItem( Row.Builder() .setTitle(title) .build() ) .build() ) .setHeader(header) .setNavigateAction( Action.Builder() .setTitle(actionTitle) .setOnClickListener { /* onClick */ } .build() ) .setActionStrip(actionStrip) .setMapActionStrip(mapActionStrip) .build() // MapWithContentTemplate val template = MapWithContentTemplate.Builder() .setContentTemplate( ListTemplate.Builder() .setSingleList( ItemList.Builder() .addItem( Row.Builder() .setTitle(title) .addAction( Action.Builder() .setTitle(actionTitle) .setOnClickListener { /* onClick */ } .build() ) .build() ) .build() ) .setHeader(header) .build() ) .setActionStrip(actionStrip) .setMapController( MapController.Builder() .setMapActionStrip(mapActionStrip) .build() ) .build()
Przesyłanie metadanych nawigacyjnych
Aplikacje do nawigacji muszą przekazywać hostowi dodatkowe metadane nawigacji. Host używa tych informacji, aby przekazywać je do jednostki głównej pojazdu i zapobiegać konfliktom między aplikacjami do nawigacji w zakresie zasobów współdzielonych.
Metadane nawigacyjne są udostępniane za pomocą usługi samochodowej
NavigationManager
dostępnej w ramach
CarContext:
val navigationManager = carContext.getCarService(NavigationManager::class.java)
Rozpoczynanie, kończenie i zatrzymywanie nawigacji
Aby host mógł zarządzać wieloma aplikacjami do nawigacji, powiadomieniami o wyznaczaniu trasy i danymi klastra pojazdu, musi znać bieżący stan nawigacji. Gdy użytkownik rozpoczyna nawigację, wywołaj funkcję
NavigationManager.navigationStarted.
Podobnie, gdy nawigacja się zakończy, np. gdy użytkownik dotrze do miejsca docelowego lub anuluje nawigację, wywołaj funkcję NavigationManager.navigationEnded.
Wywołuj tylko NavigationManager.navigationEnded, gdy użytkownik zakończy nawigację. Jeśli na przykład musisz ponownie obliczyć trasę w trakcie podróży, użyj funkcji Trip.Builder.setLoading(true).
Czasami prowadzący musi zatrzymać nawigację i połączenia w aplikacji
onStopNavigation w obiekcie
NavigationManagerCallback
dostarczonym przez aplikację za pomocą
NavigationManager.setNavigationManagerCallback.
Aplikacja musi wtedy przestać wyświetlać informacje o kolejnym skręcie na ekranie klastra, wysyłać powiadomienia nawigacyjne i udzielać wskazówek głosowych.
Aktualizowanie informacji o przejazdach
Podczas aktywnej nawigacji zadzwoń NavigationManager.updateTrip.
Informacje podane w tym wywołaniu mogą być używane przez zestaw wskaźników i wyświetlacz HUD w samochodzie. W zależności od konkretnego pojazdu nie wszystkie informacje są wyświetlane użytkownikowi.
Na przykład DHU wyświetla Step dodane do Trip, ale nie wyświetla informacji Destination.
Rysowanie na wyświetlaczu klastra
Aby zapewnić użytkownikom jak najlepsze wrażenia, możesz wyjść poza wyświetlanie podstawowych metadanych na wyświetlaczu klastra pojazdu. Od poziomu 6 interfejsu Car App API aplikacje nawigacyjne mogą renderować własne treści bezpośrednio na wyświetlaczu deski rozdzielczej (w obsługiwanych pojazdach) z następującymi ograniczeniami:
- Interfejs API wyświetlacza klastra nie obsługuje elementów sterujących
- Wskazówki dotyczące jakości aplikacji samochodowych
NF-9: Wyświetlacz klastra powinien wyświetlać tylko kafelki mapy. Na tych kafelkach można opcjonalnie wyświetlać aktywną trasę nawigacji. - Interfejs API wyświetlania klastra obsługuje tylko użycie
NavigationTemplate- W przeciwieństwie do wyświetlaczy głównych wyświetlacze klastra mogą nie wyświetlać wszystkich
NavigationTemplateelementów interfejsu, takich jak szczegółowe instrukcje, karty z szacowanym czasem przybycia i działania. Kafelki mapy to jedyny element interfejsu, który jest wyświetlany w sposób ciągły.
- W przeciwieństwie do wyświetlaczy głównych wyświetlacze klastra mogą nie wyświetlać wszystkich
Deklarowanie obsługi klastra
Aby poinformować aplikację hosta, że Twoja aplikacja obsługuje renderowanie na wyświetlaczach klastrowych, musisz dodać element androidx.car.app.category.FEATURE_CLUSTER
<category> do elementu CarAppService<intent-filter> w sposób pokazany w tym fragmencie kodu:
<application>
...
<service
...
android:name=".MyNavigationCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.NAVIGATION"/>
<category android:name="androidx.car.app.category.FEATURE_CLUSTER"/>
</intent-filter>
</service>
...
</application>
Zarządzanie cyklem życia i stanem
Od poziomu API 6 cykl życia aplikacji samochodowej pozostaje taki sam, ale funkcja CarAppService::onCreateSession przyjmuje teraz parametr typu SessionInfo, który zawiera dodatkowe informacje o tworzonym Session (czyli typ wyświetlacza i zestaw obsługiwanych szablonów).
Aplikacje mogą używać tej samej klasy Session do obsługi zarówno klastra, jak i głównego wyświetlacza, lub tworzyć klasy Sessions specyficzne dla wyświetlacza, aby dostosowywać działanie na każdym wyświetlaczu (jak pokazano w tym fragmencie kodu).
override fun onCreateSession(sessionInfo: SessionInfo): Session { return if (sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER) { ClusterSession() } else { MainDisplaySession() } }
Nie ma gwarancji, że wyświetlanie klastra będzie dostępne, ani kiedy to nastąpi. Może się też zdarzyć, że klaster Session będzie jedynym Session (np. użytkownik przełączył główny wyświetlacz na inną aplikację, gdy Twoja aplikacja aktywnie nawiguje). „Standardowa” umowa polega na tym, że aplikacja uzyskuje kontrolę nad wyświetlaniem klastra dopiero po wywołaniu funkcji NavigationManager::navigationStarted. Może się jednak zdarzyć, że aplikacja otrzyma wyświetlanie klastra, gdy nie będzie aktywna nawigacja, lub nigdy nie otrzyma wyświetlania klastra. To aplikacja musi obsługiwać te scenariusze, renderując stan bezczynności kafelków mapy.
Host tworzy osobne bindery i CarContext instancji na Session. Oznacza to, że w przypadku metod takich jak ScreenManager::push czy Screen::invalidate dotyczy to tylko Session, z którego są one wywoływane. Aplikacje powinny tworzyć własne kanały komunikacji między tymi instancjami, jeśli potrzebna jest komunikacja międzyprocesowa (np. za pomocą broadcastów, wspólnego singletonu lub czegoś innego).Session
Pomoc dotycząca klastra testowego
Możesz przetestować wdrożenie zarówno w Androidzie Auto, jak i w systemie operacyjnym Android Automotive. W przypadku Androida Auto odbywa się to przez skonfigurowanie jednostki głównej na komputerze tak, aby emulowała wyświetlacz klastra dodatkowego. W przypadku systemu operacyjnego Android Automotive podstawowe obrazy systemu na poziomie API 30 i wyższym emulują wyświetlacz klastra.
Dostosowywanie elementu TravelEstimate za pomocą tekstu lub ikony
Aby dostosować szacunkowy czas podróży za pomocą tekstu, ikony lub obu tych elementów, użyj metod TravelEstimate.Builder, setTripIcon lub setTripText klasy
TravelEstimate.Builder. Element
NavigationTemplate
używa
TravelEstimate
do opcjonalnego ustawiania tekstu i ikon obok lub zamiast szacowanego czasu przybycia, pozostałego czasu i pozostałego dystansu.
W tym fragmencie kodu użyto symboli setTripIcon i setTripText, aby dostosować szacunkowy czas podróży:
TravelEstimate.Builder( Distance.create(350.0, Distance.UNIT_METERS), arrivalTimeAtDestination ) .setTripIcon( CarIcon.Builder( IconCompat.createWithResource(carContext, R.drawable.ic_garage) ).build() ) .setTripText(CarText.create("Custom Text")) .build()
przekazywać powiadomienia o kolejnych krokach,
Udostępniaj szczegółowe instrukcje nawigacyjne za pomocą często aktualizowanych powiadomień nawigacyjnych. Aby powiadomienie było traktowane jako powiadomienie nawigacyjne na ekranie samochodu, jego konstruktor musi wykonać te czynności:
- Oznacz powiadomienie jako w trakcie za pomocą metody
NotificationCompat.Builder.setOngoing. - Ustaw kategorię powiadomienia na
Notification.CATEGORY_NAVIGATION. - Wydłuż powiadomienie za pomocą elementu
CarAppExtender.
Powiadomienie o nawigacji wyświetli się w widżecie na dole ekranu samochodu. Jeśli poziom ważności powiadomienia jest ustawiony na IMPORTANCE_HIGH, wyświetla się ono również jako powiadomienie z ostrzeżeniem.
Jeśli ważność nie zostanie ustawiona za pomocą metody CarAppExtender.Builder.setImportance, zostanie użyta ważność kanału powiadomień.
Aplikacja może ustawić PendingIntent w CarAppExtender, który jest wysyłany do aplikacji, gdy użytkownik kliknie HUN lub widżet kolumny bocznej.
Jeśli funkcja
NotificationCompat.Builder.setOnlyAlertOnce
zostanie wywołana z wartością true, powiadomienie o wysokim priorytecie będzie wyświetlane w HUN tylko
raz.
Poniższy fragment kodu pokazuje, jak utworzyć powiadomienie o nawigacji:
NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setOnlyAlertOnce(true) .setOngoing(true) .setCategory(NotificationCompat.CATEGORY_NAVIGATION) .extend( CarAppExtender.Builder() .setContentTitle(carScreenTitle) .setContentIntent( PendingIntent.getBroadcast( context, ACTION_OPEN_APP.hashCode(), Intent(ACTION_OPEN_APP).setComponent( ComponentName(context, MyNotificationReceiver::class.java) ), PendingIntent.FLAG_IMMUTABLE ) ) .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH) .build() ) .build()
Regularnie aktualizuj powiadomienie TBT w przypadku zmian odległości, co spowoduje aktualizację widżetu kolejowego. Powiadomienie powinno być wyświetlane tylko jako HUN.
Możesz kontrolować działanie HUN, ustawiając ważność powiadomienia za pomocą parametru
CarAppExtender.Builder.setImportance. Ustawienie ważności na
IMPORTANCE_HIGH powoduje wyświetlenie numeru HUN. Ustawienie innej wartości spowoduje tylko zaktualizowanie widżetu kolumny bocznej.
Odświeżanie treści PlaceListNavigationTemplate
Podczas przeglądania list miejsc utworzonych za pomocą PlaceListNavigationTemplate kierowcy mogą odświeżać treści jednym kliknięciem.
Aby włączyć odświeżanie listy, zaimplementuj metodę onContentRefreshRequested interfejsu OnContentRefreshListener i użyj PlaceListNavigationTemplate.Builder.setOnContentRefreshListener, aby ustawić odbiornik w szablonie.
Poniższy fragment kodu pokazuje, jak ustawić odbiornik w szablonie:
PlaceListNavigationTemplate.Builder() .setOnContentRefreshListener { // Execute any desired logic // Then call invalidate() so onGetTemplate() is called again screen.invalidate() } .build()
Przycisk odświeżania jest widoczny tylko w nagłówku elementu PlaceListNavigationTemplate, jeśli odbiornik ma wartość.
Gdy użytkownik kliknie przycisk odświeżania, wywoływana jest metoda onContentRefreshRequested w Twojej implementacji OnContentRefreshListener. W funkcji onContentRefreshRequested wywołaj metodę Screen.invalidate.
Następnie host wywołuje metodę Screen.onGetTemplate w aplikacji, aby pobrać szablon ze zaktualizowaną treścią. Więcej informacji o odświeżaniu szablonów znajdziesz w artykule Odświeżanie zawartości szablonu. Dopóki następny szablon zwracany przez onGetTemplate jest tego samego typu, jest on traktowany jako odświeżenie i nie wlicza się do limitu szablonów.
przekazywać wskazówki głosowe,
Aby odtwarzać wskazówki nawigacyjne przez głośniki samochodu, aplikacja musi poprosić o aktywność audio. W ramach AudioFocusRequest ustaw wykorzystanie jako AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE. Ustaw też wzmocnienie ostrości na AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK.
Symulowanie nawigacji
Aby zweryfikować funkcję nawigacji w aplikacji podczas przesyłania jej do Sklepu Google Play, musi ona implementować wywołanie zwrotne NavigationManagerCallback.onAutoDriveEnabled. Gdy to wywołanie zwrotne zostanie wywołane, aplikacja musi symulować nawigację do wybranego miejsca docelowego, gdy użytkownik rozpocznie nawigację. Aplikacja może wyjść z tego trybu, gdy cykl życia bieżącego Session osiągnie stan Lifecycle.Event.ON_DESTROY.
Aby sprawdzić, czy implementacja funkcji onAutoDriveEnabled jest wywoływana, wykonaj to polecenie w wierszu poleceń:
adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE
Pokazuje to poniższy przykład:
adb shell dumpsys activity service androidx.car.app.samples.navigation.car.NavigationCarAppService AUTO_DRIVE
Domyślna aplikacja do nawigacji w samochodzie
W Androidzie Auto domyślna aplikacja nawigacyjna w samochodzie to ostatnia aplikacja nawigacyjna uruchomiona przez użytkownika. Aplikacja domyślna otrzymuje intencje nawigacji, gdy użytkownik wywołuje polecenia nawigacji za pomocą Asystenta lub gdy inna aplikacja wysyła intencję rozpoczęcia nawigacji.
Wyświetlanie alertów nawigacyjnych w kontekście
Alert wyświetla kierowcy ważne informacje z opcjonalnymi działaniami – bez opuszczania kontekstu ekranu nawigacji. Aby zapewnić kierowcy jak najlepsze wrażenia, usługa
Alert działa w ramach
NavigationTemplate
i nie blokuje trasy nawigacji oraz minimalizuje rozproszenie uwagi kierowcy.
Alert jest dostępna tylko w NavigationTemplate.
Aby powiadomić użytkownika poza NavigationTemplate, rozważ użycie powiadomienia z ostrzeżeniem (HUN), jak wyjaśniono w artykule Wyświetlanie powiadomień.
Na przykład użyj symbolu Alert, aby:
- informować kierowcę o aktualizacjach związanych z bieżącą nawigacją, np. o zmianach w warunkach na drodze;
- Poproś kierowcę o aktualne informacje dotyczące bieżącej nawigacji, np. o to, czy w pobliżu znajduje się urządzenie do kontroli prędkości.
- Proponowanie nadchodzącego zadania i pytanie, czy kierowca je akceptuje, np. czy jest gotowy odebrać kogoś po drodze.
W podstawowej formie Alert składa się z tytułu i Alert czasu trwania. Czas trwania jest przedstawiony na pasku postępu. Opcjonalnie możesz dodać podtytuł, ikonę i maksymalnie 2 obiekty Action.
Gdy wyświetli się Alert, nie będzie ono przenoszone do innego szablonu, jeśli interakcja kierowcy spowoduje opuszczenie NavigationTemplate.
Pozostaje w pierwotnym NavigationTemplate do momentu Alert, gdy upłynie limit czasu, użytkownik podejmie działanie lub aplikacja odrzuci Alert.
Utwórz alert
Aby utworzyć instancję Alert, użyj Alert.Builder:
Alert.Builder( 1, // alertId CarText.create("Hello"), // title 5000 // durationMillis ) // The fields below are optional .addAction(firstAction) .addAction(secondAction) .setSubtitle(CarText.create("Subtitle")) .setIcon(CarIcon.APP_ICON) .setCallback(alertCallback) .build()
Jeśli chcesz nasłuchiwać Alertanulowania lub odrzucenia, utwórz implementację interfejsu AlertCallback.
Ścieżki połączeń AlertCallback to:
Jeśli
Alertprzekroczy limit czasu, host wywoła metodęAlertCallback.onCancelz wartościąAlertCallback.REASON_TIMEOUT. Następnie wywołuje metodęAlertCallback.onDismiss.Jeśli kierowca kliknie jeden z przycisków polecenia, host wywoła funkcję
Action.OnClickListenera następnie funkcjęAlertCallback.onDismiss.Jeśli atrybut
Alertnie jest obsługiwany, host wywołuje funkcjęAlertCallback.onCancelz wartościąAlertCallback.REASON_NOT_SUPPORTED. Gospodarz nie dzwoniAlertCallback.onDismiss, ponieważ nie wyświetlił sięAlert.
Konfigurowanie czasu trwania alertu
Wybierz czas trwania Alert, który odpowiada potrzebom Twojej aplikacji. Zalecany czas trwania nawigacjiAlert to 10 sekund. Więcej informacji znajdziesz w artykule Alerty nawigacyjne.
Wyświetlanie alertu
Aby wyświetlić Alert, wywołaj metodę
AppManager.showAlert
dostępną w CarContext aplikacji.
carContext.getCarService(AppManager::class.java).showAlert(alert)
- Wywołanie funkcji
showAlertz parametremAlert, który ma parametralertIdo takim samym identyfikatorze jak identyfikator parametruAlert, który jest już wyświetlany, nie powoduje żadnych zmian.Alertsię nie aktualizuje. Aby zaktualizowaćAlert, musisz utworzyć go ponownie z nowymalertId. - Wywołanie funkcji
showAlertz parametremAlert, który ma inny parametralertIdniż parametrAlertjuż wyświetlany, powoduje zamknięcie wyświetlanego alertuAlert.
Odrzucanie alertu
Alert automatycznie znika z powodu przekroczenia limitu czasu lub interakcji kierowcy, ale możesz też ręcznie zamknąć Alert, np. jeśli informacje w nim zawarte staną się nieaktualne. Aby odrzucić Alert, wywołaj metodę dismissAlert z parametrem alertId Alert.
carContext.getCarService(AppManager::class.java).dismissAlert(alert.id)
Wywołanie funkcji dismissAlert za pomocą elementu alertId, który nie pasuje do już wyświetlonego elementu Alert, nie przynosi żadnego efektu. Nie zgłasza wyjątku.