Menggunakan Library Aplikasi Android untuk Mobil

Library Aplikasi Android untuk Mobil memungkinkan Anda menghadirkan aplikasi navigasi, lokasi menarik (POI), dan Internet of Things (IOT) ke mobil. Hal ini dilakukan dengan menyediakan serangkaian template yang dirancang untuk memenuhi standar gangguan bagi pengemudi dan menangani detail seperti berbagai faktor layar mobil dan modalitas input.

Panduan ini memberikan ringkasan fitur dan konsep utama library, serta memandu Anda dalam proses menyiapkan aplikasi dasar.

Sebelum memulai

  1. Tinjau halaman Desain untuk Mengemudi yang membahas Library Aplikasi Mobil
  2. Tinjau istilah dan konsep utama di bagian berikut.
  3. Pelajari UI Sistem Android Auto dan desain Android Automotive OS.
  4. Tinjau Catatan Rilis.
  5. Tinjau Contoh.

Istilah dan konsep utama

Model dan Template
Antarmuka pengguna diwakili oleh grafik objek model yang dapat digabungkan dengan cara yang berbeda-beda, seperti yang diizinkan oleh template yang mencakupnya. Template adalah subset model yang dapat bertindak sebagai root dalam grafik tersebut. Model mencakup informasi yang akan ditampilkan kepada pengguna dalam bentuk teks dan gambar serta atribut untuk mengonfigurasi aspek tampilan visual informasi tersebut—misalnya, warna teks atau ukuran gambar. Host mengonversi model menjadi tampilan yang dirancang untuk memenuhi standar gangguan bagi pengemudi dan menangani detail seperti berbagai faktor layar mobil dan modalitas input.
Host
Host adalah komponen backend yang menerapkan fungsi yang ditawarkan oleh API library agar aplikasi Anda dapat berjalan di mobil. Tanggung jawab host berkisar dari menemukan aplikasi dan mengelola siklus prosesnya hingga mengubah model Anda menjadi tampilan dan memberi tahu aplikasi Anda tentang interaksi pengguna. Pada perangkat seluler, host ini diimplementasikan oleh Android Auto. Di Android Automotive OS, host ini diinstal sebagai aplikasi sistem.
Batasan template
Berbagai template menerapkan pembatasan pada konten model mereka. Misalnya, template daftar memiliki batas jumlah item yang dapat ditampilkan kepada pengguna. Template juga memiliki batasan dalam cara terhubung untuk membentuk alur tugas. Misalnya, aplikasi hanya dapat mengirim hingga lima template ke stack layar. Lihat Batasan template untuk mengetahui detail selengkapnya.
Screen
Screen adalah class yang disediakan oleh library yang diterapkan aplikasi untuk mengelola antarmuka pengguna yang ditampilkan kepada pengguna. Screen memiliki siklus proses dan menyediakan mekanisme bagi aplikasi untuk mengirim template agar ditampilkan saat layar terlihat. Instance Screen juga dapat didorong dan muncul ke dan dari stack Screen, yang memastikannya mematuhi pembatasan alur template.
CarAppService
CarAppService adalah class Service abstrak yang harus diterapkan dan diekspor aplikasi Anda agar dapat ditemukan dan dikelola oleh host. CarAppService aplikasi Anda bertanggung jawab untuk memvalidasi bahwa koneksi host dapat dipercaya menggunakan createHostValidator dan kemudian menyediakan instance Session untuk setiap koneksi menggunakan onCreateSession.
Session

Session adalah class abstrak yang harus diterapkan dan ditampilkan oleh aplikasi Anda menggunakan CarAppService.onCreateSession. Ini berfungsi sebagai titik entri untuk menampilkan informasi di layar mobil. Aplikasi ini memiliki siklus proses yang menginformasikan status aplikasi saat ini di layar mobil, seperti saat aplikasi Anda terlihat atau tersembunyi.

Saat Session dimulai, seperti saat aplikasi pertama kali diluncurkan, host akan meminta Screen awal untuk ditampilkan menggunakan metode onCreateScreen.

Menginstal Library Aplikasi Mobil

Lihat halaman rilis library Jetpack untuk mengetahui petunjuk cara menambahkan library ke aplikasi Anda.

Mengonfigurasi file manifes aplikasi Anda

Sebelum dapat membuat aplikasi mobil, konfigurasikan file manifes aplikasi Anda sebagai berikut.

Mendeklarasikan CarAppService Anda

Host terhubung ke aplikasi Anda melalui implementasi CarAppService. Anda mendeklarasikan layanan ini dalam manifes agar host dapat menemukan dan terhubung ke aplikasi Anda.

Anda juga harus mendeklarasikan kategori aplikasi Anda dalam elemen <category> dari filter intent aplikasi Anda. Lihat daftar kategori aplikasi yang didukung untuk nilai yang diizinkan untuk elemen ini.

Cuplikan kode berikut menunjukkan cara mendeklarasikan layanan aplikasi mobil untuk aplikasi lokasi menarik dalam manifes Anda:

<application>
    ...
   <service
       ...
        android:name=".MyCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService"/>
        <category android:name="androidx.car.app.category.POI"/>
      </intent-filter>
    </service>

    ...
<application>

Kategori aplikasi yang didukung

Deklarasikan kategori aplikasi Anda dengan menambahkan satu atau beberapa nilai kategori berikut dalam filter intent saat Anda mendeklarasikan CarAppService seperti yang dijelaskan di bagian sebelumnya:

  • androidx.car.app.category.NAVIGATION: aplikasi yang menyediakan rute navigasi belokan demi belokan. Lihat Membangun aplikasi navigasi untuk mobil guna dokumentasi tambahan tentang kategori ini.
  • androidx.car.app.category.POI: aplikasi yang menyediakan fungsi yang relevan untuk menemukan lokasi menarik seperti tempat parkir, SPKLU, dan SPBU. Lihat Mem-build aplikasi lokasi menarik untuk mobil guna mendapatkan dokumentasi tambahan tentang kategori ini.
  • androidx.car.app.category.IOT: Aplikasi yang memungkinkan pengguna mengambil tindakan yang relevan di perangkat terhubung dari dalam mobil. Lihat Membangun aplikasi Internet of Things untuk mobil untuk dokumentasi tambahan tentang kategori ini.

