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

Build apps for Cars

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Build apps for Cars

Avatar for Keishin Yokomaku

Keishin Yokomaku

July 08, 2023

More Decks by Keishin Yokomaku

Other Decks in Technology

Transcript

  1. Build apps for Cars About me ▸ Keishin Yokomaku -

    @KeithYokoma ▸ GitHub / Twitter / Stack Over fl ow ▸ Giftmall, Inc. / Android App Engineer DroidKaigi.collect { #5@Nagoya }
  2. Build apps for Cars Android Auto / Automotive OS ▸

    Android Auto ▸ ंࡌγεςϜ (Head Unit) ʹઐ༻ͷ UI Λදࣔ͢ΔϞόΠϧ୺຤ͷ࢓૊Έ ▸ ंࡌγεςϜͱϞόΠϧ୺຤͕ Android Auto ʹରԠ͍ͯ͠Δඞཁ͕͋Δ ▸ Android Automotive OS ▸ Android ϕʔεͷΠϯϑΥςΠϯϝϯτγεςϜ༻ͷ OS ▸ ं͕ Android Automotive OS Λ౥ࡌ͍ͯ͠Δඞཁ͕͋Δ DroidKaigi.collect { #5@Nagoya }
  3. ▸ ϞόΠϧ୺຤ʹ౥ࡌ͞Ε͍ͯΔ Android Auto ͕த৺ (Host) ▸ Android Auto ͕ରԠͨ͠ΞϓϦͱ΍ΓऔΓ

    (IPC) ͢Δ ▸ Android Auto ͕ंࡌγεςϜͷ UI Λ੍ޚ Build apps for Cars Android Auto DroidKaigi.collect { #5@Nagoya } Icons: https://icons8.com/icon/1oqfhfFvXU8c/starbucks
  4. Build apps for Cars Android Automotive OS DroidKaigi.collect { #5@Nagoya

    } ▸ ंʹ౥ࡌ͞Ε͍ͯΔ Android Automotive OS ͕த৺ (Host) ▸ Android Automotive OS ͸ Android ͷѥछ ▸ Google PlayStore ͔ΒΞϓϦͷΠϯετʔϧ͕Մೳ Icons: https://icons8.com/icon/1oqfhfFvXU8c/starbucks
  5. Build apps for Cars Features DroidKaigi.collect { #5@Nagoya } ▸

    Turn by turn φϏήʔγϣϯ / POI ▸ ࠶ੜίϯτϩʔϧ ▸ ϝοηʔδϯά
  6. Build apps for Cars Features DroidKaigi.collect { #5@Nagoya } ▸

    Turn by turn φϏήʔγϣϯ ▸ ໨త஍ͷݕࡧͱԻ੠Ҋ಺ ▸ ަ௨ঢ়گͷදࣔ ▸ Point of Interest (POI) ▸ ߦ͖ઌΛφϏήʔγϣϯΞϓϦʹఏڙ͢Δ Icons: https://icons8.com/icon/1oqfhfFvXU8c/starbucks
  7. Build apps for Cars Features DroidKaigi.collect { #5@Nagoya } ▸

    ࠶ੜίϯτϩʔϧ ▸ Ի੠ɾಈըϝσΟΞͷ࠶ੜ ▸ ϓϨΠϦετͷมߋ
  8. Build apps for Cars Features DroidKaigi.collect { #5@Nagoya } ▸

    ϝοηʔδϯά ▸ ৽ணϝοηʔδͷԻ੠ಡΈ্͛ ▸ Ի੠ೖྗʹΑΔฦ৴
  9. Build apps for Cars AndroidX Libraries DroidKaigi.collect { #5@Nagoya }

    ▸ φϏήʔγϣϯ / POI ▸ Car App Library ▸ ࠶ੜίϯτϩʔϧ ▸ AndroidX Media3 ▸ ϝοηʔδϯά ▸ AnroidX Core
  10. Build apps for Cars Media Playback with AndroidX Media3 DroidKaigi.collect

    { #5@Nagoya } ▸ Android Auto / Automotive OS ରԠͰ࢖͏ओཁͳΫϥε ▸ MediaBrowserServiceCompat ▸ MediaSessionCompat ▸ MediaControllerCompat
  11. Build apps for Cars Media Playback with AndroidX Media3 DroidKaigi.collect

    { #5@Nagoya } ▸ MediaBrowserServiceCompat ▸ ΞϓϦ಺ʹ͋Δ࠶ੜՄೳͳϝσΟΞίϯςϯπͷ৘ใΛ 
 Android Auto / Automotive OS ʹఏڙ͢Δ
  12. Build apps for Cars Media Playback with AndroidX Media3 DroidKaigi.collect

    { #5@Nagoya } ▸ MediaBrowserServiceCompat ▸ Android Auto / Automotive OS ͕ࣗ෼ͷΞϓϦͷ 
 MediaBrowserService ʹόΠϯυ͠ʹ͘Δ Icons: https://icons8.com/icon/0dttLEPe98bJ/ fi at-500 onGetRoot ίϯςϯπ֊૚࠷্Ґͷ৘ใ onLoadChildren ࢠ֊૚ͷίϯςϯπ৘ใ MediaBrowserService MediaBrowser
  13. Build apps for Cars Media Playback with AndroidX Media3 DroidKaigi.collect

    { #5@Nagoya } ▸ MediaSessionCompmat ▸ ϝσΟΞίϯςϯπͷ࠶ੜঢ়گΛఏڙ͢Δ ▸ MediaBrowserService ͕ಈ͖࢝ΊͨΒ͸͡ΊʹॳظԽ͢Δ Icons: https://icons8.com/icon/0dttLEPe98bJ/ fi at-500 ίϯςϯπ֊૚࠷্Ґͷ৘ใ MediaBrowserService MediaBrowser onCreate: MediaSession ͷॳظԽ bindService connected onGetRoot
  14. Build apps for Cars Media Playback with AndroidX Media3 DroidKaigi.collect

    { #5@Nagoya } ▸ MediaControllerCompat ▸ ϝσΟΞίϯςϯπͷ࠶ੜঢ়گΛૢ࡞͢Δ ▸ Android Auto / Automotive OS ͷ UI ૢ࡞͕ى఺ Icons: https://icons8.com/icon/0dttLEPe98bJ/ fi at-500 ίϯςϯπ֊૚࠷্Ґͷ৘ใ MediaBrowserService MediaBrowser onCreate: MediaSession ͷॳظԽ bindService connected onGetRoot MediaController ͷॳظԽ MediaController.play ࠶ੜΛ։࢝ ࠶ੜΛ։࢝
  15. Build apps for Cars Media Playback with AndroidX Media3 DroidKaigi.collect

    { #5@Nagoya } ▸ Caveats ▸ MediaBrowser ͸୭Ͱ΋࣮૷Ͱ͖Δ ▸ MediaBrowserService ͸ bind ͖ͯͨ͠ΞϓϦͷݕূΛ͢΂͖ Icons: https://icons8.com/icon/EQ0QKBwiUSDM/pennywise ۭͷϦετΛฦ͢ MediaBrowserService MediaBrowser onGetRoot ύοέʔδΛݕূ: ෆڐՄ
  16. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } ▸ Android Auto / Automotive OS ͕ϝοηʔδΛಡΈ্͛Δ࢓૊Έ Noti fi cationManager Noti fi cationListenerService app Icons: https://icons8.com/icon/0dttLEPe98bJ/ fi at-500 / https://icons8.com/icon/wT8BPIITf9UK/android-phone notify(): Noti fi cation Λදࣔ ৽͍͠ Noti fi cation Λ௨஌ Noti fi cation ΛಡΈऔΔ ϝοηʔδΛಡΈ্͛Δ طಡʹ͢Δ ฦ৴͢Δ Ի੠ೖྗΛड͚෇͚Δ
  17. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } ▸ ࣍ʹ্͛ΔཁٻΛຬͨ͢௨஌ΛදࣔՄೳ ▸ Noti fi cation.MessagingStyle Λ࢖͍ͬͯΔ ▸ CATEGORY_MESSAGE ΧςΰϦʹଐ͢Δ ▸ ະಡϝοηʔδͷΈΛอ࣋͢Δ ▸ طಡʹ͢ΔΞΫγϣϯϘλϯ͕͋Δ ▸ SEMANTIC_ACTION_MARK_AS_READ ▸ ΞΫγϣϯϘλϯͷΠϕϯτॲཧʹ௥Ճͷ UI ͕ଘࡏ͠ͳ͍
  18. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } ▸ ฦ৴ػೳΛ࢖͏৔߹͸௥ՃͰ࣍ͷཁٻ΋ຬͨ͢ ▸ ฦ৴ઐ༻ͷΞΫγϣϯϘλϯΛઃఆ͢Δ ▸ SEMANTIC_ACTION_REPLY ▸ ΞΫγϣϯϘλϯͷΠϕϯτॲཧʹ௥Ճͷ UI ͕ଘࡏ͠ͳ͍ ▸ RemoteInput ΦϒδΣΫτΛ͍࣋ͬͯΔ
  19. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } val sender = Person.Builder() .setName("John Doe") .build() val style = NotificationCompat.MessagingStyle(sender) .addMessage("hello!", System.currentTimeMillis(), sender) val markAsReadIntent = PendingIntent.getBroadcast(/* */) val markAsReadAction = NotificationCompat.Action.Builder(R.drawable.ic_mark_as_read, "Mark as read", markAsReadIntent) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ) .build() val replyPendingIntent = PendingIntent.getBroadcast(/* */) val replyInput = RemoteInput.Builder("input") .build() val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, "Reply", replyPendingIntent) .addRemoteInput(replyInput) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY) .build() val notification = NotificationCompat.Builder(context, "notification_channel") .setContentTitle("title") .setContentText("message") .setCategory(NotificationCompat.CATEGORY_MESSAGE) .addAction(markAsReadAction) .addAction(replyAction) .setStyle(style) .build()
  20. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } val sender = Person.Builder() .setName("John Doe") .build() val style = NotificationCompat.MessagingStyle(sender) .addMessage("hello!", System.currentTimeMillis(), sender) val markAsReadIntent = PendingIntent.getBroadcast(/* */) val markAsReadAction = NotificationCompat.Action.Builder(R.drawable.ic_mark_as_read, "Mark as read", markAsReadIntent) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ) .build() val replyPendingIntent = PendingIntent.getBroadcast(/* */) val replyInput = RemoteInput.Builder("input") .build() val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, "Reply", replyPendingIntent) .addRemoteInput(replyInput) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY) .build() val notification = NotificationCompat.Builder(context, "notification_channel") .setContentTitle("title") .setContentText("message") .setCategory(NotificationCompat.CATEGORY_MESSAGE) .addAction(markAsReadAction) .addAction(replyAction) .setStyle(style) .build()
  21. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } val sender = Person.Builder() .setName("John Doe") .build() val style = NotificationCompat.MessagingStyle(sender) .addMessage("hello!", System.currentTimeMillis(), sender) val markAsReadIntent = PendingIntent.getBroadcast(/* */) val markAsReadAction = NotificationCompat.Action.Builder(R.drawable.ic_mark_as_read, "Mark as read", markAsReadIntent) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ) .build() val replyPendingIntent = PendingIntent.getBroadcast(/* */) val replyInput = RemoteInput.Builder("input") .build() val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, "Reply", replyPendingIntent) .addRemoteInput(replyInput) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY) .build() val notification = NotificationCompat.Builder(context, "notification_channel") .setContentTitle("title") .setContentText("message") .setCategory(NotificationCompat.CATEGORY_MESSAGE) .addAction(markAsReadAction) .addAction(replyAction) .setStyle(style) .build()
  22. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } val sender = Person.Builder() .setName("John Doe") .build() val style = NotificationCompat.MessagingStyle(sender) .addMessage("hello!", System.currentTimeMillis(), sender) val markAsReadIntent = PendingIntent.getBroadcast(/* */) val markAsReadAction = NotificationCompat.Action.Builder(R.drawable.ic_mark_as_read, "Mark as read", markAsReadIntent) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ) .build() val replyPendingIntent = PendingIntent.getBroadcast(/* */) val replyInput = RemoteInput.Builder("input") .build() val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, "Reply", replyPendingIntent) .addRemoteInput(replyInput) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY) .build() val notification = NotificationCompat.Builder(context, "notification_channel") .setContentTitle("title") .setContentText("message") .setCategory(NotificationCompat.CATEGORY_MESSAGE) .addAction(markAsReadAction) .addAction(replyAction) .setStyle(style) .build()
  23. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } ▸ CarExtender ▸ Android Auto / Automotive OS ޲͚ʹ௨஌Λ֦ு͢ΔͨΊͷศརΫϥε ▸ ௨஌ͷࡉ͔͍ઃఆΛ೚͍ͤͨͱ͖͸ CarExtender Λ࢖͏
  24. Build apps for Cars Messaging with AndroidX Core DroidKaigi.collect {

    #5@Nagoya } ▸ Caveats ▸ Noti fi cationListenerService ͸୭Ͱ΋࣮૷Մೳ ▸ MediaBrowserService ͷΑ͏ʹύοέʔδͷݕূ͸ෆՄ ▸ ௨ৗͷ Permission ͱ͸ผͷೝՄͷ࢓૊Έ͕༻ҙ͞Ε͍ͯΔ ▸ ref: https://www.jssec.org/dl/android_securecoding.pdf ▸ ௨஌ʹ͓͚ΔϓϥΠόγʔ؅ཧͷϦϑΝϨϯε
  25. Build apps for Cars ৄղ Android Auto DroidKaigi.collect { #5@Nagoya

    } ▸ https://www.youtube.com/watch?v=0ffNY26f-q4 ▸ DroidKaigi 2018 ▸ ࠶ੜίϯτϩʔϧ΍ϝοηʔδϯάʹ͍ͭͯղઆ
  26. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ Android Auto / Automotive OS ޲͚ͷػೳ։ൃϥΠϒϥϦ ▸ ݱࡏ͸φϏήʔγϣϯͱ POI ޲͚ͷػೳΛ࣮૷͢ΔͨΊͷ API Λఆٛ ▸ UI Λߏங͢ΔͨΊͷπʔϧΩοτ΋ఏڙ ▸ ςϯϓϨʔτϕʔεͷ UI ▸ YouTube: https://www.youtube.com/watch?v=watUEk6_i-4 ▸ Codelab: https://developer.android.com/codelabs/car-app-library- fundamentals
  27. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ Car App Library ͰఏڙՄೳͳػೳ ▸ φϏήʔγϣϯ ▸ POI ▸ IOT (experimental)
  28. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ Android Auto / Automotive OS ޲͚ΞϓϦͷ API Ϩϕϧ ▸ Android OS ͷόʔδϣϯͱ͸ผͷ API Ϩϕϧఆ͕ٛଘࡏ͢Δ ▸ API ϨϕϧʹΑͬͯ Car App Library Ͱఏڙ͞ΕΔػೳʹ͕ࠩ͋ΔͨΊ
  29. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } <manifest> <application> <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" /> </application> </manifest>
  30. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ ΞϓϦ͕࣋ͭ CarAppService Λܦ༝ͯ͠ Android Auto / Automotive OS ͱ௨৴ ▸ CarAppService Ͱ Session Λੜ੒͠ɺSession ʹඥͮ͘ Screen Λ࡞Δ Android Auto / Automotive OS CarAppService bindService Session ύοέʔδΛݕূ Session ͔Βը໘Λߏங
  31. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ ंʹ͸ෳ਺ͷσΟεϓϨΠΛ౥ࡌՄೳ ▸ σΟεϓϨΠ͝ͱݸผʹ CarAppService ʹ bind ͠ʹ͘Δ Android Auto / Automotive OS 
 Dispay 1 CarAppService bindService Android Auto / Automotive OS 
 Dispay 2 bindService
  32. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ ंʹ͸ෳ਺ͷσΟεϓϨΠΛ౥ࡌՄೳ ▸ σΟεϓϨΠ͝ͱݸผʹ Session Λͭ͘Δ Android Auto / Automotive OS 
 Dispay 1 CarAppService Session Android Auto / Automotive OS 
 Dispay 2 Session
  33. Build apps for Cars CarAppService DroidKaigi.collect { #5@Nagoya } class

    MyCarAppService : CarAppService() { override fun createHostValidator(): HostValidator { return HostValidator.ALLOW_ALL_HOSTS_VALIDATOR } override fun onCreateSession(): Session { return MyCarAppSession() } }
  34. Build apps for Cars Session Implementation DroidKaigi.collect { #5@Nagoya }

    class MyCarAppSession : Session() { override fun onCreateScreen(intent: Intent): Screen { return MyCarAppScreen(carCotnext) } }
  35. Build apps for Cars Screen implementation DroidKaigi.collect { #5@Nagoya }

    class MyCarAppScreen( 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() } }
  36. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ ༷ʑͳςϯϓϨʔτ͕ϥΠϒϥϦ಺ʹ͋Δ ▸ Google Maps Λදࣔ͢ΔςϯϓϨʔτ ▸ ೝূը໘Λදࣔ͢ΔςϯϓϨʔτ ▸ etc…
  37. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } ▸ Automotive OS ޲͚ʹ͸ઐ༻ͷରԠ͕ඞཁ ▸ app Ϟδϡʔϧͱ͸ผʹ automotive ༻ͷϞδϡʔϧ͕ඞཁ ▸ app ϞδϡʔϧΛ run ͢Δͱී௨ͷΞϓϦ͕ͦͷ·· deploy ͞Εͯ͠·͏ ▸ automotive ༻ͷϞδϡʔϧͰઐ༻ͷ apk Λు͖ग़͢ ▸ uses-feature Ͱ Automotive OS ޲͚ͷ΋ͷΛ required ʹ͢Δ ▸ automotive ༻ͷ Activity Λ࢖͏
  38. Build apps for Cars Car App Library DroidKaigi.collect { #5@Nagoya

    } <manifest> <uses-feature android:name="android.hardware.type.automotive" android:required="true" /> <uses-feature android:name="android.software.car.templates_host" android:required="true" /> <application> <activity android:name="androidx.car.app.activity.CarAppActivity" android:exported="true" android:launchMode="singleTask" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="distractionOptimized" android:value="true" /> </activity> <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" /> </application> </manifest>
  39. Build apps for Cars Emulators: Android Auto ▸ Android Auto

    Desktop Head Unit (DHU) Emulator ▸ Android Virtual Device (AVD) Ͱ͸ͳ͍͜ͱʹؾΛ͚ͭΔ ▸ ࣍ͷίϚϯυͰ DHU Λىಈ͢Δ ▸ PC ʹ USB Ͱܨ͍ͩ୺຤Λ࢖͏৔߹ DroidKaigi.collect { #5@Nagoya } $SDK_LOCATION/extras/google/auto/desktop-head-unit $SDK_LOCATION/extras/google/auto/desktop-head-unit -u
  40. Build apps for Cars Emulators: Android Automotive OS ▸ ઐ༻

    AVD ͕͋Δ ▸ Play Store ෇ଐͷΤϛϡϨʔλΛ࢖͏ DroidKaigi.collect { #5@Nagoya }
  41. Build apps for Cars Emulators: Android Automotive OS ▸ Google

    Assistant / Google Maps ͳͲϓϦΠϯετʔϧࡁΈ ▸ ηϯαʔ৘ใ (ं଎΍ΪΞ౳) ΋ΤϛϡϨʔγϣϯͰ͖Δ ▸ ηϯαʔ৘ใΛ·ͱΊͯ import ͯ͠ϦϓϨʔ΋Մ ▸ λονૢ࡞ / ෺ཧϘλϯૢ࡞྆ํରԠ DroidKaigi.collect { #5@Nagoya }
  42. Build apps for Cars Emulators: Android Automotive OS ▸ Caveats

    ▸ AndroidStudio ͷ Tool Window ಺Ͱ͸ಈ͔ͳ͍ ▸ ىಈ͸Ͱ͖Δ͕ද͕ࣔͰ͖ͳ͍… ▸ ඞͣ Standalone Ͱಈ͔͢͜ͱ DroidKaigi.collect { #5@Nagoya }
  43. Build apps for Cars Emulators: Android Automotive OS ▸ ࣗಈंϝʔΧʔ͕࡞͍ͬͯΔ

    system image ΋͋Δ ▸ GM ▸ Honda ▸ Polestar ▸ Volvo DroidKaigi.collect { #5@Nagoya }
  44. Build apps for Cars Emulators: Android Automotive OS ▸ Caveats

    ▸ x86 system images ͔͠ͳ͍৔߹ Apple Silicon Ͱಈ͔ͳ͍͜ͱ͕͋Δ DroidKaigi.collect { #5@Nagoya }
  45. Build apps for Cars Wrap up DroidKaigi.collect { #5@Nagoya }

    ▸ Android Auto / Automotive OS ʹରԠ͢Δ࢓૊Έ ▸ AndroidX Media3 ▸ AndroidX Core ▸ Car App Library ▸ ಉ͡ϥΠϒϥϦͰ Android Auto / Automotive OS ͲͪΒʹ΋ରԠՄೳ ▸ Ұ෦ Automotive OS ઐ༻ͷରԠ͕͋Δ