Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Going on a road trip with Android Auto

cmota
April 27, 2023

Going on a road trip with Android Auto

Android is truly everywhere. It's running on the phone, watch, TV, car, and there are even some fridges and toasters that want to be part of the family. While they're still under development, Android Auto is starting to gain a lot of adoption.

In this talk, we're going to travel around the road of Android Auto, see its use cases and go through its functionalities, so you can later implement them on your app. All of this without moving your desk to be inside a car.

Jump in, it's going to be an amazing journey.

cmota

April 27, 2023
Tweet

More Decks by cmota

Other Decks in Technology

Transcript

  1. @cafonsomota 👨💻 Android GDE 🧙 Android/ KMP cra ft sman

    (and advocate) ✍ Author @kodecodev 🗺 Loves travel, photography and running 🇫🇷 Je suis ravie d'être ici à Android Makers
  2. @cafonsomota By avg. people spend ~600 per year on cars

    hours Source: bristolstreet.co.uk/news/drivers-in-england-spend-25-days-per-year-in-their-cars
  3. @cafonsomota By avg. people spend 25 days per year on

    cars Source: bristolstreet.co.uk/news/drivers-in-england-spend-25-days-per-year-in-their-cars
  4. Dance Think about life Listen to music Nothing Listen podcasts

    Endless radio advertisements Making phone calls Record a podcast Look for radars Listen to audio books Football matches Talk to the person in the car Sleep Switch between radio stations Plan my day Nothing Sing Eat
  5. Source: Distracted driving in Europe by Diana Sure, Head of

    NGO on Responsible Driving in Europe drivers 36% read text/emails while driving
  6. Source: Distracted driving in Europe by Diana Sure, Head of

    NGO on Responsible Driving in Europe 10-30% of road collisions in Europe are due to the use of smartphones while driving
  7. … people have even changed. From using a mobile now

    for texting. What they’re actually doing now is surfing the net. They’re looking at their Instagram portfolio, their Facebook. “ - David Sheahan, Garda National Roads Policing Bureau, Ireland Source: Distracted driving in Europe by Diana Sure, Head of NGO on Responsible Driving in Europe
  8. android for cars The Belfry of … Eiffel Tower Orly

    @cafonsomota Android Auto Android Automotive Assistant Driving Mode
  9. Suppo rt is added via mobile .apk/.aab android for cars

    android auto Projection of your device, optimized for vehicles Requires your sma rt phone to be connected Runs with the same look and feel on all cars The Belfry of … Eiffel Tower Orly
  10. @cafonsomota android for cars android automotive OS (AAOS) Requires a

    separate .apk/.aab OS for cars App is installed into your car Adapted to OEM colors and styling
  11. @cafonsomota android for cars assistant driving mode Requires Google Maps

    Set of features available when driving Voice commands to read/send messages, make calls, etc. Not available on all countries
  12. android for cars @cafonsomota why? Limit user distraction Voice enabled

    commands Quick access to actions More enjoyable (and safe) ride
  13. android auto @cafonsomota why? Empower drivers with your app Easy

    to implement New market that you can reach
  14. car library for android auto and automotive AndroidManifest <meta-data android:name="com.google.android.gms.car.application"

    android:resource="@xml/automotive_app" tools:ignore="MetadataTagInsideApplicationTag" />
  15. car library for android auto and automotive AndroidManifest <?xml version="1.0"

    encoding="utf-8"?> <automotiveApp> <uses name="template" /> </ automotiveApp>
  16. car library for android auto and automotive AndroidManifest <meta-data android:name="androidx.car.app.theme"

    android:resource="@style/Night.Theme.Confetti" tools:ignore="MetadataTagInsideApplicationTag" />
  17. car library for android auto and automotive AndroidManifest <meta-data android:name="androidx.car.app.minCarApiLevel"

    android:value="1" tools:ignore="MetadataTagInsideApplicationTag" /> Latest API: 6
  18. app categories for android auto and automotive @cafonsomota Audio players,

    radio, audiobooks,… Media (audio) Read messages aloud, reply via voice input,… Messaging Provide turn-by-turn directions Navigation Android auto only
  19. app categories for android auto and automotive @cafonsomota Monitor and

    control the state of home devices Internet of Things (IOT) Stream videos while the car is parked Video apps Android Automotive only (for now) Navigate to POI’s, parking, charging,… Point of Interest (POI)
  20. app categories for android auto and automotive AndroidManifest <service android:name=".auto.ConfettiCarAppService"

    android:exported="true"> <intent-filter> <action android:name="androidx.car.app.CarAppService" / > <category android:name="androidx.car.app.category.POI" /> < / intent-filter> </ service>
  21. app categories for android auto and automotive AndroidManifest <service android:name=".auto.ConfettiCarAppService"

    android:exported="true"> <intent-filter> <action android:name="androidx.car.app.CarAppService" / > <category android:name="androidx.car.app.category.POI" /> < / intent-filter> </ service>
  22. app categories for android auto and automotive AndroidManifest <service android:name=".auto.ConfettiCarAppService"

    android:exported="true"> <intent-filter> <action android:name="androidx.car.app.CarAppService" / > <category android:name="androidx.car.app.category.POI" /> < / intent-filter> </ service>
  23. app categories for android auto and automotive AndroidManifest <service android:name=".auto.ConfettiCarAppService"

    android:exported="true"> <intent-filter> <action android:name="androidx.car.app.CarAppService" / > <category android:name="androidx.car.app.category.POI" /> < / intent-filter> </ service> ⚠ POI and IOT needs to be uppercase (otherwise your app will get rejected, trust me 😅)
  24. app categories for android auto and automotive AndroidManifest class ConfettiCarAppService:

    CarAppService() { override fun createHostValidator(): HostValidator { return HostValidator.Builder(applicationContext) .addAllowedHosts(R.array.hosts_allowlist) .build() } override fun onCreateSession(sessionInfo: SessionInfo) { return object : Session() { override fun onCreateScreen(intent: Intent) = ConferencesScreen(carContext) …
  25. app categories for android auto and automotive AndroidManifest class ConfettiCarAppService:

    CarAppService() { override fun createHostValidator(): HostValidator { return HostValidator.Builder(applicationContext) .addAllowedHosts(R.array.hosts_allowlist) .build() } override fun onCreateSession(sessionInfo: SessionInfo) { return object : Session() { override fun onCreateScreen(intent: Intent) = ConferencesScreen(carContext) …
  26. app categories for android auto and automotive AndroidManifest class ConfettiCarAppService:

    CarAppService() { override fun createHostValidator(): HostValidator { return HostValidator.Builder(applicationContext) .addAllowedHosts(R.array.hosts_allowlist) .build() } override fun onCreateSession(sessionInfo: SessionInfo) { return object : Session() { override fun onCreateScreen(intent: Intent) = ConferencesScreen(carContext) …
  27. overview @cafonsomota Designed for driving Strict implementation rules Shows impo

    rt ant information glanceable Discourages distraction car templates
  28. ListTemplate GridTemplate SignInTemplate MessageTemplate LongMessageTemplate SearchTemplate PaneTemplate overview for android

    auto and automotive for POI and IOT apps TabTemplate PlaceListTemplate for navigation apps PlaceListTemplate MapTemplate RoutePreviewTemplate NavigationTemplate car templates ⚠ API level 6 ⚠ Parked only* ⚠ Parked only* * requires user a tt ention/interaction
  29. ListTemplate App name List item one List item two List

    item three List item four @cafonsomota car templates
  30. var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply

    { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota ListTemplate car templates
  31. var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply

    { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota ListTemplate car templates
  32. var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply

    { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota ListTemplate car templates
  33. var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply

    { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota ListTemplate car templates
  34. var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply

    { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota ListTemplate car templates
  35. car templates ListTemplate var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name)

    .build()) return ListTemplate.Builder().apply { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota
  36. Section One Title One Text one Section Two Title two

    Text two Category @cafonsomota car templates ListTemplate with SectionedItemList
  37. var listBuilder =aItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply {a

    setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates ListTemplate with SectionedItemList
  38. var listBuilder =aItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) val listTemplate =

    ListTemplate.Builder() listTemplate.addSectionedList( SectionedItemList.create( listBuilder.build(), startTime)) return listTemplate.apply {a setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota ListTemplate with SectionedItemList car templates
  39. var listBuilder = ItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) val listTemplate

    = ListTemplate.Builder() listTemplate.addSectionedList( SectionedItemList.create( listBuilder.build(), startTime)) return listTemplate.apply { setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates ListTemplate with SectionedItemList
  40. Category Text one Text two Text three Text four Text

    fi ve Text six @cafonsomota car templates GridTemplate
  41. var listBuilder =aItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply {a

    setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates ListTemplate
  42. var listBuilder =aItemList.Builder() listBuilder.addItem( Row.Builder() .setTitle(conference.name) .build()) return ListTemplate.Builder().apply {a

    setTitle("Confetti") setHeaderAction(Action.APP_ICON) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates ListTemplate
  43. var listBuilder = ItemList.Builder() listBuilder.addItem( GridItem.Builder() .setTitle(speaker.name) .setText(speaker.company) .setImage(image).build()) return

    GridTemplate.Builder().apply { setTitle("Speakers") setHeaderAction(Action.BACK) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates GridTemplate
  44. var listBuilder = ItemList.Builder() listBuilder.addItem( GridItem.Builder() .setTitle(speaker.name) .setText(speaker.company) .setImage(image).build()) return

    GridTemplate.Builder().apply { setTitle("Speakers") setHeaderAction(Action.BACK) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates GridTemplate
  45. var listBuilder = ItemList.Builder() listBuilder.addItem( GridItem.Builder() .setTitle(speaker.name) .setText(speaker.company) .setImage(image).build()) return

    GridTemplate.Builder().apply { setTitle("Speakers") setHeaderAction(Action.BACK) setSingleList(listBuilder.build()) }.build() @cafonsomota car templates GridTemplate
  46. app templates restrictions @cafonsomota Some templates have mandatory prope rt

    ies There’s a limit of 5 templates that can be pushed during the fl ow of a task There’s a maximum number of items per template
  47. app templates what if there’s no template for my use

    case? @cafonsomota You can make a request for it on Google’s issue tracker Or…
  48. car templates what if there’s no template for my use

    case? @cafonsomota Draw directly in the su rf ace canvas once it’s available Create and set a Su rf aceCallback You can use NavigationTemplate for this
  49. car templates what if there’s no template for my use

    case? val surfaceCallback = object : SurfaceCallback { override fun onSurfaceAvailable(container: SurfaceContainer) { val canvas: Canvas? = container.surface ?. lockCanvas(null) // Do all calculations canvas ?. drawBitmap(bitmap, width, height, Paint()) container.surface ?. unlockCanvasAndPost(canvas) } }
  50. car templates what if there’s no template for my use

    case? val surfaceCallback = object : SurfaceCallback { override fun onSurfaceAvailable(container: SurfaceContainer) { val canvas: Canvas? = container.surface ?. lockCanvas(null) // Do all calculations canvas ?. drawBitmap(bitmap, width, height, Paint()) container.surface ?. unlockCanvasAndPost(canvas) } }
  51. car templates what if there’s no template for my use

    case? val surfaceCallback = object : SurfaceCallback { override fun onSurfaceAvailable(container: SurfaceContainer) { val canvas: Canvas? = container.surface ?. lockCanvas(null) // Do all calculations canvas ?. drawBitmap(bitmap, width, height, Paint()) container.surface ?. unlockCanvasAndPost(canvas) } }
  52. car templates what if there’s no template for my use

    case? val surfaceCallback = object : SurfaceCallback { override fun onSurfaceAvailable(container: SurfaceContainer) { val canvas: Canvas? = container.surface ?. lockCanvas(null) // Do all calculations canvas ?. drawBitmap(bitmap, width, height, Paint()) container.surface ?. unlockCanvasAndPost(canvas) } }
  53. car templates override fun onGetTemplate(): Template { carContext.getCarService(AppManager :: class.java)

    .setSurfaceCallback(surfaceCallback) return NavigationTemplate.Builder() .setActionStrip(ActionStrip.Builder() .addAction( Action.Builder() .setTitle("Close") .build()) .build()).build() } what if there’s no template for my use case?
  54. car templates override fun onGetTemplate(): Template { carContext.getCarService(AppManager :: class.java)

    .setSurfaceCallback(surfaceCallback) return NavigationTemplate.Builder() .setActionStrip(ActionStrip.Builder() .addAction( Action.Builder() .setTitle("Close") .build()) .build()).build() } what if there’s no template for my use case?
  55. car templates override fun onGetTemplate(): Template { carContext.getCarService(AppManager :: class.java)

    .setSurfaceCallback(surfaceCallback) return NavigationTemplate.Builder() .setActionStrip(ActionStrip.Builder() .addAction( Action.Builder() .setTitle("Close") .build()) .build()).build() } what if there’s no template for my use case?
  56. Your car app is going to be reviewed. You need

    to follow Google’s design guidelines for vehicles. developers.google.com/cars/design
  57. android auto how to run? Desktop Head Unit (DHU) Simulator

    Can install any (debug) app Not connected to the car Needs to connect to the phone The Belfry of … Eiffel Tower Orl @cafonsomota
  58. android auto how to run? Desktop Head Unit (DHU) Car

    Head Unit (DHU) Physical device Requires an app from store Not connected to the car Needs to connect to the phone Simulator Can install any (debug) app Not connected to the car Needs to connect to the phone The Belfry of … Eiffel Tower Orl @cafonsomota
  59. android auto how to run? Desktop Head Unit (DHU) Car

    Head Unit (DHU) Cars with Android Auto Physical device Requires an app from store Connected to the car Needs to connect to the phone Physical device Requires an app from store Not connected to the car Needs to connect to the phone Simulator Can install any (debug) app Not connected to the car Needs to connect to the phone The Belfry of … Eiffel Tower Orl
  60. android auto lessons learned @cafonsomota There’s no suppo rt to

    load ImageVector, for instance. You’ll need to use drawables Templates aren’t Composable You can request it, or try to create your own Some templates might be missing for your use cases You’ll need to handle this, and call invalidate() a ft erwards to refresh the screen There’s no direct solution to fetch an image TabTemplate only exists on CarAppApiLevel 6 (for now) Not all templates are backward po rt able
  61. android auto lessons learned @cafonsomota You’ll need to use keep

    in proguard Minify and R8 removes car app classes Especially the ones under androidx GitHub repo See and run the car samples There are mandatory elements that you need to set and rules to follow Read the documentation
  62. android auto key takeaways @cafonsomota Less is more, only show

    information that can be easily glanced and accessed Simplicity is key Not the other way around Your app needs to adapt to the car Keep touch/key actions to a minimum Voice input actions Keep task fl ows sho r Provide sho rt cuts and show recurrent actions fi rst