Lihat Kualitas aplikasi Android untuk mobil guna mengetahui deskripsi terperinci tentang setiap kategori dan kriteria untuk aplikasi yang termasuk dalam kategori tersebut.

Menentukan nama dan ikon aplikasi

Anda perlu menentukan nama dan ikon aplikasi yang dapat digunakan oleh host untuk mewakili aplikasi Anda di UI sistem.

Anda dapat menentukan nama dan ikon aplikasi yang digunakan untuk mewakili aplikasi menggunakan atribut label dan icon dari CarAppService:

...
<service
   android:name=".MyCarAppService"
   android:exported="true"
   android:label="@string/my_app_name"
   android:icon="@drawable/my_app_icon">
   ...
</service>
...

Jika label atau ikon tidak dideklarasikan dalam elemen <service>, host akan kembali ke nilai yang ditentukan untuk elemen <application>.

Menetapkan tema kustom

Guna menetapkan tema kustom untuk aplikasi mobil Anda, tambahkan elemen <meta-data> dalam file manifes Anda, seperti berikut:

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

Kemudian, deklarasikan resource gaya untuk menetapkan atribut berikut untuk tema aplikasi mobil kustom Anda:

<resources>
  <style name="MyCarAppTheme">
    <item name="carColorPrimary">@layout/my_primary_car_color</item>
    <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item>
    <item name="carColorSecondary">@layout/my_secondary_car_color</item>
    <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item>
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

API Level Aplikasi Mobil

Library Aplikasi Mobil menentukan API level-nya sendiri sehingga Anda dapat mengetahui fitur library yang didukung oleh host template pada kendaraan. Untuk mengambil API Level Aplikasi Mobil tertinggi yang didukung oleh host, gunakan metode getCarAppApiLevel().

Deklarasikan API Level Aplikasi Mobil minimum yang didukung oleh aplikasi Anda di file AndroidManifest.xml:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

Lihat dokumentasi untuk anotasi RequiresCarApi guna mengetahui detail tentang cara mempertahankan kompatibilitas mundur dan mendeklarasikan API level minimum yang diperlukan untuk menggunakan suatu fitur. Untuk mengetahui definisi API level mana yang diperlukan untuk menggunakan fitur tertentu dari Library Aplikasi Mobil, lihat dokumentasi referensi untuk CarAppApiLevels.

Membuat CarAppService dan Sesi

Aplikasi Anda perlu memperluas class CarAppService dan menerapkan metode onCreateSession, yang menampilkan instance Session yang sesuai dengan koneksi saat ini ke host:

Kotlin

class HelloWorldService : CarAppService() {
    ...
    override fun onCreateSession(): Session {
        return HelloWorldSession()
    }
    ...
}

Java

public final class HelloWorldService extends CarAppService {
    ...
    @Override
    @NonNull
    public Session onCreateSession() {
        return new HelloWorldSession();
    }
    ...
}

Instance Session bertanggung jawab menampilkan instance Screen untuk digunakan saat aplikasi pertama kali dimulai:

Kotlin

class HelloWorldSession : Session() {
    ...
    override fun onCreateScreen(intent: Intent): Screen {
        return HelloWorldScreen(carContext)
    }
    ...
}

Java

public final class HelloWorldSession extends Session {
    ...
    @Override
    @NonNull
    public Screen onCreateScreen(@NonNull Intent intent) {
        return new HelloWorldScreen(getCarContext());
    }
    ...
}

Untuk menangani skenario saat aplikasi mobil harus dimulai dari layar yang bukan layar utama atau halaman landing aplikasi, seperti menangani deep link, Anda dapat melakukan pra-seed data layar sebelumnya menggunakan ScreenManager.push sebelum kembali dari onCreateScreen. Pra-seeding memungkinkan pengguna kembali ke layar sebelumnya dari layar pertama yang ditampilkan aplikasi Anda.

Membuat layar mulai

Anda membuat layar yang ditampilkan oleh aplikasi dengan menentukan class yang memperluas class Screen dan menerapkan metode onGetTemplate, yang menampilkan instance Template yang mewakili status UI untuk ditampilkan di layar mobil.

Cuplikan berikut menunjukkan cara mendeklarasikan Screen yang menggunakan template PaneTemplate untuk menampilkan string “Halo dunia!” sederhana:

Kotlin

class HelloWorldScreen(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()
    }
}

Java

public class HelloWorldScreen extends Screen {
    @NonNull
    @Override
    public Template onGetTemplate() {
        Row row = new Row.Builder().setTitle("Hello world!").build();
        Pane pane = new Pane.Builder().addRow(row).build();
        return new PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build();
    }
}

Class CarContext

Class CarContext adalah subclass ContextWrapper yang dapat diakses oleh instance Session dan Screen Anda. API ini memberikan akses ke layanan mobil, seperti ScreenManager untuk mengelola stack layar; AppManager untuk fungsi terkait aplikasi umum, seperti mengakses objek Surface untuk menggambar peta; dan NavigationManager yang digunakan oleh aplikasi navigasi belokan demi belokan untuk menyampaikan metadata navigasi dan peristiwa terkait navigasi lainnya dengan host.

Lihat Mengakses template navigasi untuk daftar lengkap fungsi library yang tersedia untuk aplikasi navigasi.

CarContext juga menawarkan fungsi lain, seperti mengizinkan Anda memuat resource drawable menggunakan konfigurasi dari layar mobil, memulai aplikasi di mobil menggunakan intent, dan memberi sinyal apakah aplikasi Anda harus menampilkan petanya dalam tema gelap.

Menerapkan navigasi layar

