1. Sebelum memulai
Dalam codelab ini, Anda akan mempelajari cara membuat aplikasi distraksi dioptimalkan untuk Android Auto dan Android Automotive OS menggunakan Library Aplikasi Android untuk Mobil. Pertama-tama, Anda akan menambahkan dukungan untuk Android Auto, lalu dengan sedikit upaya tambahan, Anda akan membuat varian aplikasi yang dapat dijalankan di Android Automotive OS. Setelah aplikasi dapat dijalankan di kedua platform, Anda akan membuat layar tambahan dan interaktivitas dasar.
Tidak termasuk dalam cakupan
- Panduan tentang cara membuat aplikasi media (audio) untuk Android Auto dan Android Automotive OS. Lihat Membuat aplikasi media untuk mobil guna mengetahui detail tentang cara membuat aplikasi tersebut.
- Panduan tentang cara membuat aplikasi pesan untuk Android Auto. Lihat Membuat aplikasi pesan untuk Android Auto guna mengetahui detail tentang cara membuat aplikasi tersebut.
Yang akan Anda butuhkan
- Pratinjau Android Studio. Emulator Android Automotive OS hanya tersedia melalui Pratinjau Android Studio. Jika belum menginstal Pratinjau Android Studio, Anda tetap dapat memulai codelab dengan rilis stabil saat versi pratinjau didownload.
- Pengalaman dengan Kotlin dasar.
- Pengetahuan dasar tentang Layanan Android.
- Rasakan pengalaman membuat Perangkat Virtual Android dan menjalankannya di Android Emulator.
- Pengetahuan dasar tentang Modularisasi aplikasi Android.
- Pengetahuan dasar tentang Pola desain builder.
Yang akan Anda buat
Android Auto | Android Automotive OS |
Yang akan Anda pelajari
- Cara kerja arsitektur host klien Library Aplikasi Mobil.
- Cara menulis class
CarAppService
,Session
, danScreen
Anda sendiri. - Cara menggunakan kembali implementasi Anda di Android Auto maupun Android Automotive OS.
- Cara menjalankan Android Auto di mesin pengembangan menggunakan Desktop Head Unit.
- Cara menjalankan emulator Android Automotive OS.
2. Memulai persiapan
Mendapatkan kode
- Kode untuk codelab ini dapat ditemukan di direktori
car-app-library-fundamentals
dalam repositori GitHubcar-codelabs
. Untuk membuat clone kode ini, jalankan perintah berikut:
git clone https://github.com/android/car-codelabs.git
- Atau, Anda dapat mendownload repositori sebagai file ZIP:
Membuka project
- Setelah memulai Android Studio, impor project dengan memilih direktori
car-app-library-fundamentals/start
saja. Direktoricar-app-library-fundamentals/end
berisi kode solusi yang dapat Anda rujuk kapan saja jika Anda mengalami kebuntuan atau hanya ingin melihat project lengkap.
Memahami kode
- Setelah membuka project di Android Studio, luangkan waktu untuk memeriksa kode awal.
Perhatikan bahwa kode awal untuk aplikasi dibagi menjadi dua modul, yakni :app
dan :common:data
.
Modul :app
berisi UI dan logika aplikasi seluler, sedangkan modul :common:data
berisi class data dan repositori model Place
yang digunakan untuk membaca model Place
. Agar lebih sederhana, repositori membaca data dari daftar yang di-hardcode, tetapi juga dapat secara mudah membaca data dari database atau server backend di aplikasi sebenarnya.
Modul :app
memiliki dependensi pada modul :common:data
sehingga dapat membaca dan menampilkan daftar model Place
.
3. Mempelajari Library Aplikasi Android untuk Mobil
Library Aplikasi Android untuk Mobil adalah serangkaian library Jetpack yang memungkinkan developer membuat aplikasi untuk kendaraan. Library ini memberikan template framework berisi antarmuka pengguna yang dioptimalkan untuk mengemudi sekaligus memungkinkan adaptasi dengan berbagai konfigurasi hardware yang ada di mobil (misalnya, metode input, ukuran layar, dan rasio aspek). Semua ini akan memudahkan Anda sebagai developer dalam membuat aplikasi yang tentunya akan berperforma baik di berbagai kendaraan yang dilengkapi Android Auto dan Android Automotive OS.
Mempelajari cara kerjanya
Aplikasi yang dibuat menggunakan Library Aplikasi Mobil tidak dijalankan langsung di Android Auto atau Android Automotive OS. Namun, aplikasi ini mengandalkan aplikasi host yang berkomunikasi dengan aplikasi klien dan merender antarmuka pengguna klien untuk aplikasi tersebut. Android Auto sendiri merupakan host dan Google Automotive App Host adalah host yang digunakan di kendaraan Android Automotive OS yang dilengkapi Google. Berikut class kunci Library Aplikasi Mobil yang harus Anda perluas saat membuat aplikasi:
CarAppService
CarAppService
adalah subclass dari class Service
Android dan berfungsi sebagai titik entri bagi aplikasi host untuk berkomunikasi dengan aplikasi klien (seperti aplikasi yang akan Anda buat dalam codelab ini). Tujuan utamanya adalah membuat instance Session
yang akan berinteraksi dengan aplikasi host.
Session
Session
dapat dianggap sebagai instance aplikasi klien yang dijalankan di layar kendaraan. Seperti komponen Android lainnya, class ini memiliki siklus prosesnya sendiri yang dapat digunakan untuk menginisialisasi dan mengakhiri resource yang digunakan selama masa aktif instance Session
. CarAppService
dan Session
memiliki hubungan one-to-many. Misalnya, CarAppService
mungkin saja memiliki dua instance Session
, satu untuk layar utama, dan satu lagi untuk layar cluster aplikasi navigasi yang mendukung layar cluster.
Screen
Instance Screen
berfungsi menghasilkan antarmuka pengguna yang dirender oleh aplikasi host. Antarmuka pengguna ini direpresentasikan oleh class Template
sehingga setiap model memiliki jenis tata letak tertentu, seperti petak atau daftar. Setiap Session
mengelola stack instance Screen
yang menangani alur penggunaan melalui berbagai bagian aplikasi Anda. Sama halnya dengan Session
, Screen
juga memiliki siklus prosesnya sendiri yang dapat Anda gunakan.
Anda akan menulis CarAppService
, Session
, dan Screen
di bagian Menulis CarAppService dalam codelab ini, jadi tidak perlu khawatir jika merasa belum benar-benar memahaminya.
4. Menyiapkan konfigurasi awal
Untuk memulai, siapkan modul yang berisi CarAppService
, lalu deklarasikan dependensinya.
Membuat modul car-app-service
- Setelah memilih modul
:common
di jendela Project, klik kanan dan pilih opsi New > Module. - Dalam wizard modul yang terbuka, pilih template Android Library (agar modul ini dapat digunakan sebagai dependensi oleh modul lainnya) dalam daftar di sebelah kiri, lalu gunakan nilai berikut:
- Nama modul:
:common:car-app-service
- Nama paket:
com.example.places.carappservice
- SDK minimum:
API 23: Android 6.0 (Marshmallow)
Menyiapkan dependensi
- Dalam file
build.gradle
level project, tambahkan deklarasi variabel untuk Library Aplikasi Mobil sebagai berikut. Dengan begitu, Anda dapat secara mudah menggunakan versi yang sama di tiap-tiap modul dalam aplikasi.
build.gradle (Project: Places)
buildscript {
ext {
// All versions can be found at https://developer.android.com/jetpack/androidx/releases/car-app
car_app_library_version = '1.3.0-rc01'
...
}
}
- Selanjutnya, tambahkan dua dependensi ke file
build.gradle
modul:common:car-app-service
.
androidx.car.app:app
. Komponen ini adalah artefak utama dari Library Aplikasi Mobil dan berisi semua class inti yang digunakan saat membuat aplikasi. Library ini terdiri dari tiga artefak lainnya,androidx.car.app:app-projected
untuk fungsi spesifik Android Auto,androidx.car.app:app-automotive
untuk kode fungsi Android Automotive OS, danandroidx.car.app:app-testing
untuk komponen pendukung yang berguna untuk pengujian unit. Nantinya Anda juga akan menggunakanapp-projected
danapp-automotive
dalam codelab ini.:common:data
. Komponen ini adalah modul data yang sama yang digunakan oleh aplikasi seluler yang sudah ada dan memungkinkan penggunaan sumber data yang sama untuk setiap versi pengalaman aplikasi.
build.gradle (Module :common:car-app-service)
dependencies {
...
implementation "androidx.car.app:app:$car_app_library_version"
implementation project(":common:data")
...
}
Dengan perubahan ini, grafik dependensi untuk modul aplikasi akan terlihat seperti berikut:
Setelah dependensinya siap, kini saatnya kita menulis CarAppService
.
5. Menulis CarAppService
- Mulailah dengan membuat file bernama
PlacesCarAppService.kt
di paketcarappservice
dalam modul:common:car-app-service
. - Dalam file ini, buat class bernama
PlacesCarAppService
, yang memperluasCarAppService
.
PlacesCarAppService.kt
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()
}
}
Class abstrak CarAppService
mengimplementasikan metode Service
seperti onBind
dan onUnbind
untuk Anda dan mencegah penggantian lebih lanjut dari metode tersebut guna memastikan interoperabilitas yang sesuai dengan aplikasi host. Anda hanya perlu mengimplementasikan createHostValidator
dan onCreateSession
.
HostValidator
yang Anda tampilkan dari createHostValidator
akan dirujuk saat CarAppService
Anda diikat guna memastikan bahwa host dapat dipercaya, dan pengikatan tersebut akan gagal jika host tidak sesuai dengan parameter yang Anda tetapkan. Untuk tujuan codelab ini (dan pengujian secara umum), sebaiknya gunakan ALLOW_ALL_HOSTS_VALIDATOR
agar dapat dengan mudah memastikan bahwa aplikasi Anda sudah terhubung, tetapi jangan gunakan ini dalam produksi. Lihat dokumentasi terkait createHostValidator
guna mengetahui info selengkapnya tentang cara mengonfigurasi komponen ini untuk aplikasi produksi.
Untuk aplikasi yang sederhana seperti ini, onCreateSession
dapat dengan mudah menampilkan instance Session
. Dalam aplikasi yang lebih kompleks, sebaiknya lakukan inisialisasi terhadap resource jangka panjang seperti metrik dan klien logging yang digunakan selama aplikasi Anda dijalankan di kendaraan.
- Terakhir, Anda harus menambahkan elemen
<service>
yang sesuai denganPlacesCarAppService
dalam fileAndroidManifest.xml
modul:common:car-app-service
untuk memberi tahu keberadaannya pada sistem operasi (dan lebih luas lagi, pada aplikasi lainnya seperti host).
AndroidManifest.xml (:common:car-app-service)
<?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="com.example.places.carappservice.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>
Ada dua hal penting yang harus dicatat di sini:
- Elemen
<action>
memungkinkan aplikasi host (dan peluncur) menemukan aplikasi. - Elemen
<category>
mendeklarasikan kategori aplikasi, yang akan menentukan kriteria kualitas aplikasi yang harus dipenuhi (hal ini akan dibahas lebih lanjut nanti). Nilai lainnya yang mungkin digunakan adalahandroidx.car.app.category.NAVIGATION
danandroidx.car.app.category.IOT
.
Membuat class PlacesSession
- Buat file
PlacesCarAppService.kt
, lalu tambahkan kode berikut:
PlacesCarAppService.kt
class PlacesSession : Session() {
override fun onCreateScreen(intent: Intent): Screen {
// MainScreen will be an unresolved reference until the next step
return MainScreen(carContext)
}
}
Untuk aplikasi sederhana seperti ini, Anda hanya perlu menampilkan layar utama di onCreateScreen
. Namun, karena metode ini memerlukan Intent
sebagai parameter, aplikasi dengan fitur yang lebih lengkap mungkin juga akan membaca datanya dan mengisi data sebelumnya dari layar atau menggunakan logika kondisional lainnya.
Membuat class MainScreen
Selanjutnya, buat paket baru bernama screen.
- Klik kanan paket
com.example.places.carappservice
, lalu pilih New > Package (nama lengkap paketnya adalahcom.example.places.carappservice.screen
). Di sinilah Anda akan meletakkan semua subclassScreen
untuk aplikasi. - Dalam paket
screen
, buat file bernamaMainScreen.kt
untuk meletakkan classMainScreen
, yang akan memperluasScreen
. Untuk sekarang, pesan yang ditampilkannya menggunakanPaneTemplate
mungkin akan bersifat sederhana seperti Hello, world!.
MainScreen.kt
class MainScreen(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()
}
}
6. Menambahkan dukungan untuk Android Auto
Meski kini Anda telah mengimplementasikan semua logika yang diperlukan untuk mengaktifkan dan menjalankan aplikasi, ada dua konfigurasi lainnya yang harus disiapkan sebelum Anda dapat menjalankannya di Android Auto.
Menambahkan dependensi pada modul car-app-service
Dalam file build.gradle
modul :app
, tambahkan komponen berikut:
build.gradle (Modul :app)
dependencies {
...
implementation project(path: ':common:car-app-service')
...
}
Dengan perubahan ini, grafik dependensi untuk modul aplikasi akan terlihat seperti berikut:
Dengan ini, kode yang baru saja Anda tulis dalam modul :common:car-app-service
akan dipaketkan bersama dengan komponen lainnya yang disertakan dalam Library Aplikasi Mobil, seperti aktivitas pemberian izin yang disediakan.
Mendeklarasikan meta-data com.google.android.gms.car.application
- Klik kanan modul
:common:car-app-service
, pilih opsi New > Android Resource File, lalu masukkan nilai berikut:
- Nama file:
automotive_app_desc.xml
- Jenis resource:
XML
- Elemen root:
automotiveApp
- Dalam file tersebut, tambahkan elemen
<uses>
berikut untuk mendeklarasikan bahwa aplikasi Anda menggunakan template yang disediakan oleh Library Aplikasi Mobil.
automotive_app_desc.xml
<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
<uses name="template"/>
</automotiveApp>
- Dalam file
AndroidManifest.xml
modul:app
, tambahkan elemen<meta-data>
berikut, yang merujuk fileautomotive_app_desc.xml
yang baru saja Anda buat.
AndroidManifest.xml (:app)
<application ...>
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
...
</application>
File ini dibaca oleh Android Auto dan memberi tahu kemampuan apa yang didukung aplikasi Anda–dalam kasus ini, file memberi tahu Android Auto bahwa aplikasi menggunakan sistem template Library Aplikasi Mobil. Informasi ini kemudian digunakan untuk menangani perilaku seperti menambahkan aplikasi ke peluncur Android Auto dan membukanya dari notifikasi.
Opsional: Memproses perubahan proyeksi
Terkadang, Anda perlu tahu apakah perangkat pengguna sudah terhubung ke mobil atau tidak. Anda dapat mengetahuinya menggunakan CarConnection
API, yang memberikan LiveData
sehingga Anda dapat memantau status koneksi.
- Untuk menggunakan
CarConnection
API, Anda harus menambahkan dependensi terlebih dahulu dalam modul:app
di artefakandroidx.car.app:app
.
build.gradle (Modul :app)
dependencies {
...
implementation "androidx.car.app:app:$car_app_library_version"
...
}
- Untuk tujuan demonstrasi, Anda dapat membuat Composable sederhana seperti berikut, yang menampilkan status koneksi saat ini. Dalam aplikasi sebenarnya, status ini mungkin dicatat dalam logging tertentu, yang digunakan untuk menonaktifkan fungsi tertentu di layar ponsel saat diproyeksikan, atau digunakan untuk tujuan lainnya.
MainActivity.kt
@Composable
fun ProjectionState(carConnectionType: Int, modifier: Modifier = Modifier) {
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"
}
Text(
text = text,
style = MaterialTheme.typography.bodyMedium,
modifier = modifier
)
}
- Setelah menemukan cara untuk menampilkan data, kini saatnya membaca dan meneruskannya menjadi Composable, sebagaimana ditunjukkan dalam cuplikan berikut.
MainActivity.kt
setContent {
val carConnectionType by CarConnection(this).type.observeAsState(initial = -1)
PlacesTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column {
Text(
text = "Places",
style = MaterialTheme.typography.displayLarge,
modifier = Modifier.padding(8.dp)
)
ProjectionState(
carConnectionType = carConnectionType,
modifier = Modifier.padding(8.dp)
)
PlaceList(places = PlacesRepository().getPlaces())
}
}
}
}
- Jika dijalankan, aplikasinya akan menampilkan pesan Not projecting.
7. Melakukan pengujian menggunakan Desktop Head Unit (DHU)
Setelah mengimplementasikan CarAppService
dan menyiapkan konfigurasi Android Auto, kini saatnya menjalankan aplikasi dan melihat tampilannya.
- Instal aplikasi di ponsel Anda, lalu ikuti petunjuk tentang cara menginstal dan menjalankan DHU.
Setelah DHU aktif dan dijalankan, Anda akan melihat ikon aplikasi di peluncur (jika tidak, periksa kembali apakah Anda sudah mengikuti semua langkah di bagian sebelumnya, lalu keluar dan mulai ulang DHU dari terminal).
Ups, aplikasinya error.
- Untuk mengetahui penyebab error aplikasi, Anda dapat mengaktifkan ikon debug di pojok kanan atas (hanya terlihat jika menjalankan aplikasi di DHU) atau memeriksa Logcat di Android Studio.
Error: [type: null, cause: null, debug msg: java.lang.IllegalArgumentException: Min API level not declared in manifest (androidx.car.app.minCarApiLevel) at androidx.car.app.AppInfo.retrieveMinCarAppApiLevel(AppInfo.java:143) at androidx.car.app.AppInfo.create(AppInfo.java:91) at androidx.car.app.CarAppService.getAppInfo(CarAppService.java:380) at androidx.car.app.CarAppBinder.getAppInfo(CarAppBinder.java:255) at androidx.car.app.ICarApp$Stub.onTransact(ICarApp.java:182) at android.os.Binder.execTransactInternal(Binder.java:1285) at android.os.Binder.execTransact(Binder.java:1244) ]
Dari log, Anda dapat melihat bahwa ada deklarasi yang belum disertakan dalam manifes untuk level API minimum yang didukung aplikasi. Sebelum menambahkan entri tersebut, sebaiknya pahami terlebih dahulu mengapa kita perlu melakukannya.
Seperti Android itu sendiri, Library Aplikasi Mobil juga memiliki konsep level API karena harus ada perjanjian antara aplikasi host dan klien agar keduanya dapat berkomunikasi. Aplikasi host mendukung level API tertentu beserta fiturnya yang terkait (dan untuk kompatibilitas mundur, hal ini juga berlaku untuk level yang lebih rendah). Misalnya, SignInTemplate
dapat digunakan pada host yang menjalankan level API 2 atau lebih tinggi. Namun, jika Anda mencoba menggunakannya pada host yang hanya mendukung level API 1, host tersebut tidak akan mengetahui jenis template dan tidak akan bisa melakukan tindakan penting dengan hal tersebut.
Selama proses binding host ke klien, harus ada semacam titik temu dalam hal level API yang didukung agar binding berhasil. Misalnya, jika host hanya mendukung level API 1, tetapi aplikasi klien tidak dapat dijalankan tanpa fitur dari level API 2 (sebagaimana disebutkan dalam deklarasi manifes ini), aplikasi tidak akan terhubung karena klien tidak akan berhasil dijalankan di host. Oleh karena itu, persyaratan level API minimum harus dideklarasikan oleh klien dalam manifesnya guna memastikan bahwa hanya host yang dapat mendukungnya yang akan terikat dengannya.
- Untuk menetapkan level API minimum yang didukung, tambahkan elemen
<meta-data>
berikut dalam fileAndroidManfiest.xml
modul:common:car-app-service
:
AndroidManifest.xml (:common:car-app-service)
<application>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1" />
<service android:name="com.example.places.carappservice.PlacesCarAppService" ...>
...
</service>
</application>
- Instal aplikasi lagi dan luncurkan di DHU, setelah itu Anda akan melihat tampilan berikut:
Agar lebih lengkap, Anda juga dapat mencoba menetapkan minCarApiLevel
ke nilai yang besar (misalnya 100) untuk mengetahui apa yang terjadi saat Anda mencoba memulai aplikasi jika host dan klien tidak kompatibel (petunjuk: aplikasi akan mengalami error, sama seperti jika tidak ada nilai yang ditetapkan).
Penting juga untuk diketahui bahwa, sama seperti Android itu sendiri, Anda dapat menggunakan berbagai fitur dari API yang lebih tinggi dari level minimum yang dideklarasikan jika Anda memverifikasi di runtime bahwa host mendukung level yang diwajibkan.
Opsional: Memproses perubahan proyeksi
- Jika Anda menambahkan pemroses
CarConnection
pada langkah sebelumnya, Anda akan melihat perubahan status di ponsel Anda saat DHU dijalankan, seperti yang terlihat di bawah:
8. Menambahkan dukungan untuk Android Automotive OS
Setelah Android Auto aktif dan dijalankan, kini saatnya melakukan upaya ekstra untuk mendukung Android Automotive OS juga.
Membuat modul :automotive
- Guna membuat modul yang berisi kode khusus untuk versi Android Automotive OS aplikasi, buka File > New > New Module... di Android Studio, pilih opsi Automotive dari daftar jenis template di sebelah kiri, lalu gunakan nilai berikut:
- Nama Aplikasi/Library:
Places
(sama seperti aplikasi utama, tetapi Anda juga dapat memilih nama lain sesuai keinginan) - Nama modul:
automotive
- Nama paket:
com.example.places.automotive
- Bahasa:
Kotlin
- SDK minimum:
API 29: Android 10.0 (Q)
—seperti yang dijelaskan sebelumnya saat membuat modul:common:car-app-service
, semua kendaraan Android Automotive OS yang mendukung aplikasi Library Aplikasi Mobil memiliki level API minimum 29.
- Klik Next, lalu pilih No Activity di layar berikutnya sebelum mengklik Finish.
Menambahkan dependensi
Sama seperti Android Auto, Anda harus mendeklarasikan dependensi di modul :common:car-app-service
. Dengan begitu, Anda dapat menggunakan implementasi Anda di kedua platform.
Selain itu, Anda perlu menambahkan dependensi di artefak androidx.car.app:app-automotive
. Berbeda dengan artefak androidx.car.app:app-projected
yang sifatnya opsional bagi Android Auto, dependensi ini diwajibkan di Android Automotive OS karena berisi CarAppActivity
yang digunakan untuk menjalankan aplikasi Anda.
- Untuk menambahkan dependensi, buka file
build.gradle
, lalu sisipkan kode berikut:
build.gradle (Modul :automotive)
dependencies {
...
implementation project(':common:car-app-service')
implementation "androidx.car.app:app-automotive:$car_app_library_version"
...
}
Dengan perubahan ini, grafik dependensi untuk modul aplikasi akan terlihat seperti berikut:
Menyiapkan manifes
- Pertama, Anda harus mendeklarasikan dua fitur, yakni
android.hardware.type.automotive
danandroid.software.car.templates_host
, sebagaimana diwajibkan.
android.hardware.type.automotive
merupakan fitur sistem yang mengindikasikan bahwa perangkat itu sendiri adalah kendaraan (lihat FEATURE_AUTOMOTIVE
untuk mengetahui detail selengkapnya). Hanya aplikasi yang mewajibkan fitur ini yang dapat dikirim ke jalur Automotive OS di Konsol Play (dan aplikasi yang dikirim ke jalur lain tidak dapat mewajibkan fitur ini). android.software.car.templates_host
adalah fitur sistem yang hanya tersedia di kendaraan yang memiliki host template yang diwajibkan untuk menjalankan aplikasi template.
AndroidManifest.xml (:automotive)
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature
android:name="android.hardware.type.automotive"
android:required="true" />
<uses-feature
android:name="android.software.car.templates_host"
android:required="true" />
...
</manifest>
- Selanjutnya, Anda harus mendeklarasikan bahwa beberapa fitur tidak diwajibkan.
Hal ini bertujuan memastikan bahwa aplikasi Anda kompatibel dengan rentang hardware yang tersedia di mobil yang dilengkapi Google. Misalnya, jika aplikasi Anda mewajibkan fitur android.hardware.screen.portrait
, aplikasi tersebut tidak akan kompatibel dengan kendaraaan yang memiliki layar lanskap karena orientasi layar di sebagian besar kendaraan bersifat tetap. Oleh karena itu, atribut android:required
ditetapkan ke false
untuk fitur ini.
AndroidManifest.xml (:automotive)
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.landscape"
android:required="false" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
...
</manifest>
- Selanjutnya, Anda harus menambahkan referensi ke file
automotive_app_desc.xml
seperti yang Anda lakukan untuk Android Auto.
Perlu diketahui bahwa kali ini atribut android:name
tidak sama seperti sebelumnya–jika sebelumnya nilainya com.google.android.gms.car.application
, sekarang nilainya adalah com.android.automotive
. Sama seperti sebelumnya, ini akan merujuk file automotive_app_desc.xml
dalam modul :common:car-app-service
, sehingga resource yang sama akan digunakan di Android Auto dan Android Automotive OS. Perlu diketahui bahwa elemen <meta-data>
berada di dalam elemen <application>
(jadi Anda harus mengubah tag application
agar tidak tertutup).
AndroidManifest.xml (:automotive)
<application>
...
<meta-data android:name="com.android.automotive"
android:resource="@xml/automotive_app_desc"/>
...
</application>
- Terakhir, Anda harus menambahkan elemen
<activity>
untukCarAppActivity
yang disertakan dalam library.
AndroidManifest.xml (:automotive)
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
...
<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>
</application>
</manifest>
Semua itu akan memberikan hasil sebagai berikut:
android:name
membuat daftar nama class yang sepenuhnya memenuhi syarat pada classCarAppActivity
dari paketapp-automotive
.android:exported
ditetapkan ketrue
karenaActivity
ini harus bisa diluncurkan oleh aplikasi selain aplikasi itu sendiri (peluncur).android:launchMode
ditetapkan kesingleTask
sehingga hanya boleh ada satu instanceCarAppActivity
pada satu waktu.android:theme
ditetapkan ke@android:style/Theme.DeviceDefault.NoActionBar
sehingga aplikasi menggunakan ruang layar penuh yang tersedia untuknya.- Filter intent menunjukkan bahwa ini adalah
Activity
peluncur untuk aplikasi. - Terdapat elemen
<meta-data>
yang menunjukkan ke sistem bahwa aplikasi dapat digunakan saat pembatasan UX diterapkan, seperti saat kendaraan sedang bergerak.
Opsional: menyalin ikon peluncur dari modul :app
Karena Anda baru saja membuat modul :automotive
, ikon logo Android hijau akan menjadi ikon default.
- Jika mau, Anda dapat menyalin dan menempel direktori resource
mipmap
dari modul:app
ke modul:automotive
agar menggunakan ikon peluncur yang sama seperti aplikasi seluler.
9. Melakukan pengujian menggunakan emulator Android Automotive OS
Menginstal Image Sistem Automotive dengan Play Store
- Pertama, buka SDK Manager di Android Studio, lalu pilih tab SDK Platforms jika belum dipilih. Di pojok kanan bawah jendela SDK Manager, pastikan kotak Show package details dicentang.
- Instal satu atau beberapa image emulator berikut. Image hanya dapat berjalan di komputer dengan arsitektur yang sama (x86/ARM) dengan image itu sendiri.
- Image Sistem Atom_64 Intel x86 Android 12L > Automotive dengan Play Store
- Image Sistem ARM 64 v8a Android 12L > Automotive dengan Play Store
- Image Sistem Atom_64 Intel x86 Android 11 > Automotive dengan Play Store
- Image Sistem Atom_64 Intel x86 Android 10 > Automotive dengan Play Store
Membuat Perangkat Virtual Android untuk Android Automotive OS
- Setelah membuka Pengelola Perangkat, pilih Automotive di kolom Category di sisi kiri jendela. Setelah itu, pilih definisi perangkat Automotive (1024p landscape) dari daftar, lalu klik Next.
- Pada halaman berikutnya, pilih image sistem dari langkah sebelumnya (jika Anda memilih image Android 11/API 30, opsi ini mungkin ada di tab x86 Images, bukan tab Recommended default). Klik Next, lalu pilih opsi lanjutan yang Anda inginkan sebelum akhirnya membuat AVD dengan mengklik Finish.
Menjalankan aplikasi
- Jalankan aplikasi di emulator yang baru saja Anda buat menggunakan konfigurasi run
automotive
.
Saat pertama kali menjalankan aplikasi, Anda mungkin akan melihat layar seperti berikut:
Jika ini terjadi, klik tombol Check for updates, yang akan mengarahkan Anda ke halaman Play Store untuk aplikasi Google Automotive App Host, lalu klik tombol Install. Jika Anda tidak login saat mengklik tombol Check for updates, Anda akan diarahkan ke alur login. Setelah login, Anda dapat membuka aplikasi lagi untuk mengklik tombol dan kembali ke halaman Play Store.
- Setelah host diinstal, buka aplikasi dari peluncur (ikon petak sembilan titik di baris bawah) lagi, dan Anda akan melihat tampilan berikut:
Pada langkah berikutnya, Anda akan membuat perubahan pada modul :common:car-app-service
untuk menampilkan daftar tempat dan memungkinkan pengguna memulai navigasi ke lokasi yang dipilih di aplikasi lain.
10. Menambahkan peta dan layar detail
Menambahkan peta ke layar utama
- Untuk memulai, ganti kode di metode
onGetTemplate
classMainScreen
dengan kode berikut:
MainScreen.kt
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 { TODO() }
// 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()
}
Kode ini membaca daftar instance Place
dari PlacesRepository
, lalu mengonversi masing-masing instance menjadi Row
untuk ditambahkan ke ItemList
yang ditampilkan oleh PlaceListMapTemplate
.
- Jalankan aplikasi lagi (di salah satu atau kedua platform) untuk mengetahui hasilnya.
Android Auto | Android Automotive OS |
Ups, terjadi error lagi–sepertinya ada izin yang belum disertakan.
java.lang.SecurityException: The car app does not have a required permission: androidx.car.app.MAP_TEMPLATES at android.os.Parcel.createExceptionOrNull(Parcel.java:2373) at android.os.Parcel.createException(Parcel.java:2357) at android.os.Parcel.readException(Parcel.java:2340) at android.os.Parcel.readException(Parcel.java:2282) ...
- Untuk memperbaiki error, tambahkan elemen
<uses-permission>
berikut dalam manifes modul:common:car-app-service
.
Izin ini harus dideklarasikan oleh setiap aplikasi yang menggunakan PlaceListMapTemplate
. Jika tidak, aplikasi akan mengalami error seperti yang ditunjukkan. Perlu diketahui bahwa hanya aplikasi yang mendeklarasikan kategorinya sebagai androidx.car.app.category.POI
yang dapat menggunakan template ini, dan kemudian dapat menggunakan izin ini.
AndroidManifest.xml (:common:car-app-service)
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="androidx.car.app.MAP_TEMPLATES" />
...
</manifest>
Jika Anda menjalankan aplikasi setelah menambahkan izin ini, tampilannya akan terlihat seperti berikut di setiap platform:
Android Auto | Android Automotive OS |
Anda tidak perlu mengkhawatirkan proses rendering peta karena hal ini ditangani oleh host aplikasi saat Anda memberikan Metadata
yang diperlukan!
Menambahkan layar detail
Selanjutnya, kita akan menambahkan layar detail agar pengguna dapat melihat informasi lebih lanjut terkait suatu lokasi tertentu, lalu pengguna dapat melakukan navigasi ke lokasi tersebut menggunakan aplikasi navigasi pilihan mereka atau kembali ke daftar tempat lainnya. Hal ini dapat dilakukan menggunakan PaneTemplate
, yang memungkinkan Anda menampilkan hingga empat baris informasi di samping tombol tindakan opsional.
- Pertama, klik kanan direktori
res
di modul:common:car-app-service
, klik New > Vector Asset, lalu buat ikon navigasi menggunakan konfigurasi berikut:
- Jenis aset:
Clip art
- Gambar klip:
navigation
- Nama:
baseline_navigation_24
- Ukuran:
24
dp x24
dp - Warna:
#000000
- Opasitas:
100%
- Setelah itu, di paket
screen
buat file bernamaDetailScreen.kt
(di samping fileMainScreen.kt
yang sudah ada), lalu tambahkan kode berikut:
DetailScreen.kt
class DetailScreen(carContext: CarContext, private val placeId: Int) : Screen(carContext) {
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()
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)
.build()
}
}
Perhatikan baik-baik cara navigateAction
dibuat—panggilan ke startCarApp
dalam OnClickListener
miliknya adalah kunci untuk berinteraksi dengan aplikasi lain di Android Auto dan Android Automotive OS.
Navigasi antar-layar
Dengan dua jenis layar yang sudah siap, kini saatnya menambahkan navigasi antar-keduanya. Navigasi dalam Library Aplikasi Mobil menggunakan model stack push dan pop-up yang sangat cocok untuk alur tugas sederhana yang dapat diselesaikan saat mengemudi.
- Untuk melakukan navigasi dari salah satu item daftar di
MainScreen
keDetailScreen
untuk item tersebut, tambahkan kode berikut:
MainScreen.kt
Row.Builder()
...
.setOnClickListener { screenManager.push(DetailScreen(carContext, it.id)) }
...
Anda tidak perlu mengkhawatirkan navigasi kembali dari DetailScreen
ke MainScreen
. Hal ini sudah ditangani karena setHeaderAction(Action.BACK)
dipanggil saat membuat PaneTemplate
yang ditampilkan di DetailScreen
. Saat tindakan header diklik oleh pengguna, host akan menangani penutupan layar saat ini dari stack untuk Anda, tetapi perilaku ini dapat diganti oleh aplikasi Anda jika diinginkan.
- Sekarang, jalankan aplikasi untuk melihat cara kerja
DetailScreen
dan navigasi dalam aplikasi.
11. Memperbarui konten di layar
Anda sering kali ingin agar pengguna dapat berinteraksi dengan layar dan mengubah status elemen layar tersebut. Agar tahu cara melakukan ini, Anda akan membuat fungsi agar pengguna dapat beralih antara opsi favoritkan dan batal favoritkan tempat dari DetailScreen
.
- Pertama, tambahkan variabel lokal,
isFavorite
, yang berisi status. Di aplikasi yang sebenarnya, ini akan disimpan sebagai bagian dari lapisan data, tetapi variabel lokal sudah cukup untuk tujuan demonstrasi.
DetailScreen.kt
class DetailScreen(carContext: CarContext, private val placeId: Int) : Screen(carContext) {
private var isFavorite = false
...
}
- Selanjutnya, klik kanan direktori
res
di modul:common:car-app-service
, klik New > Vector Asset, lalu buat ikon navigasi menggunakan konfigurasi berikut:
- Jenis aset:
Clip art
- Nama:
baseline_favorite_24
- Gambar klip:
favorite
- Ukuran:
24
dp x24
dp - Warna:
#000000
- Opasitas:
100%
- Kemudian, di
DetailsScreen.kt
, buatActionStrip
untukPaneTemplate
.
Komponen UI ActionStrip
ditempatkan di baris header di sebelah judul dan sangat cocok untuk tindakan sekunder maupun tersier. Karena navigasi adalah tindakan utama yang akan dilakukan di DetailScreen
, menempatkan Action
untuk tindakan favoritkan dan batalkan favorit di ActionStrip
adalah cara yang bagus untuk menyusun struktur layar.
DetailScreen.kt
val navigateAction = ...
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
}.build()
)
.build()
...
Ada dua poin menarik di sini:
CarIcon
akan diberi tint bergantung pada status item.setOnClickListener
digunakan untuk memberikan reaksi terhadap input dari pengguna dan mengaktifkan/menonaktifkan status favorit.
- Jangan lupa untuk memanggil
setActionStrip
diPaneTemplate.Builder
jika ingin menggunakannya.
DetailScreen.kt
return PaneTemplate.Builder(...)
...
.setActionStrip(actionStrip)
.build()
- Sekarang, jalankan aplikasi dan lihat apa yang terjadi:
Ini menarik... kliknya sudah terjadi tetapi UI-nya tidak berubah.
Hal ini karena Library Aplikasi Mobil memiliki konsep refresh. Untuk membatasi gangguan bagi pengemudi, refresh konten di layar memiliki batasan tertentu (yang mungkin bervariasi menurut template yang ditampilkan), dan setiap refresh harus diminta secara eksplisit oleh kode Anda sendiri dengan memanggil metode invalidate
class Screen
. UI-nya tidak akan berubah jika Anda hanya memperbarui status tertentu yang dirujuk di onGetTemplate
.
- Untuk memperbaiki masalah ini, perbarui
OnClickListener
seperti berikut:
DetailScreen.kt
.setOnClickListener {
isFavorite = !isFavorite
// Request that `onGetTemplate` be called again so that updates to the
// screen's state can be picked up
invalidate()
}
- Jalankan aplikasi lagi, dan kali ini akan terlihat bahwa warna ikon hati akan berubah di setiap kliknya.
Begitulah langkah-langkahnya, kini Anda memiliki aplikasi yang terintegrasi secara optimal dengan Android Auto dan Android Automotive OS.
12. Selamat
Anda berhasil membuat aplikasi Library Aplikasi Mobil. Kini saatnya menerapkan apa yang telah Anda pelajari pada aplikasi Anda sendiri.
Seperti yang dijelaskan sebelumnya, saat ini hanya kategori tertentu yang dibuat menggunakan aplikasi Library Aplikasi Mobil yang dapat dikirim ke Play Store. Jika aplikasi Anda adalah aplikasi navigasi, aplikasi lokasi menarik (POI) (seperti yang Anda kerjakan dalam codelab ini), atau aplikasi internet of things (IOT), Anda dapat mulai membuat aplikasi sekarang juga dan merilisnya hingga fase produksi di kedua platform.
Berbagai kategori aplikasi baru akan ditambahkan setiap tahunnya, sehingga meski Anda tidak dapat langsung menerapkan apa yang telah Anda pelajari, pantau terus informasinya, bisa jadi akan tiba saat yang tepat untuk memperluas aplikasi Anda ke perangkat mobil.
Untuk dicoba
- Instal emulator OEM (misalnya emulator Polestar 2) dan lihat bagaimana penyesuaian OEM dapat mengubah tampilan dan nuansa aplikasi Library Aplikasi Mobil di Android Automotive OS. Perlu diketahui bahwa tidak semua emulator OEM mendukung aplikasi Library Aplikasi Mobil.
- Lihat Etalase aplikasi contoh yang menunjukkan fungsi lengkap Library Aplikasi Mobil.
Bacaan lebih lanjut
- Menggunakan Library Aplikasi Android untuk Mobil membahas konten dalam codelab ini dan banyak konten lainnya.
- Panduan Desain Library Aplikasi Android untuk Mobil memberikan penjelasan mendetail terkait semua template yang berbeda beserta praktik terbaik yang sebaiknya diikuti saat membuat aplikasi Anda.
- Halaman Kualitas aplikasi Android untuk mobil menjelaskan kriteria yang harus dipenuhi aplikasi Anda untuk menciptakan pengalaman pengguna yang optimal dan lulus peninjauan Play Store.