The Android for Cars App Library allows you to bring your navigation, parking, and charging apps to the car. It does so by providing a set of templates designed to meet driver distraction standards and taking care of details such as the variety of car screen factors and input modalities.
This guide provides an overview of the library’s key features and concepts, and walks you through the process of setting up a simple app.
Before you begin
- Review the Android for Cars App Library Design Guidelines.
- Review the key terms and concepts listed in this section.
- Familiarize yourself with the Android Auto System UI.
- Review the Release Notes.
- Review the Samples.
- [Closed source library only] Review the Android for Cars App Library Terms of Use.
Key terms and concepts
- Models and Templates
- The user interface is represented by a graph of model objects that can be arranged together in different ways as allowed by the template they belong to. Templates are a subset of the models that can act as a root in those graphs. Models include the information to be displayed to the user, in the form of text and images, as well as attributes to configure aspects of the visual appearance of such information (for example, text colors or image sizes). The host converts the models to views that are designed to meet driver distraction standards and takes care of details such as the variety of car screen factors and input modalities.
- Host
- The host is the back end component that implements the functionality offered by the library’s APIs in order for your app to run in the car. The responsibilities of the host range from discovering your app and managing its lifecycle, to converting your models into views and notifying your app of user interactions. On mobile devices, this host is implemented by Android Auto.
- Template restrictions
- Different templates enforce restrictions in the content of their models. For example, list templates have limits on the number of items that can be presented to the user. Templates also have restrictions in the way they can be connected to form the flow of a task. For example, the app can only push up to 5 templates to the screen stack. See Template restrictions for more details.
- Screen
- A
Screen
is a class provided by the library that apps implement to manage the user interface presented to the user. AScreen
has alifecycle
and provides the mechanism for the app to send the template to display when the screen is visible.Screen
instances can also be pushed and popped to and from a Screen stack, which ensures they adhere to the template flow restrictions. - CarAppService
- A
CarAppService
is an abstractService
class that your app must implement and export in order to be discovered and managed by the host. Your app'sCarAppService
is responsible for validating that a host connection can be trusted usingCarAppService.createHostValidator
, and subsequently providingSession
instances for each connection usingCarAppService.onCreateSession
. - Session
- A
Session
is an abstract class that your app must implement and return usingCarAppService.onCreateSession
. It serves as the entry point to display information on the car screen, and has a lifecycle that informs the current state of your app on the car screen, such as when your app is visible or hidden.
When a Session
is started (such as
when the app is first launched), the host requests for the initial Screen
to display using the Session.onCreateScreen
method.
Install the library
Please follow the Jetpack library release page for instructions on how to add the library to your app.
Configure your app’s manifest files
Before you can create your car app, you need to configure your app’s manifest files.
Declare your CarAppService
The host connects to your app through your CarAppService
implementation. You declare this service in your manifest to allow the host to
discover and connect to your app.
You also need to declare your app’s category in the
category
element of your app’s
intent filter. See the list of supported app categories
for the values allowed for this element.
The following code snippet shows how to declare a car app service for a parking app in your manifest:
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService"/>
<category android:name="androidx.car.app.category.PARKING"/>
</intent-filter>
</service>
...
<application>
Supported App Categories
In order to be listed in the Play Store for Android Auto, the app needs to belong to one of the supported car app categories. You declare your app’s category by adding one or more of the following supported category values in the intent filter when you declare your car app service:
androidx.car.app.category.NAVIGATION
: An app that provides turn-by-turn navigation directions.androidx.car.app.category.PARKING
: An app that provides functionality relevant to finding parking spots.androidx.car.app.category.CHARGING
: An app that provides functionality relevant to finding electric vehicle charging stations.
See Android app quality for cars for the detailed description and criteria for apps to belong to each category.
Specify the app name and icon
You need to specify an app name and icon that the host can use to represent your app in the system UI.
You can specify the app name and icon that is used to represent your app using
the label
and
icon
elements of your
CarAppService
:
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
If the label or icon are not declared in the
service
element, the host will fall
back to the values specified for the application.
Set your app's minSdkVersion
Android Auto requires your app to target Android 6.0 (API level 23) or higher.
To specify this value in your project, set the minSdkVersion
attribute in
the uses-sdk
element to 23 or higher in your phone app module's
AndroidManifest.xml
file, as shown in the following example:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
...
</manifest>
Declare Android Auto support
The Android Auto host checks that the app has declared support for Android Auto. To enable this support, include the following entry in your app's manifest:
<application>
...
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc"/>
...
</application>
This manifest entry refers to another XML file that you should create with the
path YourAppProject/app/src/main/res/xml/automotive_app_desc.xml
where you
declare what Android Auto capabilities your app supports.
Apps using the Android for Cars App Library must declare the template
capability in the automotive_app_desc.xml
file:
<automotiveApp>
<uses name="template" />
</automotiveApp>
Create your CarAppService and Session
Your app needs to extend the CarAppService
class and implement the CarAppService.onCreateSession
method, which returns a Session
instance corresponding to the current connection to the host:
public final class HelloWorldService extends CarAppService {
...
@Override
@NonNull
public Session onCreateSession() {
return new HelloWorldSession();
}
...
}
The Session
instance is responsible for
returning the Screen
instance to use the
first time the app is started:
public final class HelloWorldSession extends Session {
...
@Override
@NonNull
public Screen onCreateScreen(@NonNull Intent intent) {
return new HelloWorldScreen();
}
...
}
To handle scenarios where your car app needs to start from a screen that is not
the home or landing screen of your app (such as handling deep links), you can
pre-seed a back stack of screens using ScreenManager.push
.
before returning from onCreateScreen
.
Pre-seeding allows users to navigate back to previous screens from the first
screen that your app is showing.
Create your start screen
You create the screens displayed by your app by defining classes that extend the
Screen
class and implementing the
Screen.onGetTemplate
method, which returns the Template
instance representing the state of the UI to display in the car screen.
The following snippet shows how to declare a Screen
that uses a PaneTemplate
template to display a simple “Hello world!” string:
public class HelloWorldScreen extends Screen {
@NonNull
@Override
public Template onGetTemplate() {
Pane pane = new Pane.Builder()
.addRow(new Row.Builder()
.setTitle("Hello world!")
.build())
.build();
return new PaneTemplate.Builder(pane)
.setHeaderAction(Action.APP_ICON)
.build();
}
}
The CarContext class
The CarContext
class is a
ContextWrapper
subclass
accessible to your Session
and
Screen
instances, which provides access
to car services such as the ScreenManager
for managing the screen stack, the AppManager
for general app-related functionality such as accessing the Surface
object for
drawing your navigation app’s map, and the
NavigationManager
used by turn-by-turn navigation apps to communicate navigation metadata
and other navigation-related events with
the host. See Access the navigation templates
for a comprehensive list of library functionality available to navigation apps.
The CarContext
also offers other
functionality such as allowing loading drawableresources using the configuration
from the car screen, starting an app in the car using intents,
and signaling whether your navigation app should display its map
in dark mode.
Implement screen navigation
Apps often present a number of different screens, each possibly utilizing different templates, that the user can navigate through as they interact with the interface displayed in the screen.
The ScreenManager
class provides
a screen stack that you can use to push screens that can be popped automatically
when the user selects a back button in the car screen, or uses the hardware back
button available in some cars.
The following snippet shows how to add a back action to message template, as well as an action that pushes a new screen when selected by the user:
MessageTemplate template = new MessageTemplate.Builder("Hello world!")
.setHeaderAction(Action.BACK)
.addAction(
new Action.Builder()
.setTitle("Next screen")
.setOnClickListener(() -> getScreenManager().push(new NextScreen()))
.build())
.build();
The Action.BACK
object is a
standard Action
that automatically
invokes ScreenManager.pop
.
This behavior can be overridden by using the OnBackPressedDispatcher
instance available from the CarContext
.
To ensure the app is safe while driving, the screen stack can have a maximum depth of 5 screens. See Template restrictions for more details.
Refresh the contents of a template
Your app can request the content of a Screen
to be invalidated by calling the Screen.invalidate
method. The host subsequently calls back into your app’s
Screen.onGetTemplate
method to retrieve the template with the new contents.
When refreshing a Screen
, it is
important to understand the specific content in the template that can be updated
so that the host will not count the new template against the template quota.
See Template restrictions for more details.
It is recommended that you structure your screens so that there is a
one-to-one mapping between a Screen
and
the type of template it returns through its Screen.onGetTemplate
implementation.
Handle user input
Your app can respond to user input by passing the appropriate listeners to the
models that support them. The following snippet shows how to create an
Action
model that sets an
OnClickListener
that
calls back to a method defined by your app’s code:
Action action = new Action.Builder()
.setTitle("Navigate")
.setOnClickListener(this::onClickNavigate)
.build();
The onClickNavigate
method can then start the default navigation car app by
using the CarContext.startCarApp
method:
private void onClickNavigate() {
Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
getCarContext().startCarApp(intent);
}
For more details on how to start apps, including the format of the
ACTION_NAVIGATE
intent, see Start a car app with an intent.
Some actions, such as those that require directing the user to continue the
interaction on their mobile devices, are only allowed when the car is parked.
You can use the ParkedOnlyOnClickListener
to implement those actions. If the car is not parked, the host will display an
indication to the user that the action is not allowed in this case. If the car
is parked, the code will execute normally. The following snippet shows how to
use the ParkedOnlyOnClickListener
to open a settings screen on the mobile device:
Row row = new Row.Builder()
.setTitle("Open Settings")
.setOnClickListener(
ParkedOnlyOnClickListener.create(this::openSettingsOnPhone)
.build();
Display notifications
Notifications sent to the mobile device will only show up in the car screen if
they are extended with a CarAppExtender
.
Some notification attributes, such as content title, text, icon, and actions,
can be set in the CarAppExtender
, overriding the notification's attributes
when appearing in the car screen.
The following snippet shows how to send a notification to the car screen that displays a different title than the one shown on the mobile device:
Notification notification =
new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setContentTitle(titleOnThePhone)
.extend(
new CarAppExtender.Builder()
.setContentTitle(titleOnTheCar)
...
.build())
.build();
Notifications can affect the following parts of the user interface:
- A heads-up notification (HUN) may be displayed to the user.
- An entry in the notification center may be added, optionally with a badge visible in the rail.
- For navigation apps, the notification may be displayed in the rail widget as described in Turn-by-turn notifications.
Applications can choose how to configure their notifications to affect each of
those user interface elements by using the notification’s priority, as described
in the CarAppExtender
documentation.
If NotificationCompat.Builder.setOnlyAlertOnce
is called with a value of true
, a high-priority notification will display as
a HUN only once.
For more information on how to design your car app’s notifications, see Notifications.
Show toasts
Your app can display a toast using CarToast
as shown in this snippet:
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
Start a car app with an intent
You can call the CarContext.startCarApp
method to perform one of the following actions:
- Open the dialer to make a phone call.
- Start turn-by-turn navigation to a location with the default navigation car app.
- Start your own app with an intent.
The following example shows how to create a notification with an action that
opens your app with a screen that shows the details of a parking reservation.
You extend the notification instance with a content intent that contains a
PendingIntent
wrapping an explicit
intent to your app’s action:
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())
Your app must also declare a BroadcastReceiver
that is invoked to process the intent when the user selects the action in the
notification interface and invokes CarContext.startCarApp
with an intent including the data URI:
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)));
}
}
}
Finally, the Session.onNewIntent
method in your app handles this intent by pushing the parking reservation screen
on the stack if not already on top:
@Override
public void onNewIntent(@NonNull Intent intent) {
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 screenManager = getCarContext().getCarService(ScreenManager.class);
screenManager.push(new ParkingReservationScreen(getCarContext()));
}
}
}
See Display notifications for more information on how to handle notifications for the car app.
Template restrictions
The host limits the number of templates to display for a given task to a maximum of 5, of which the last template of the 5 must be one of the following types:
If the template quota is exhausted and the app attempts to send a new
template, the host will display an error message to the user. Note that this
limit applies to the number of templates, and not the number of Screen
instances in the stack. For example, if while in screen A an app sends 2
templates, and then pushes screen B, it can now send 3 more templates.
Alternatively, if each screen is structured to send a single template, then
the app can push 5 screen instances onto the ScreenManager
stack.
There are special cases to these restrictions: template refreshes, back and reset operations.
Template refreshes
Certain content updates are not counted towards the template limit. In general,
as long as an app pushes a new template that is of the same type and contains
the same main content as the previous template, the new template will not be
counted against the quota. For example, updating the toggle state of a row in a
ListTemplate
does not count
against the quota. See the documentation of individual templates to learn more
about what types of content updates can be considered a refresh.
Back operations
To enable sub-flows within a task, the host detects when an app is popping a
Screen
from the ScreenManager
stack, and updates the remaining quota based on the number of templates that the
app is going backwards by.
For example, if while in screen A, the app sends 2 templates and then pushes screen B and sends 2 more templates, then the app has 1 quota remaining. If the app now pops back to screen A, the host will reset the quota to 3, because the app has gone backwards by 2 templates.
Note that when popping back to a screen, an app must send a template that is of the same type as the one last sent by that screen. Sending any other template types would cause an error. However, as long as the type remains the same during a back operation, an app can freely modify the contents of the template without affecting the quota.
Reset operations
Certain templates have special semantics that signify the end of a task. For
example, the NavigationTemplate
is a view that is expected to stay on the screen and be refreshed with new
turn-by-turn instructions for the user’s consumption. Upon reaching one of these
templates, the host will reset the template quota, treating that template as if
it is the first step of a new task, thus allowing the app to begin a new task.
See the documentation of individual templates to see which ones trigger a reset
on the host.
If the host receives an intent to start the app from a notification action or from the launcher, the quota will also be reset. This mechanism allows an app to begin a new task flow from notifications, and it holds true even if an app is already bound and in the foreground.
See Display notifications for more details on how to display your app’s notifications in the car screen, and Start a car app with an intent for how to start your app from a notification action.
Build a parking or charging app
This section details the different features of the library that you can make use of to implement the functionality of your parking or charging app.
Declare category support in your manifest
Your app needs to declare either the
androidx.car.app.category.PARKING
or androidx.car.app.category.CHARGING
car app category in the intent filter of its
CarAppService
. For example:
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.PARKING"/>
</intent-filter>
</service>
...
<application>
Access the map template
Apps can access the PlaceListMapTemplate
specifically designed for showing a list of points of interest alongside a map
that is rendered by the host.
In order to get access to this template, your app needs to declare the
androidx.car.app.MAP_TEMPLATES
permission in its AndroidManifest.xml
:
<uses-permission android:name="androidx.car.app.MAP_TEMPLATES"/>
Build a navigation app
This section details the different features of the library that you can make use of to implement the functionality of your turn-by-turn navigation app.
Declare navigation support in your manifest
Your navigation app needs to declare the androidx.car.app.category.NAVIGATION
car app category in the intent filter of its
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>
Support navigation intents
In order to support navigation Intents to your app, including those coming from
the Google Assistant using a voice query, your app needs to handle the
CarContext.ACTION_NAVIGATE
intent in its Session.onCreateScreen
and Session.onNewIntent
.
See the documentation of CarContext.startCarApp
for details on the format of the intent.
Access the navigation templates
Navigation apps can access the following templates specifically designed for navigation apps. All these templates display a surface in the background that your app can access in order to draw your map, alongside other information provided by your app which varies per template.
NavigationTemplate
: displays the map along with an optional informational message or routing directions and travel estimates during active navigation.PlaceListNavigationTemplate
: displays a list of places that can have corresponding markers drawn in the map.RoutePreviewNavigationTemplate
: displays a list of routes one of which can be selected and highlighted in the map.
For more details on how to design your navigation app’s user interface using those templates, see the Android for Cars App Library Design Guidelines.
In order to get access to the navigation templates, your app needs to declare
the androidx.car.app.NAVIGATION_TEMPLATES
permission in its
AndroidManifest.xml
:
<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>
Drawing the Map
Navigation applications can access a Surface
to draw the map on relevant templates.
A SurfaceContainer
object can
then be accessed by setting a SurfaceCallback
instance to the AppManager
car
service:
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
The SurfaceCallback
provides a
callback when the SurfaceContainer
is available along with other callbacks when the Surface
’s properties change.
In order to get access to the surface, your app needs to declare the
androidx.car.app.ACCESS_SURFACE
permission in its AndroidManifest.xml
:
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>
The map’s visible area
The host may draw user interface elements for the different templates on top of
the map. The host will communicate the area that is guaranteed to be unoccluded
and fully visible to the user by calling the
SurfaceCallback.onVisibleAreaChanged
.
Also, in order to minimize the number of changes, the host will also call the
SurfaceCallback.onStableAreaChanged
method with the largest rectangle which will be visible based on the current
template.
For example, when a navigation app is using the NavigationTemplate
with an action strip on top, the action strip may hide itself when the user has
not interacted with the screen for a while to make more space for the map. In
this case, there will be a callback to onStableAreaChanged
and
onVisibleAreaChanged
with the same rectangle. When the action strip is hidden,
only onVisibleAreaChanged
will be called with the larger area. If the user
interacts with the screen, then again only onVisibleAreaChanged
is called with
the first rectangle.
Dark mode
Navigation applications must redraw their map onto the Surface
instance with
the proper dark colors when the host determines that conditions warrant it, as
described in the Android Auto app quality guidelines.
In order to decide on whether you should draw a dark map you can use the
CarContext.isDarkMode
method. Whenever the dark mode status changes, you will receive a call to
Session.onCarConfigurationChanged
.
Navigation metadata
Navigation applications must communicate additional navigation metadata with the host. The host makes use of the information to provide information to the vehicle head unit and to prevent navigation applications from clashing over shared resources.
Navigation metadata is provided through the NavigationManager
car service accessible from the CarContext
:
NavigationManager navigationManager = carContext.getCarService(NavigationManager.class);
Starting, ending, and stopping navigation
In order for the host to manage multiple navigation apps, routing notifications,
and vehicle cluster data, it needs to be aware of the current state of
navigation. When a user starts navigation, the app should call
NavigationManager.navigationStarted
.
Similarly, when navigation ends, for example when the user arrives at their
destination or the user cancels navigation, the app should call
NavigationManager.navigationEnded
.
You should only call NavigationManager.navigationEnded
when the user is finished navigating. For example, if you need to recalculate
the route in the middle of a trip, use Trip.Builder.setLoading(true)
instead.
Occasionally, the host will need an app to stop navigation and will call
stopNavigation
in a NavigationManagerListener
object provided by your app
through NavigationManager.setListener
. The app must then stop issuing
next-turn information in the cluster display, navigation notifications, and voice guidance.
Trip information
During active navigation, the app should call NavigationManager.updateTrip
.
The information provided in this call will be used in the vehicle’s cluster and
heads-up displays. Not all information may be displayed to the user depending on
the particular vehicle being driven.
In order to test that the information is reaching the cluster the Desktop Head
Unit (DHU) tool can be configured to show a simple cluster display. Create an
cluster.ini
file with the following contents:
[general]
instrumentcluster = true
You can then invoke the DHU with an additional command line parameter:
dhu -c cluster.ini
Turn-by-turn notifications
The turn-by-turn (TBT) navigation instructions can be given with a frequently updated navigation notification. In order to be treated as a navigation notification in the car screen, your notification's builder must do the following:
- Mark the notification as ongoing with the
NotificationCompat.Builder.setOngoing
method. - Set the notification’s category to
Notification.CATEGORY_NAVIGATION
. - Extend the notification with a
CarAppExtender
.
A navigation notification will be displayed in the rail widget at the bottom of
the car screen. If the notification's importance level is set to
IMPORTANCE_HIGH
, it will also be displayed as a heads-up notification (HUN).
If the importance is not set with the CarAppExtender.Builder.setImportance
method, the notification channel's importance
will be used.
The app can set a PendingIntent
in the
CarAppExtender
that
will be sent to the app when the user taps on the HUN or the rail widget.
If NotificationCompat.Builder.setOnlyAlertOnce
is called with a value of true
, a high-importance notification will alert only
once in the HUN.
The following snippet shows how to build a navigation notification:
new NotificationCompat.Builder(context, myNotificationChannelId)
...
.setOnlyAlertOnce(true)
.setOngoing(true)
.setCategory(NotificationCompat.CATEGORY_NAVIGATION)
.extend(
new CarAppExtender.Builder()
.setContentTitle(carScreenTitle)
...
.setContentIntent(
PendingIntent.getBroadcast(
context,
ACTION_OPEN_APP.hashCode(),
new Intent(ACTION_OPEN_APP)
.setComponent(
new ComponentName(context, MyNotificationReceiver.class)),
0))
.setImportance(NotificationManagerCompat.IMPORTANCE_HIGH)
.build())
Guidelines for turn-by-turn notifications
Navigation apps should update the TBT notification regularly on distance
changes, which updates the rail widget, and only show the notification as a HUN.
Apps can control the HUN behavior by setting the notification's importance with
the CarAppExtender.Builder.setImportance
method. Setting the importance to IMPORTANCE_HIGH
will show a HUN, and setting
it to any other value will only update the rail widget.
Voice Guidance
To play navigation guidance over the car speakers your app must request
audio focus. As a part of your
AudioFocusRequest
you should set
the usage as AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE
. You should
also set the focus gain as AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
.
Simulating navigation
In order to verify your app's navigation functionality when submitting it to the
Google Play Store, your app must implement the
NavigationManagerCallback.onAutoDriveEnabled
callback. When this callback is called, your app should simulate navigation to
the chosen destination when the user begins navigation. Your app can exit this
mode whenever the current Session
's
lifecycle reaches the Lifecycle.Event#ON_DESTROY
state.
You can test that your implementation of onAutoDriveEnabled
is called by
executing the following from a command line:
adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE
For example:
adb shell dumpsys activity service androidx.car.app.samples.navigation.car.NavigationCarAppService AUTO_DRIVE
Default navigation car app
In Android Auto, the default navigation car app corresponds to the last navigation app that the user launched. This is the app that, for example, will receive navigation intents when the user invokes navigation commands through the assistant or when another app sends an intent to start navigation.
The CarAppService, Session and Screen Lifecycles
The Session
and Screen
classes implement the LifecycleOwner
interface. As the user interacts with the app, your Session
and Screen
objects’ lifecycle callbacks will be invoked, as described in the following
diagrams.
The lifecycles of a CarAppService and a Session