Aplikasi sering kali menyajikan sejumlah layar yang berbeda, masing-masing mungkin menggunakan template yang berbeda yang dapat dilihat pengguna saat mereka berinteraksi dengan antarmuka yang ditampilkan di layar.

Class ScreenManager menyediakan stack layar yang dapat digunakan untuk mendorong layar yang dapat muncul secara otomatis saat pengguna memilih tombol kembali di layar mobil atau menggunakan tombol kembali hardware yang tersedia di beberapa mobil.

Cuplikan berikut menunjukkan cara menambahkan tindakan kembali ke template pesan serta tindakan yang mendorong layar baru saat dipilih oleh pengguna:

Kotlin

val template = MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener { screenManager.push(NextScreen(carContext)) }
            .build())
    .build()

Java

MessageTemplate template = new MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        new Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener(
                () -> getScreenManager().push(new NextScreen(getCarContext())))
            .build())
    .build();

Objek Action.BACK adalah Action standar yang secara otomatis memanggil ScreenManager.pop. Perilaku ini dapat diganti dengan menggunakan instance OnBackPressedDispatcher yang tersedia dari CarContext.

Untuk membantu memastikan aplikasi aman digunakan saat mengemudi, stack layar dapat memiliki kedalaman maksimum lima layar. Lihat bagian Pembatasan template untuk detail selengkapnya.

Memuat ulang konten template

Aplikasi Anda dapat meminta konten Screen dibatalkan validasinya dengan memanggil metode Screen.invalidate. Host kemudian memanggil kembali ke metode Screen.onGetTemplate aplikasi untuk mengambil template dengan konten baru.

Saat memuat ulang Screen, penting untuk memahami konten tertentu dalam template yang dapat diperbarui sehingga host tidak memperhitungkan template baru dalam kuota template. Lihat bagian Batasan template untuk mengetahui detail selengkapnya.

Sebaiknya buat struktur layar Anda sehingga ada pemetaan one-to-one antara Screen dan jenis template yang ditampilkan melalui implementasi onGetTemplate.

Menggambar peta

Aplikasi navigasi dan lokasi menarik (POI) yang menggunakan template berikut dapat menggambar peta dengan mengakses Surface:

Template Izin template Panduan kategori
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES Navigasi
MapWithContentTemplate androidx.car.app.NAVIGATION_TEMPLATES ATAU
androidx.car.app.MAP_TEMPLATES
Navigasi, POI
MapTemplate (tidak digunakan lagi) androidx.car.app.NAVIGATION_TEMPLATES Navigasi
PlaceListNavigationTemplate (tidak digunakan lagi) androidx.car.app.NAVIGATION_TEMPLATES Navigasi
RoutePreviewNavigationTemplate (tidak digunakan lagi) androidx.car.app.NAVIGATION_TEMPLATES Navigasi

Mendeklarasikan izin platform

Selain izin yang diperlukan untuk template yang digunakan aplikasi Anda, aplikasi Anda harus mendeklarasikan izin androidx.car.app.ACCESS_SURFACE dalam file AndroidManifest.xml-nya untuk mendapatkan akses ke platform:

<manifest ...>
  ...
  <uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
  ...
</manifest>

Mengakses platform

Untuk mengakses Surface yang disediakan host, Anda harus mengimplementasikan SurfaceCallback dan menyediakan implementasi tersebut ke layanan mobil AppManager. Surface saat ini diteruskan ke SurfaceCallback Anda dalam parameter SurfaceContainer dari callback onSurfaceAvailable() dan onSurfaceDestroyed().

Kotlin

carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)

Java

carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);

Memahami area yang terlihat pada platform

Host dapat menggambar elemen antarmuka pengguna untuk template di atas peta. Host mengomunikasikan area platform yang dijamin tanpa halangan dan sepenuhnya terlihat oleh pengguna dengan memanggil metode SurfaceCallback.onVisibleAreaChanged. Selain itu, untuk meminimalkan jumlah perubahan, host memanggil metode SurfaceCallback.onStableAreaChanged dengan kotak terkecil yang selalu terlihat berdasarkan template saat ini.

Misalnya, saat aplikasi navigasi menggunakan NavigationTemplate dengan strip tindakan di atasnya, strip tindakan tersebut dapat menyembunyikan dirinya sendiri ketika pengguna tidak berinteraksi dengan layar untuk beberapa saat guna membuat lebih banyak ruang untuk peta. Dalam hal ini, ada callback ke onStableAreaChanged dan onVisibleAreaChanged dengan kotak yang sama. Jika strip tindakan disembunyikan, hanya onVisibleAreaChanged yang dipanggil dengan area yang lebih besar. Jika pengguna berinteraksi dengan layar, sekali lagi hanya onVisibleAreaChanged yang dipanggil dengan kotak pertama.

Mendukung tema gelap

Aplikasi harus menggambar ulang peta ke instance Surface dengan warna gelap yang sesuai saat host menentukan bahwa kondisi menjaminnya, seperti yang dijelaskan dalam kualitas aplikasi Android untuk mobil.

Untuk memutuskan apakah Anda akan menggambar peta gelap, Anda dapat menggunakan metode CarContext.isDarkMode. Setiap kali status tema gelap berubah, Anda akan menerima panggilan ke Session.onCarConfigurationChanged.

Memungkinkan pengguna berinteraksi dengan peta Anda

Saat menggunakan template berikut, Anda dapat menambahkan dukungan bagi pengguna untuk berinteraksi dengan peta yang Anda gambar, seperti mengizinkan mereka melihat berbagai bagian peta dengan memperbesar/memperkecil dan menggeser.

Template Interaktivitas yang didukung sejak API Level Aplikasi Mobil
NavigationTemplate 2
PlaceListNavigationTemplate (tidak digunakan lagi) 4
RoutePreviewNavigationTemplate (tidak digunakan lagi) 4
MapTemplate (tidak digunakan lagi) 5 (pengantar template)
MapWithContentTemplate 7 (pengantar template)

