Nowadays, most car stereos come equipped with screens that support Android OS, allowing apps to integrate with the car’s infotainment system. This enhances convenience by enabling users to interact with apps without needing to look at their phones while driving.
Some apps offer entertainment features like music streaming (Spotify, YouTube Music), while others provide utilities such as navigation (Google Maps), locating charging stations, parking apps, and messaging services like WhatsApp or Telegram.
As a developer, if you believe your app can be useful for users while driving or riding, you should consider adding support for Android Auto or Apple CarPlay to enhance the in-car experience.
Android Automotive is a full-fledged operating system that runs directly on the car’s infotainment system. In this setup, the car functions as an Android device itself, allowing apps to run natively on the car without needing a connected smartphone. Automotive apps can interact more deeply with the vehicle’s hardware and provide enhanced functionality (e.g., navigation, media, vehicle controls).
Android Auto is a platform that mirrors or projects apps from a connected Android smartphone onto the car’s infotainment system. Unlike Automotive OS, it uses the car’s existing operating system but adds the ability to display and control apps directly from the phone. This setup allows users to access supported apps (navigation, music, messaging, etc.) while driving through the infotainment display, provided the phone and car system support Android Auto.
So, Android Auto simplifies smartphone connectivity for accessing key apps while driving, whereas Android Automotive OS offers a comprehensive standalone operating system integrated directly into the vehicle. Understanding these differences can help you choose the right platform to enhance your driving experience.
Android Automotive OS is a full operating system that runs directly on the car’s infotainment system. It does not require a smartphone connection to operate and can run apps natively like any Android device.
Android Auto, on the other hand, relies on a connected Android phone. It mirrors or projects apps from the phone onto the car’s infotainment screen, requiring a supported device to run.
Android Automotive OS typically includes built-in network connectivity, such as SIM card support, which allows it to stay connected to the internet without needing a smartphone.
Android Auto depends entirely on the smartphone’s network connection for internet access, so a phone must be connected for app functionality.
Android Automotive OS is highly customizable, allowing automakers and developers to build apps that control vehicle-specific features, such as air conditioning, radio, and even car settings like drive modes. It provides deep integration with the vehicle’s hardware.
Android Auto is not customizable for specific vehicle controls, as it functions primarily as an app projection system. However, recent updates have introduced some limited hardware integration capabilities, but these require collaboration with car manufacturers.
Android Automotive OS supports a broader range of apps, including those designed specifically for automotive functions. It has its own app store, where users can download and install supported apps directly onto the infotainment system.
Android Auto only supports a specific set of apps that are optimized for driving, like navigation, music, and messaging, which are accessed via the connected phone.
Android Automotive OS can also support phone mirroring via Bluetooth, Wi-Fi, or USB cable, similar to Android Auto. This allows features like making calls or reading SMS messages through the car’s system. Additionally, Android Automotive OS can run apps from the connected device, just like Android Auto. However, Automotive can run its own native apps independently as well.
Due to the specific safety and usability considerations for in-car environments, both Android Auto and Android Automotive OS support only certain types of apps. These apps are designed to minimize distractions and ensure a safe driving experience.
Type | Description | Automotive | Android auto | While driving | While Parking |
Media – audio | Media apps let users browse and play music, radio, audiobooks, and other audio content in the car. See Build media apps for cars for more information. Android Service:-MediaBrowserService and MediaSession | YES | YES | YES | YES |
Navigation | Navigation apps, including providers of driver and delivery services, help users get where they want to go by providing turn-by-turn directions. | YES | YES | YES | YES |
Messaging | Messaging apps let users receive incoming notifications, read messages aloud using text-to-speech, and send replies using voice input in the car. | NO | YES | YES | YES |
IOT APPS | IOT apps let users take relevant actions on connected devices from within the car. Examples include controlling the state of certain devices, such as opening a garage door, flipping home light switches, or enabling home security. | YES | YES | YES | YES |
Video | Video apps let users view streaming videos while the car is parked. | YES | YES | NO | YES |
Games | Game apps let users play games while the car is parked. | YES | YES | NO | YES |
Browsers | Browser apps let users access web pages while the car is parked. | YES | YES | NO | YES |
The Tab template acts as a container for other templates listed below, providing tabs across the top.(best for music app, for example Spotify is using this). Embedded template, which can be any of the following types(container templets):
- List
- Grid
- Search
- Pane
- Message
- Navigation
The List template presents information items in a list layout.
- This template can be embedded in the Tab template to provide tabbed navigation.
- This template can be included in the Map + Content template to provide a list on a map.
- Floating action button and subtitle, header can be displayed.
- We can expand it while it vehicle is parked and show less content while driving.
As name suggest we it provides grid layout, This template is useful when users rely primarily on images to make their selections.
- This template can be embedded in the Tab template to provide tabbed navigation.
- This template can be included in the Map + Content template to provide a grid on a map.
The Sign-in template presents options for signing in to the app while parked. You can choose from 4 possible sign-in methods
- Provider sign-in method: This method lets users sign in using a provider, with no input required
- Username/password method: This method lets users enter authentication information in a single, mandatory form field. This field can be used to enter a username or password.
- QR code method: This method displays a mandatory PIN code (up to 12 characters in length) provided by the app and instructions for where the user should enter it.
- PIN method: This method displays a mandatory PIN code (up to 12 characters in length) provided by the app and instructions for where the user should enter it.
Messages present a brief message and optional relevant actions.
- This template can be embedded in the Tab template to provide tabbed navigation.
- This template can be included in the Map + Content template to display a message on a map.
- Action buttons can be added as per requirements.
Icon, loading spinner and image can be added as well.
The Search template presents a search bar, keyboard, and results list for users to perform searches, such as searching for destinations.
- During drives, users can’t access the keyboard, but they can use the voice assistant to interact with search and see previous results.
- Search bar header with optional action strip Keyboard (when parked), which apps can collapse or expand
- List rows for search results (within limits*)
The Pane template presents detailed information and prominent actions.
- For easy scanning, actions and information rows are limited to 4 each.
- This template is useful for presenting non-editable metadata, such as location and reservation details, and for taking action based on data.
- Up to 2 buttons, where one can be designated as primary (optional)
- Up to 4 non-actionable rows (1 row is mandatory)
The Place List template presents an ordered list of locations (or containers for sublists), overlaid on a map provided by the app library.
- Header (in card) with optional refresh button for users to request a list update (doesn’t add to step count)
- Action strip (optional)
- Base map (full-screen, not drawn by apps)
List rows within limits(The number of list rows allowed to be shown depends on the vehicle. To retrieve the list row limit for a given vehicle, use the)
Markers on the map to show list item on map
The Navigation template presents a base map and optional routing information.
- When a user is driving without text-based turn-by-turn directions, apps can show a full-screen map updated in real time. During active navigation, apps can surface optional cards with maneuvers and surface details, as well as navigation alerts.
- Full-screen base map drawn by app
Routing card (optional) with upcoming maneuvers
Travel estimate card (optional) with estimated time of arrival (ETA), time to destination, and remaining distance (or an alternate information display with custom text and icon options
More details can be checked here:- https://developers.google.com/cars/design/create-apps/apps-for-drivers/templates/overview
Components are commonly used ui elements which can be used with multiple templates.
Action strip are basically buttons in ui. In Action strip up to 2 buttons are allowed expect map templates with map where up to 4 buttons are allowed.
Allows to add buttons map screen to control map related features like zoom,pan ,recenter etc. up to 4 buttons are allowed.
Buttons can we add inside the template like row or message. There are 3 type of buttons can be use.
- Icon only
- Label only
- Icon + label
We can supply color for text background for buttons to match our app’s theme. But OEM can control to show custom colors or not.
We can create Primary button or Timer buttons. Timers buttons are buttons which shows. Where if user does not complete action in given timeframe it will be considered as clicked and action will be performed which is assigned with button click. For example accept will be performed after time out
Floating action buttons place the most important actions on the screen a tap away. Which is similar to what we see in android native app’s FAB. It will be as below
- Icon with no label
- Background color
- No text is supported in FAB
- Fabs are supported in Grid and List templates.
- Each grid or list templates can have maximum 2 Fabs.
Headers help drivers understand which app and what part of the app they’re using.
- Icon or image (optional), such as app icon
- Text (one line only – longer text is truncated), typically the title of the screen
- Back button (optional)
- This is similar to appbar in android native app.
To provide android auto support add 2 library to gradle from google.
- Implementation “androidx.car.app:app:1.4.0” (check version compatibility and latest versions)
- Implementation “androidx.car.app:app-projected:1.4.0”
Once you add these libraries, we need to modify android manifest files as below so android auto can detect the app that it supports android auto and also it can detect type of app.
<application>
…
<meta-data android:name=”com.google.android.gms.car.application”
android:resource=”@xml/automotive_app_desc”/>
…
</application>
<application>
…
<meta-data
android:name=”com.google.android.gms.car.application”
android:resource=”@xml/automotive_app_desc”/>
…
</application>
<uses-permission android:name=”androidx.car.app.MAP_TEMPLATES”/>
<uses-feature android:name=”android.hardware.type.automotive” android:required=”true” />
<uses-feature android:name=”android.software.car.templates_host” android:required=”true” />
<queries>
<package android:name=”com.google.android.apps.maps” /> </queries>
<application>
…
<meta-data
android:name=”com.google.android.gms.car.application”
android:resource=”@xml/automotive_app_desc”/>
…
</application>
We have mentioned “@xml/automotive_app_desc” file as resource for that we just create a xml file in resource->xml directory named “automotive_app_desc.xml” with below content.
<?xml version=”1.0″ encoding=”utf-8″?>
<automotiveApp>
<uses name=”template”/>
<uses name=”notification” /> (for notification permission)
<uses name=”sms” /> (for sms app) </automotiveApp>
More we can learn about code here:- https://developer.android.com/codelabs/car-app-library-fundamentals#0
1. Add required libraries as mentioned above to gradle script(androidx.car.app:app)
2. Update manifest file as mentioned above.
3. Create a service which extends CarAppService which will be responsible for handling the app projection to car and entry point of app for android auto.
class PlacesCarAppService : CarAppService() {
override fun createHostValidator(): HostValidator {
return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
}
override fun onCreateSession(): Session {
// PlacesSession will be an unresolved reference until the next step return PlacesSession()
}
}
4. Declare created service to manifest.
<?xml version=”1.0″ encoding=”utf-8″?> <manifest xmlns:android=”http://schemas.android.com/apk/res/android”> <!– This AndroidManifest.xml will contain all of the elements that should be shared across the Android Auto and Automotive OS versions of the app, such as the CarAppService <service> element –> <application>
<service android:name=”{yourpackage}.PlacesCarAppService”
android:exported=”true”>
<intent-filter>
<action android:name=”androidx.car.app.CarAppService” />
<category android:name=”androidx.car.app.category.POI” />
</intent-filter>
</service>
</application>
</manifest>
With this code we declare that our app has service to support android auto/automotive and category is POI.
5. Now create a session class which we declared in service class.
class PlacesSession : Session() {
override fun onCreateScreen(intent: Intent): Screen {
// MainScreen will be an unresolved reference until the next step return MainScreen(carContext)
}
}
Note:- here we care using carContext is similar to appContext but it reference to car . It will be available only till device is connected to car and app is running on car.
6. Now lates create Main/first screen for the car app called MainScreen.
class MainScreen(carContext: CarContext) : Screen(carContext) {
override fun onGetTemplate(): Template {
val placesRepository = PlacesRepository()
val itemListBuilder = ItemList.Builder() .setNoItemsMessage(“No places to show”)
placesRepository.getPlaces()
.forEach {
itemListBuilder.addItem( Row.Builder() .setTitle(it.name)
// Each item in the list *must* have a DistanceSpan applied to either the title
// or one of the its lines of text (to help drivers make decisions)
.addText(SpannableString(” “).apply {
setSpan( DistanceSpan.create( Distance.create(Math.random() * 100, Distance.UNIT_KILOMETERS) ), 0, 1,
Spannable.SPAN_INCLUSIVE_INCLUSIVE )
}) .setOnClickListener {
screenManager.push(DetailScreen(carContext, it.id)
}
// Setting Metadata is optional, but is required to automatically show the
// item’s location on the provided map
.setMetadata( Metadata.Builder()
.setPlace( Place.Builder(CarLocation.create(it.latitude, it.longitude))
// Using the default PlaceMarker indicates that the host should
// decide how to style the pins it shows on the map/in the list
.setMarker(PlaceMarker.Builder().build()) .build() )
.build()
)
.build() )
} return PlaceListMapTemplate.Builder()
.setTitle(“Places”)
.setItemList(itemListBuilder.build())
.build()
}
}
7. Now we can have to create DetailScreen to display details of selected place by use we already have set seton click listener for item. Here ScreenManger will be responsible for navigating from one screen to other in android auto mode.
class DetailScreen(carContext: CarContext, private val placeId: Int) : Screen(carContext){
private var isFavorite = false
override fun onGetTemplate(): Template {
val place = PlacesRepository().getPlace(placeId)
?: return MessageTemplate.Builder(“Place not found”)
.setHeaderAction(Action.BACK)
.build()
val navigateAction = Action.Builder()
.setTitle(“Navigate”)
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.baseline_navigation_24
)
).build()
)
// Only certain Intent actions are supported by `startCarApp`. Check its documentation
// for all of the details. To open another app that can handle navigating to a location
// you must use the CarContext.ACTION_NAVIGATE action and not Intent.ACTION_VIEW like
// you might on a phone.
.setOnClickListener { carContext.startCarApp(place.toIntent(CarContext.ACTION_NAVIGATE)) }
.build()
val actionStrip = ActionStrip.Builder()
.addAction(
Action.Builder()
.setIcon(
CarIcon.Builder(
IconCompat.createWithResource(
carContext,
R.drawable.baseline_favorite_24
)
).setTint(
if (isFavorite) CarColor.RED else CarColor.createCustom(
Color.LTGRAY,
Color.DKGRAY
)
).build(
)
.setOnClickListener {
isFavorite = !isFavorite
// Request that `onGetTemplate` be called again so that updates to the
// screen’s state can be picked up
invalidate()
}.build()
)
.build()
return PaneTemplate.Builder(
Pane.Builder()
.addAction(navigateAction)
.addRow(
Row.Builder()
.setTitle(“Coordinates”)
.addText(“${place.latitude}, ${place.longitude}”)
.build()
).addRow(
Row.Builder()
.setTitle(“Description”)
.addText(place.description)
.build()
).build()
)
.setTitle(place.name)
.setHeaderAction(Action.BACK)
.setActionStrip(actionStrip)
.build()
}
}
- In above class DetailScreen, we can observe the invalidate() is called when favorite is clicked on action strip. Invalidate function use for refreshing screen with latest data. Like we use notifyDataSetChanged for ArrayAdapters class.
Note: Here we can use any supported templets list which we mentioned above for example here we have used PaneTemplate with Row for first screen of the app for car. You can use simple ListTemplete or Grid Templete or any other of your choice.
The Desktop Head Unit (DHU) lets your development machine emulate an Android Auto head unit so that you can run and test Android Auto apps. The DHU runs on Windows, macOS, and Linux systems.
- Detailed instruction can be found here , it is based on you development operation system.
CarConnection class is useful to detect the device is connected to car so based on that we can apply ui logic to make use user don’t have much distraction while it is connected.
val carConnectionType by CarConnection(this).type.observeAsState(initial = -1)
fun ProjectionState(carConnectionType: Int) {
val text = when (carConnectionType) {
CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> “Not projecting”
CarConnection.CONNECTION_TYPE_NATIVE -> “Running on Android Automotive OS”
CarConnection.CONNECTION_TYPE_PROJECTION -> “Projecting”
else -> “Unknown connection type”
}
}
More examples can be found on official android websites: https://developer.android.com/training/cars