Session
lifecycle.For full details see the documentation of Session.getLifecycle
method.
The lifecycle of a Screen

Screen
lifecycle.For full details see the documentation of
Screen.getLifecycle
.
Testing Library
The Android for Cars Testing Library
provides auxiliary classes that you can use to validate your apps' behavior in
a test environment. For example, the SessionController
allows you to simulate a connection to the host and verify that the correct
Screen
and Template
are created and returned.
Refer to the Samples for usage examples.
Running the app on a real head unit
In order for your app to run on a real head unit (not the desktop head unit we provide), your app must be distributed via the Google Play Store. This ensures that your application has been tested and vetted for adherence to our guidelines. These guidelines ensure that your application is relevant to the car environment, as well as pass our driver distraction tests.
For testing while under development, there are two options, the desktop head unit, as well as pushing your application to a Google Play Store's "Internal test track". The internal test track allows you to manually add your team to allow for internal testing. Releases to this track will not require play store reviews.
Whenever you release your APK to any other track, including closed tracks, your app will undergo a review process before being approved into that track in the play store. If the application fails the review process, you will receive information as to why it did not pass. This process allows you to fix any issues in order to comply with our guidelines.
Report an Android for Cars App Library issue
If you find an issue with the library, report it using the Google Issue Tracker. Be sure to fill out all the requested information in the issue template.
Before filing a new issue, please check if it is listed in the library's release notes or reported in the issues list. You can subscribe and vote for issues by clicking the star for an issue in the tracker. For more information, see Subscribing to an Issue.