Mengimplementasikan callback interaktivitas

Antarmuka SurfaceCallback memiliki beberapa metode callback yang dapat Anda terapkan untuk menambahkan interaktivitas ke peta yang dibuat dengan template di bagian sebelumnya:

Interaksi Metode SurfaceCallback Didukung sejak API level Aplikasi Mobil
Ketuk onClick 5
Cubit untuk zoom onScale 2
Tarik dengan satu sentuhan onScroll 2
Ayunkan jari dengan satu sentuhan onFling 2
Ketuk dua kali onScale (dengan faktor skala yang ditentukan oleh host template) 2
Sentuhan putar dalam mode geser onScroll (dengan faktor jarak yang ditentukan oleh host template) 2

Menambahkan strip tindakan peta

Template ini dapat memiliki strip tindakan peta untuk tindakan terkait peta seperti memperbesar dan memperkecil, memusatkan kembali, menampilkan kompas, dan tindakan lain yang Anda pilih untuk ditampilkan. Strip tindakan peta dapat memiliki hingga empat tombol khusus ikon yang dapat dimuat ulang tanpa memengaruhi kedalaman tugas. Strip tindakan peta disembunyikan selama status tidak ada aktivitas dan muncul kembali saat status aktif.

Untuk menerima callback interaktivitas peta, Anda harus menambahkan tombol Action.PAN di strip tindakan peta. Saat pengguna menekan tombol geser, host akan memasuki mode geser, seperti yang dijelaskan di bagian berikut.

Jika aplikasi Anda menghilangkan tombol Action.PAN di strip tindakan peta, aplikasi tidak akan menerima input pengguna dari metode SurfaceCallback, dan host keluar dari mode geser yang diaktifkan sebelumnya.

Di layar sentuh, tombol geser tidak ditampilkan.

Memahami mode geser

Dalam mode geser, host template menerjemahkan input pengguna dari perangkat input non-sentuh, seperti pengontrol putar dan touchpad, ke metode SurfaceCallback yang sesuai. Tanggapi tindakan pengguna untuk masuk atau keluar dari mode geser dengan metode setPanModeListener di NavigationTemplate.Builder. Host dapat menyembunyikan komponen UI lainnya di template saat pengguna berada dalam mode geser.

Berinteraksi dengan pengguna

Aplikasi Anda dapat berinteraksi dengan pengguna menggunakan pola yang mirip dengan aplikasi seluler.

Menangani input pengguna

Aplikasi Anda dapat merespons input pengguna dengan meneruskan pendengar yang sesuai ke model yang mendukung mereka. Cuplikan berikut menunjukkan cara membuat model Action yang menetapkan OnClickListener yang dipanggil kembali ke metode yang ditentukan dengan kode aplikasi Anda:

Kotlin

val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()

Java

Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

Metode onClickNavigate kemudian dapat memulai aplikasi mobil navigasi default dengan menggunakan metode CarContext.startCarApp:

Kotlin

private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}

Java

private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

Untuk detail selengkapnya tentang cara memulai aplikasi, termasuk format intent ACTION_NAVIGATE, lihat bagian Memulai aplikasi mobil dengan intent.

Beberapa tindakan, seperti tindakan yang mengharuskan pengguna melanjutkan interaksi di perangkat seluler, hanya diizinkan saat mobil diparkir. Anda dapat menggunakan ParkedOnlyOnClickListener untuk menerapkan tindakan tersebut. Jika mobil tidak diparkir, host akan menampilkan indikasi kepada pengguna bahwa tindakan tersebut tidak diizinkan dalam kasus ini. Jika mobil diparkir, kode akan dijalankan seperti biasa. Cuplikan berikut menunjukkan cara menggunakan ParkedOnlyOnClickListener untuk membuka layar setelan di perangkat seluler:

Kotlin

val row = Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone))
    .build()

Java

Row row = new Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone))
    .build();

Menampilkan notifikasi

Notifikasi yang dikirim ke perangkat seluler hanya akan muncul di layar mobil jika notifikasi tersebut diperluas dengan CarAppExtender. Beberapa atribut notifikasi, seperti judul konten, teks, ikon, dan tindakan, dapat ditetapkan di CarAppExtender, yang menggantikan atribut notifikasi saat muncul di layar mobil.

Cuplikan berikut menunjukkan cara mengirim notifikasi ke layar mobil yang menampilkan judul yang berbeda dari yang ditampilkan di perangkat seluler:

Kotlin

val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build()

Java

Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build();

Notifikasi dapat memengaruhi bagian antarmuka pengguna berikut:

  • Notifikasi pendahuluan (HUN) dapat ditampilkan kepada pengguna.
  • Entri di pusat notifikasi dapat ditambahkan, secara opsional dengan badge yang terlihat di rel.
  • Untuk aplikasi navigasi, notifikasi dapat ditampilkan di widget kolom samping seperti yang dijelaskan dalam Notifikasi belokan demi belokan.

Anda dapat memilih cara mengonfigurasi notifikasi aplikasi untuk memengaruhi setiap elemen antarmuka pengguna tersebut dengan menggunakan prioritas notifikasi, seperti yang dijelaskan dalam dokumentasi CarAppExtender.

Jika NotificationCompat.Builder.setOnlyAlertOnce dipanggil dengan nilai true, notifikasi berprioritas tinggi hanya ditampilkan sebagai HUN satu kali.

Untuk mengetahui informasi selengkapnya tentang cara mendesain notifikasi aplikasi mobil, lihat panduan Google Design for Driving tentang Notifikasi.

Menampilkan toast

Aplikasi Anda dapat menampilkan toast menggunakan CarToast seperti yang ditunjukkan dalam cuplikan ini:

Kotlin

CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()

Java

CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();

Meminta izin

Jika aplikasi Anda memerlukan akses ke data atau tindakan yang dibatasi—misalnya, lokasi—aturan standar izin Android akan berlaku. Untuk meminta izin, Anda dapat menggunakan metode CarContext.requestPermissions().

Manfaat menggunakan CarContext.requestPermissions(), bukan menggunakan API Android standar, adalah Anda tidak perlu meluncurkan Activity Anda sendiri untuk membuat dialog izin. Selain itu, Anda dapat menggunakan kode yang sama di Android Auto dan Android Automotive OS, daripada harus membuat alur yang bergantung pada platform.

Menata gaya dialog izin di Android Auto

Di Android Auto, dialog izin untuk pengguna akan muncul di ponsel. Secara default, tidak akan ada latar belakang di belakang dialog. Untuk menetapkan latar belakang kustom, deklarasikan tema aplikasi mobil di file AndroidManifest.xml dan tetapkan atribut carPermissionActivityLayout untuk tema aplikasi mobil Anda.

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

Kemudian, tetapkan atribut carPermissionActivityLayout untuk tema aplikasi mobil Anda:

<resources>
  <style name="MyCarAppTheme">
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

Memulai aplikasi mobil dengan intent

Anda dapat memanggil metode CarContext.startCarApp untuk melakukan salah satu tindakan berikut:

  • Buka telepon untuk menelepon.
  • Mulai navigasi belokan demi belokan ke lokasi dengan aplikasi mobil navigasi default.
  • Mulai aplikasi Anda sendiri dengan intent.

Contoh berikut menunjukkan cara membuat notifikasi dengan tindakan yang membuka aplikasi Anda dengan layar yang menampilkan detail reservasi parkir. Anda memperluas instance notifikasi dengan intent konten yang berisi PendingIntent yang menggabungkan intent eksplisit ke tindakan aplikasi Anda:

Kotlin

val notification = notificationBuilder
    ...
    .extend(
        CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(ComponentName(context, MyNotificationReceiver::class.java)),
                    0))
            .build())

Java

Notification notification = notificationBuilder
    ...
    .extend(
        new CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    new Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(new ComponentName(context, MyNotificationReceiver.class)),
                    0))
            .build());

Aplikasi Anda juga harus mendeklarasikan BroadcastReceiver yang dipanggil untuk memproses intent saat pengguna memilih tindakan dalam antarmuka notifikasi dan memanggil CarContext.startCarApp dengan intent termasuk URI data:

Kotlin

class MyNotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val intentAction = intent.action
        if (ACTION_VIEW_PARKING_RESERVATION == intentAction) {
            CarContext.startCarApp(
                intent,
                Intent(Intent.ACTION_VIEW)
                    .setComponent(ComponentName(context, MyCarAppService::class.java))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)))
        }
    }
}

Java

public class MyNotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) {
            CarContext.startCarApp(
                intent,
                new Intent(Intent.ACTION_VIEW)
                    .setComponent(new ComponentName(context, MyCarAppService.class))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)));
        }
    }
}

Terakhir, metode Session.onNewIntent di aplikasi Anda menangani intent ini dengan mendorong layar reservasi parkir di stack, jika belum ada di bagian atas:

Kotlin

override fun onNewIntent(intent: Intent) {
    val screenManager = carContext.getCarService(ScreenManager::class.java)
    val uri = intent.data
    if (uri != null
        && MY_URI_SCHEME == uri.scheme
        && MY_URI_HOST == uri.schemeSpecificPart
        && ACTION_VIEW_PARKING_RESERVATION == uri.fragment
    ) {
        val top = screenManager.top
        if (top !is ParkingReservationScreen) {
            screenManager.push(ParkingReservationScreen(carContext))
        }
    }
}

Java

@Override
public void onNewIntent(@NonNull Intent intent) {
    ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
    Uri uri = intent.getData();
    if (uri != null
        && MY_URI_SCHEME.equals(uri.getScheme())
        && MY_URI_HOST.equals(uri.getSchemeSpecificPart())
        && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment())
    ) {
        Screen top = screenManager.getTop();
        if (!(top instanceof ParkingReservationScreen)) {
            screenManager.push(new ParkingReservationScreen(getCarContext()));
        }
    }
}

Lihat bagian Menampilkan notifikasi untuk mengetahui informasi selengkapnya tentang cara menangani notifikasi untuk aplikasi mobil.

Batasan template

Host membatasi jumlah template yang ditampilkan untuk tugas yang diberikan hingga maksimum lima template, dengan template terakhir harus salah satu dari jenis berikut:

Perhatikan bahwa batas ini berlaku untuk jumlah template, bukan jumlah instance Screen dalam stack. Misalnya, jika aplikasi mengirimkan dua template saat berada di layar A, lalu mendorong layar B, aplikasi kini dapat mengirim tiga template lainnya. Atau, jika setiap layar disusun untuk mengirim satu template, aplikasi dapat mendorong lima instance layar ke stack ScreenManager.

Ada beberapa kasus khusus pada pembatasan ini: muat ulang template dan operasi kembali, dan reset.

Memuat ulang template

Pembaruan konten tertentu tidak termasuk dalam batas template. Secara umum, jika aplikasi mengirim template baru dengan jenis yang sama dan berisi konten utama yang sama dengan template sebelumnya, template baru tidak dihitung dalam kuota. Misalnya, memperbarui status pengalihan baris dalam ListTemplate tidak mengurangi kuota. Baca dokumentasi setiap template untuk mempelajari lebih lanjut jenis pembaruan konten yang dapat dianggap sebagai pemuatan ulang.

Operasi kembali

Untuk mengaktifkan sub-alur dalam tugas, host mendeteksi saat aplikasi memunculkan Screen dari stack ScreenManager dan memperbarui kuota yang tersisa berdasarkan jumlah template yang digunakan aplikasi untuk mundur.

Misalnya, jika aplikasi mengirimkan dua template saat berada di layar A, lalu mendorong layar B dan mengirim dua template lainnya, aplikasi memiliki satu kuota yang tersisa. Jika aplikasi kemudian muncul kembali ke layar A, host akan mereset kuota menjadi tiga, karena aplikasi telah mundur sebanyak dua template.

Perhatikan bahwa, saat muncul kembali ke layar, aplikasi harus mengirim template dengan jenis yang sama dengan yang terakhir dikirim oleh layar tersebut. Mengirim jenis template lainnya akan menyebabkan error. Namun, selama jenisnya tetap sama selama operasi kembali, aplikasi dapat dengan bebas mengubah konten template tanpa memengaruhi kuota.

Operasi reset

Template tertentu memiliki semantik khusus yang menandakan akhir tugas. Misalnya, NavigationTemplate adalah tampilan yang diharapkan tetap ada di layar dan dimuat ulang dengan petunjuk belokan demi belokan untuk dipakai pengguna selama beberapa bulan. Saat mencapai salah satu template ini, host akan mereset kuota template, memperlakukan template seolah-olah itu adalah langkah pertama dari tugas baru. Hal ini memungkinkan aplikasi memulai tugas baru. Lihat dokumentasi setiap template untuk melihat template mana yang memicu reset di host.

Jika host menerima intent untuk memulai aplikasi dari tindakan notifikasi atau dari peluncur, kuota juga akan direset. Mekanisme ini memungkinkan aplikasi memulai alur tugas baru dari notifikasi, dan akan tetap berlaku meskipun aplikasi sudah terikat dan berada di latar depan.

Lihat bagian Menampilkan notifikasi untuk mengetahui detail selengkapnya tentang cara menampilkan notifikasi aplikasi di layar mobil. Lihat bagian Memulai aplikasi mobil dengan intent untuk mengetahui informasi tentang cara memulai aplikasi dari tindakan notifikasi.

Connection API

Anda dapat menentukan apakah aplikasi berjalan di Android Auto atau Android Automotive OS dengan menggunakan CarConnection API untuk mengambil informasi koneksi saat runtime.

Misalnya, di Session aplikasi mobil Anda, lakukan inisialisasi CarConnection dan berlangganan update LiveData:

Kotlin

CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)

Java

new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);

Di observer, Anda kemudian dapat bereaksi terhadap perubahan status koneksi:

Kotlin

fun onConnectionStateUpdated(connectionState: Int) {
  val message = when(connectionState) {
    CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit"
    CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS"
    CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto"
    else -> "Unknown car connection type"
  }
  CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show()
}

Java

private void onConnectionStateUpdated(int connectionState) {
  String message;
  switch(connectionState) {
    case CarConnection.CONNECTION_TYPE_NOT_CONNECTED:
      message = "Not connected to a head unit";
      break;
    case CarConnection.CONNECTION_TYPE_NATIVE:
      message = "Connected to Android Automotive OS";
      break;
    case CarConnection.CONNECTION_TYPE_PROJECTION:
      message = "Connected to Android Auto";
      break;
    default:
      message = "Unknown car connection type";
      break;
  }
  CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show();
}

Constraints API

Mobil yang berbeda dapat memungkinkan jumlah instance Item yang berbeda untuk ditampilkan kepada pengguna dalam satu waktu. Gunakan ConstraintManager untuk memeriksa batas konten saat runtime dan menetapkan jumlah item yang sesuai dalam template Anda.

Mulai dengan mendapatkan ConstraintManager dari CarContext:

Kotlin

val manager = carContext.getCarService(ConstraintManager::class.java)

Java

ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);

Kemudian, Anda dapat membuat kueri objek ConstraintManager yang diambil untuk batas konten yang relevan. Misalnya, untuk mendapatkan jumlah item yang dapat ditampilkan dalam petak, panggil getContentLimit dengan CONTENT_LIMIT_TYPE_GRID:

Kotlin

val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)

Java

int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);

Menambahkan alur login

Jika aplikasi menawarkan pengalaman login untuk pengguna, Anda dapat menggunakan template seperti SignInTemplate dan LongMessageTemplate dengan Aplikasi Mobil API level 2 dan yang lebih tinggi untuk menangani proses login ke aplikasi Anda di head unit mobil.

Untuk membuat SignInTemplate, tentukan SignInMethod. Library Aplikasi Mobil saat ini mendukung metode login berikut:

Misalnya, untuk mengimplementasikan template yang mengumpulkan sandi pengguna, mulailah dengan membuat InputCallback untuk memproses dan memvalidasi input pengguna:

Kotlin

val callback = object : InputCallback {
    override fun onInputSubmitted(text: String) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    override fun onInputTextChanged(text: String) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
}

Java

InputCallback callback = new InputCallback() {
    @Override
    public void onInputSubmitted(@NonNull String text) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    @Override
    public void onInputTextChanged(@NonNull String text) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
};

InputCallback diperlukan untuk InputSignInMethod Builder.

Kotlin

val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()

Java

InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

Terakhir, gunakan InputSignInMethod baru untuk membuat SignInTemplate.

Kotlin

SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()

Java

new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();

Menggunakan AccountManager

Aplikasi Android Automotive OS yang memiliki autentikasi harus menggunakan AccountManager karena alasan berikut:

  • UX yang lebih baik dan kemudahan pengelolaan akun: Pengguna dapat mengelola semua akun mereka dengan mudah dari menu akun di setelan sistem, termasuk login dan logout.
  • Pengalaman "Tamu": Karena mobil adalah perangkat bersama, OEM dapat mengaktifkan pengalaman tamu di kendaraan, yang tidak dapat ditambahkan akun.

Menambahkan varian string teks

Ukuran layar mobil yang berbeda dapat menampilkan jumlah teks yang berbeda. Dengan Aplikasi Mobil API level 2 dan yang lebih tinggi, Anda dapat menentukan beberapa varian string teks yang paling sesuai dengan layar. Untuk melihat tempat varian teks diterima, cari template dan komponen yang menggunakan CarText.

Anda dapat menambahkan varian string teks ke CarText dengan metode CarText.Builder.addVariant():

Kotlin

val itemTitle = CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build()

Java

CarText itemTitle = new CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build();

Anda kemudian dapat menggunakan CarText ini—misalnya, sebagai teks utama GridItem.

Kotlin

GridItem.Builder()
    .addTitle(itemTitle)
    ...
    .build()

Java

new GridItem.Builder()
    .addTitle(itemTitle)
    ...
    build();

Tambahkan string secara berurutan dari yang paling disukai ke yang paling tidak disukai—misalnya, dari terpanjang ke terpendek. Host memilih string panjang yang sesuai, bergantung pada jumlah ruang yang tersedia di layar mobil.

Menambahkan CarIcons inline untuk baris

Anda dapat menambahkan ikon yang inline dengan teks untuk memperkaya daya tarik visual aplikasi Anda menggunakan CarIconSpan. Lihat dokumentasi untuk CarIconSpan.create untuk mengetahui informasi selengkapnya tentang cara membuat span ini. Lihat Gaya visual teks spantastis dengan Span untuk ringkasan tentang cara kerja gaya visual teks dengan span.

Kotlin

  
val rating = SpannableString("Rating: 4.5 stars")
rating.setSpan(
    CarIconSpan.create(
        // Create a CarIcon with an image of four and a half stars
        CarIcon.Builder(...).build(),
        // Align the CarIcon to the baseline of the text
        CarIconSpan.ALIGN_BASELINE
    ),
    // The start index of the span (index of the character '4')
    8,
    // The end index of the span (index of the last 's' in "stars")
    16,
    Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

val row = Row.Builder()
    ...
    .addText(rating)
    .build()
  
  

Java

  
SpannableString rating = new SpannableString("Rating: 4.5 stars");
rating.setSpan(
        CarIconSpan.create(
                // Create a CarIcon with an image of four and a half stars
                new CarIcon.Builder(...).build(),
                // Align the CarIcon to the baseline of the text
                CarIconSpan.ALIGN_BASELINE
        ),
        // The start index of the span (index of the character '4')
        8,
        // The end index of the span (index of the last 's' in "stars")
        16,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
);
Row row = new Row.Builder()
        ...
        .addText(rating)
        .build();
  
  

API Hardware Mobil

Mulai dari API Aplikasi Mobil level 3, Library Aplikasi Mobil memiliki API yang dapat Anda gunakan untuk mengakses properti dan sensor kendaraan.

Persyaratan

Untuk menggunakan API dengan Android Auto, mulailah dengan menambahkan dependensi pada androidx.car.app:app-projected ke file build.gradle untuk modul Android Auto Anda. Untuk Android Automotive OS, tambahkan dependensi pada androidx.car.app:app-automotive ke file build.gradle untuk modul Android Automotive OS Anda.

Selain itu, dalam file AndroidManifest.xml, Anda harus mendeklarasikan izin yang relevan yang diperlukan untuk meminta data mobil yang ingin Anda gunakan. Perhatikan bahwa izin ini juga harus diberikan kepada Anda oleh pengguna. Anda dapat menggunakan kode yang sama di Android Auto dan Android Automotive OS, daripada harus membuat alur yang bergantung pada platform. Namun, izin yang diperlukan berbeda.

CarInfo

Tabel ini menjelaskan properti yang ditampilkan oleh API CarInfo dan izin yang perlu Anda minta untuk menggunakannya:

Metode Properti Izin Android Auto Izin Android Automotive OS Didukung sejak API level Aplikasi Mobil
fetchModel Merek, model, tahun android.car.permission.CAR_INFO 3
fetchEnergyProfile Jenis konektor kendaraan listrik, jenis bahan bakar com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO 3
fetchExteriorDimensions

Data ini hanya tersedia di beberapa kendaraan Android Automotive OS yang menjalankan API 30 atau yang lebih tinggi

Dimensi eksterior T/A android.car.permission.CAR_INFO 7
addTollListener
removeTollListener
Status kartu tol, jenis kartu tol 3
addEnergyLevelListener
removeEnergyLevelListener
Tingkat daya baterai, tingkat bahan bakar, tingkat bahan bakar rendah, jarak yang tersisa com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_ENERGY,
android.car.permission.CAR_ENERGY_PORTS,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addSpeedListener
removeSpeedListener
Kecepatan mentah, kecepatan tampilan (ditampilkan di layar cluster mobil) com.google.android.gms.permission.CAR_SPEED android.car.permission.CAR_SPEED,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addMileageListener
removeMileageListener
Jarak odometer com.google.android.gms.permission.CAR_MILEAGE Data ini tidak tersedia di Android Automotive OS untuk aplikasi yang diinstal dari Play Store. 3

Misalnya, untuk mendapatkan rentang yang tersisa, buat instance objek CarInfo, lalu buat dan daftarkan OnCarDataAvailableListener:

Kotlin

val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo

val listener = OnCarDataAvailableListener<EnergyLevel> { data ->
    if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) {
      val rangeRemaining = data.rangeRemainingMeters.value
    } else {
      // Handle error
    }
  }

carInfo.addEnergyLevelListener(carContext.mainExecutor, listener)
…
// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener)

Java

CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo();

OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
  if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) {
    float rangeRemaining = data.getRangeRemainingMeters().getValue();
  } else {
    // Handle error
  }
};

carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener);
…
// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener);

Jangan berasumsi bahwa data dari mobil selalu tersedia. Jika terjadi error, periksa status nilai yang Anda minta untuk lebih memahami mengapa data yang Anda minta tidak dapat diambil. Lihat dokumentasi referensi untuk definisi class CarInfo lengkap.

CarSensors

Class CarSensors memberikan akses ke akselerometer, giroskop, kompas, dan data lokasi kendaraan. Ketersediaan nilai ini mungkin bergantung pada OEM. Format untuk data dari akselerometer, giroskop, dan kompas sama dengan yang akan Anda dapatkan dari SensorManager API. Misalnya, untuk memeriksa judul kendaraan:

Kotlin

val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors

val listener = OnCarDataAvailableListener<Compass> { data ->
    if (data.orientations.status == CarValue.STATUS_SUCCESS) {
      val orientation = data.orientations.value
    } else {
      // Data not available, handle error
    }
  }

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener)
…
// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener)

Java

CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors();

OnCarDataAvailableListener<Compass> listener = (data) -> {
  if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) {
    List<Float> orientations = data.getOrientations().getValue();
  } else {
    // Data not available, handle error
  }
};

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(),
    listener);
…
// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener);

Untuk mengakses data lokasi dari mobil, Anda juga perlu mendeklarasikan dan meminta izin android.permission.ACCESS_FINE_LOCATION.

Pengujian

Untuk menyimulasikan data sensor saat menguji di Android Auto, lihat bagian Sensor dan Konfigurasi sensor dalam panduan Desktop Head Unit. Untuk menyimulasikan data sensor saat menguji di Android Automotive OS, lihat bagian Meniru status hardware dalam panduan emulator Android Automotive OS.

Siklus proses CarAppService, Sesi, dan Layar

Class Session dan Screen mengimplementasikan antarmuka LifecycleOwner. Saat pengguna berinteraksi dengan aplikasi, callback siklus proses objek Session dan Screen akan dipanggil, seperti yang dijelaskan dalam diagram berikut.

Siklus proses CarAppService dan Sesi

Gambar 1. Siklus proses Session.

Untuk mengetahui detail selengkapnya, lihat dokumentasi untuk metode Session.getLifecycle.

Siklus proses Layar

Gambar 2. Siklus proses Screen.

Untuk detail selengkapnya, lihat dokumentasi untuk metode Screen.getLifecycle.

Rekam dari mikrofon mobil

Dengan menggunakan CarAppService dan CarAudioRecord API aplikasi, Anda dapat memberi aplikasi akses ke mikrofon mobil pengguna. Pengguna harus memberikan izin aplikasi Anda untuk mengakses mikrofon mobil. Aplikasi Anda dapat merekam dan memproses input pengguna dalam aplikasi.

Izin untuk merekam

Sebelum merekam audio, Anda harus mendeklarasikan izin untuk merekam di AndroidManifest.xml terlebih dahulu dan meminta pengguna untuk memberikannya.

<manifest ...>
   ...
   <uses-permission android:name="android.permission.RECORD_AUDIO" />
   ...
</manifest>

Anda harus meminta izin untuk merekam saat runtime. Lihat bagian Meminta izin untuk mengetahui detail tentang cara meminta izin di aplikasi mobil Anda.

Merekam audio

Setelah pengguna memberikan izin untuk merekam, Anda dapat merekam audio dan memproses rekaman.

Kotlin

val carAudioRecord = CarAudioRecord.create(carContext)
        carAudioRecord.startRecording()

        val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE)
        while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording()
 

Java

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        carAudioRecord.startRecording();

        byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE];
        while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording();
 

Fokus audio

Saat merekam dari mikrofon mobil, dapatkan terlebih dahulu fokus audio untuk memastikan media yang sedang berlangsung dihentikan. Jika Anda kehilangan fokus audio, berhenti merekam.

Berikut adalah contoh cara mendapatkan fokus audio:

Kotlin

 
val carAudioRecord = CarAudioRecord.create(carContext)
        
        // Take audio focus so that user's media is not recorded
        val audioAttributes = AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
            // Use the most appropriate usage type for your use case
            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
            .build()
        
        val audioFocusRequest =
            AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                .setAudioAttributes(audioAttributes)
                .setOnAudioFocusChangeListener { state: Int ->
                    if (state == AudioManager.AUDIOFOCUS_LOSS) {
                        // Stop recording if audio focus is lost
                        carAudioRecord.stopRecording()
                    }
                }
                .build()
        
        if (carContext.getSystemService(AudioManager::class.java)
                .requestAudioFocus(audioFocusRequest)
            != AudioManager.AUDIOFOCUS_REQUEST_GRANTED
        ) {
            // Don't record if the focus isn't granted
            return
        }
        
        carAudioRecord.startRecording()
        // Process the audio and abandon the AudioFocusRequest when done

Java

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        // Take audio focus so that user's media is not recorded
        AudioAttributes audioAttributes =
                new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        // Use the most appropriate usage type for your use case
                        .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
                        .build();

        AudioFocusRequest audioFocusRequest =
                new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                        .setAudioAttributes(audioAttributes)
                        .setOnAudioFocusChangeListener(state -> {
                            if (state == AudioManager.AUDIOFOCUS_LOSS) {
                                // Stop recording if audio focus is lost
                                carAudioRecord.stopRecording();
                            }
                        })
                        .build();

        if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest)
                != AUDIOFOCUS_REQUEST_GRANTED) {
            // Don't record if the focus isn't granted
            return;
        }

        carAudioRecord.startRecording();
        // Process the audio and abandon the AudioFocusRequest when done
 

Library Pengujian

Library Pengujian Android untuk Mobil menyediakan class tambahan yang dapat Anda gunakan untuk memvalidasi perilaku aplikasi dalam lingkungan pengujian. Misalnya, SessionController memungkinkan Anda melakukan simulasi koneksi ke host dan memastikan Screen dan Template yang tepat telah dibuat dan ditampilkan.

Lihat Contoh untuk mengetahui contoh penggunaan.

Melaporkan masalah Library Aplikasi Android untuk Mobil

Jika Anda menemukan masalah pada library, laporkan menggunakan Issue Tracker Google. Pastikan untuk mengisi semua informasi yang diminta pada template masalah.

Melaporkan masalah baru

Sebelum mengajukan masalah baru, periksa apakah masalah tersebut sudah tercantum dalam catatan rilis library atau dilaporkan dalam daftar masalah. Anda bisa berlangganan dan memberi suara pada masalah dengan mengklik bintang untuk masalah di tracker. Untuk mengetahui informasi selengkapnya, lihat Berlangganan pada topik Masalah.