Tạo và kiểm thử một ứng dụng đỗ xe dành cho Android Automotive OS: Hỗ trợ âm thanh khi lái xe

1. Trước khi bắt đầu

Không bao gồm

  • Hướng dẫn về cách tạo ứng dụng đa phương tiện (âm thanh, ví dụ: nhạc, đài phát, podcast) cho Android Auto và Android Automotive OS. Xem bài viết Tạo ứng dụng đa phương tiện cho ô tô để biết thông tin về cách tạo loại ứng dụng này.

Bạn cần có

Sản phẩm bạn sẽ tạo ra

Trong lớp học lập trình này, bạn sẽ tìm hiểu cách thêm tính năng hỗ trợ âm thanh khi lái xe trong Road Reels. Ứng dụng này hiện có hỗ trợ cả thiết bị di động và thiết bị chạy Android Automotive OS.

Phiên bản ban đầu sẽ tạm dừng phát khi có các hạn chế về trải nghiệm người dùng.

Phiên bản hoàn chỉnh của ứng dụng sẽ tiếp tục phát ngay cả khi có các hạn chế về trải nghiệm người dùng.

Kiến thức bạn sẽ học được

  • Cách bật tính năng phát âm thanh ở chế độ nền trong một ứng dụng video trên Android Automotive OS

2. Bắt đầu thiết lập

Lấy mã nguồn

  1. Bạn có thể tìm thấy đoạn mã dành cho lớp học lập trình này trong thư mục build-a-parked-app trong kho lưu trữ GitHub car-codelabs. Để sao chép đoạn mã đó, hãy chạy lệnh sau:
git clone https://github.com/android/car-codelabs.git
  1. Ngoài ra, bạn có thể tải kho lưu trữ ở dạng định dạng tệp ZIP:

Mở dự án

  • Sau khi chạy Android Studio, hãy nhập dự án, chỉ chọn thư mục build-a-parked-app/end. Thư mục build-a-parked-app/audio-while-driving chứa đoạn mã giải pháp mà bạn có thể tham khảo bất cứ lúc nào nếu gặp khó khăn hoặc đơn giản là xem toàn bộ dự án.

Làm quen với đoạn mã

  • Sau khi mở dự án trong Android Studio, hãy dành chút thời gian để xem qua đoạn mã khởi đầu.

3. Tìm hiểu về ứng dụng đỗ xe dành cho Android Automotive OS

Ứng dụng đỗ xe tạo thành một nhóm nhỏ các danh mục ứng dụng được Android Automotive OS hỗ trợ. Tại thời điểm viết bài, những danh mục này bao gồm các ứng dụng phát video trực tuyến, trình duyệt web và trò chơi. Đây là những ứng dụng phù hợp để dùng trong ô tô do phần cứng hiện có trên các phương tiện này được tích hợp sẵn Google và xe điện thì ngày càng phổ biến hơn. Do vậy, thời điểm xe sạc điện chính là lúc để lái xe và hành khách tương tác với những loại ứng dụng này.

Ô tô có nhiều điểm tương đồng với các thiết bị màn hình lớn khác như máy tính bảng và thiết bị có thể gập lại. Ô tô có màn hình cảm ứng với kích thước, độ phân giải và tỷ lệ khung hình tương tự, và có thể ở hướng dọc hoặc ngang (tuy nhiên, không giống như máy tính bảng, hướng của màn hình ô tô là cố định). Chúng cũng là những thiết bị được kết nối có thể có/không có kết nối mạng. Với tất cả những điều nêu trên, không có gì ngạc nhiên khi các ứng dụng vốn được tối ưu hoá cho màn hình lớn thường tốn ít công sức để mang lại trải nghiệm tuyệt vời cho người dùng trên ô tô.

Giống như màn hình lớn, cũng có các cấp độ chất lượng ứng dụng đối với những ứng dụng trên ô tô:

  • Cấp độ 3 – Dành cho ô tô: Ứng dụng của bạn tương thích với màn hình lớn và có thể dùng khi ô tô đang đỗ. Mặc dù ứng dụng này có thể không có tính năng nào được tối ưu hoá cho ô tô, nhưng người dùng vẫn có thể trải nghiệm ứng dụng giống như trên mọi thiết bị Android có màn hình lớn khác. Các ứng dụng di động đáp ứng những yêu cầu này sẽ đủ điều kiện được phân phối nguyên trạng cho ô tô thông qua chương trình Ứng dụng di động dành cho ô tô.
  • Cấp độ 2 – Được tối ưu hoá cho ô tô: Ứng dụng của bạn mang lại trải nghiệm tuyệt vời trên màn hình ngăn xếp trung tâm của ô tô. Để đạt được điều này, ứng dụng của bạn sẽ áp dụng kỹ thuật dành riêng cho ô tô để bao gồm các chức năng có thể dùng được ở chế độ lái xe hoặc đỗ xe, tuỳ thuộc vào danh mục ứng dụng của bạn.
  • Cấp độ 1 – Khác biệt theo loại ô tô: Ứng dụng của bạn được xây dựng để hoạt động trên nhiều loại phần cứng trong ô tô và có thể điều chỉnh trải nghiệm trong các chế độ lái xe và đỗ xe. Cấp độ này mang đến trải nghiệm tốt nhất cho người dùng, được thiết kế cho nhiều màn hình trong ô tô, chẳng hạn như bảng điều khiển trung tâm, cụm đồng hồ và các màn hình khác (như màn hình toàn cảnh trong nhiều loại ô tô hạng sang).

Trong lớp học lập trình này, bạn sẽ triển khai tính năng nghe nhạc khi lái xe (một tính năng cấp 1) để giúp ứng dụng trở thành một ứng dụng được thiết kế riêng cho xe ô tô.

4. Chạy ứng dụng trong trình mô phỏng Android Automotive OS

Cài đặt Automotive bằng hình ảnh Hệ thống Cửa hàng Play

  1. Trước tiên, hãy mở Trình quản lý SDK trong Android Studio rồi chọn thẻ SDK Platforms (Nền tảng SDK) nếu chưa chọn. Ở góc dưới bên phải của cửa sổ Trình quản lý SDK, hãy đảm bảo rằng hộp Show package details (Hiện thông tin về gói) được chọn.
  2. Cài đặt một trong những hình ảnh trình mô phỏng Android Automotive API 34 nêu trong phần Thêm hình ảnh hệ thống chung. Các hình ảnh hệ thống chỉ chạy được trên máy có cùng kiến trúc (x86/ARM) với chính chúng.

Tạo thiết bị Android ảo Android Automotive OS

  1. Sau khi mở Device Manager (Trình quản lý thiết bị), hãy chọn Automotive trong cột Category (Danh mục) ở bên trái cửa sổ. Sau đó, chọn cấu hình phần cứng theo cụm Automotive (1408p landscape) (Automotive (hướng ngang 1408 pixel)) trong danh sách rồi nhấp vào Next (Tiếp theo).

6a32a01404a7729f.png

  1. Trên trang tiếp theo, hãy chọn hình ảnh hệ thống ở bước trước. Nhấp vào Next (Tiếp theo) rồi chọn mọi tuỳ chọn nâng cao mà bạn muốn trước khi tạo AVD bằng cách nhấp vào Finish (Hoàn tất).

Chạy ứng dụng

Chạy ứng dụng trên trình mô phỏng bạn vừa tạo bằng cấu hình chạy app. Kiểm thử hành vi của ứng dụng bằng cách chuyển đến màn hình trình phát và mô phỏng hoạt động lái xe.

5. Phát hiện tính năng hỗ trợ âm thanh khi lái xe

Vì không phải xe nào cũng có tính năng hỗ trợ âm thanh khi lái xe, nên bạn cần tìm hiểu xem thiết bị hiện tại có hỗ trợ tính năng này hay không và điều chỉnh hành vi của ứng dụng cho phù hợp. Để làm việc này, bạn có thể sử dụng lớp CarFeatures trong thư viện androidx.car.app:app.

  1. Thêm một phần phụ thuộc vào cấu phần phần mềm androidx.car.app:app.

libs.version.toml

[versions]
...
carApp = "1.7.0-rc01"


[libraries]
...
androidx-car-app = { group = "androidx.car.app", name = "app", version.ref = "carApp" }

build.gradle.kts (Module :app)

implementation(libs.androidx.car.app)
  1. Sau đó, trong RoadReelsPlayer, bạn có thể xác định xem tính năng này có được hỗ trợ hay không và cập nhật logic dùng để tính giá trị của shouldPreventPlay.

RoadReelsPlayer.kt

if (packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
    ...

    val isBackgroundAudioWhileDrivingSupported = CarFeatures.isFeatureEnabled(
        context,
        CarFeatures.FEATURE_BACKGROUND_AUDIO_WHILE_DRIVING
    )

    shouldPreventPlay = !isBackgroundAudioWhileDrivingSupported &&
            carUxRestrictionsManager.currentCarUxRestrictions.isRequiresDistractionOptimization
    invalidateState()

    carUxRestrictionsManager.registerListener { carUxRestrictions: CarUxRestrictions ->
        shouldPreventPlay = !isBackgroundAudioWhileDrivingSupported &&
            carUxRestrictions.isRequiresDistractionOptimization
        ...
    }
}

Chạy lại ứng dụng khi có những thay đổi này và mô phỏng việc lái xe. Lưu ý rằng âm thanh giờ đây vẫn tiếp tục phát ngay cả khi giao diện người dùng của ứng dụng bị hệ thống che khuất. Tuy nhiên, bạn vẫn chưa xong đâu – để đáp ứng tất cả các yêu cầu, bạn cần thực hiện thêm một vài thay đổi nữa.

6. Hỗ trợ chế độ phát trong nền

Hiện tại, hoạt động phát nội dung nghe nhìn của ứng dụng được một hoạt động xử lý. Do đó, quá trình phát nội dung nghe nhìn có thể tiếp tục trong một khoảng thời gian ngắn sau khi có các hạn chế về trải nghiệm người dùng và hoạt động bị che khuất, nhưng cuối cùng, ứng dụng của bạn sẽ được hệ thống lưu vào bộ nhớ đệm khiến quá trình phát bị dừng.

Để hỗ trợ chế độ phát trong thời gian dài, ứng dụng phải được cập nhật để sử dụng một dịch vụ giúp xử lý hoạt động phát. Media3 MediaSessionService có thể giúp bạn làm được điều này.

Tạo MediaSessionService

  1. Nhấp chuột phải vào gói com.example.android.cars.roadreels trong cửa sổ Project (Dự án) rồi chọn New (Mới) > Kotlin Class/File (Lớp/tệp Kotlin). Nhập PlaybackService làm tên tệp và nhấp vào loại Class (Lớp).
  2. Thêm cách triển khai PlaybackService. sau đây. Hãy xem phần Phát trong nền bằng MediaSessionService để biết thêm thông tin về MediaSessionService.

PlaybackService.kt

import androidx.media3.common.util.UnstableApi
import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService

@UnstableApi
class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    override fun onCreate() {
        super.onCreate()
        val player = RoadReelsPlayer(this)
        mediaSession = MediaSession.Builder(this, player).build()
    }

    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }

    override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
        if (controllerInfo.isTrusted || controllerInfo.packageName == packageName) {
            return mediaSession
        }
        return null
    }
}
  1. Thêm các phần tử <uses-permission> sau đây vào tệp kê khai. Hoạt động phát nội dung nghe nhìn được xử lý bằng một dịch vụ trên nền trước

AndroidManifest.xml

<manifest ...>
    ...
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
    ...
</manifest>
  1. Đồng thời, hãy khai báo PlaybackService trong tệp kê khai:

AndroidManifest.xml

<application ...>
    ...
    <service
        android:name=".PlaybackService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="true">
        <intent-filter>
            <action android:name="androidx.media3.session.MediaSessionService"/>
        </intent-filter>
    </service>
</application>

Cập nhật PlayerViewModel để dùng PlaybackService

  1. PlaybackService tự tạo và hiển thị MediaSession, nên PlayerViewModel không cần tạo nữa. Tìm và xoá dòng sau cùng với tất cả các tệp tham chiếu đến biến:

PlayerViewModel.kt

private var mediaSession: MediaSession? = null
  1. Tiếp theo, hãy thay thế phần thuộc khối init giúp tạo thực thể RoadReelsPlayer bằng mã sau đây để kết nối ứng dụng với PlaybackService bằng MediaController.

PlayerViewModel.kt

import android.content.ComponentName
import androidx.media3.session.MediaController
import androidx.media3.session.SessionToken
import com.example.android.cars.roadreels.PlaybackService
import com.google.common.util.concurrent.MoreExecutors

...

init {
        viewModelScope.launch {
            ...
        }
        
        val sessionToken = SessionToken(
            application,
            ComponentName(application, PlaybackService::class.java)
        )

        val mediaControllerFuture =
            MediaController.Builder(getApplication(), sessionToken).buildAsync()

        mediaControllerFuture.addListener(
            { _player.update { mediaControllerFuture.get() } },
            MoreExecutors.directExecutor()
        )
    }

Kiểm thử lại ứng dụng và bạn sẽ thấy một giao diện người dùng khác xuất hiện khi hệ thống chặn ứng dụng. Giờ đây, người dùng có thể điều khiển chế độ phát trong khi di chuyển. Và khi dừng lại, họ có thể nhấp vào nút thoát để quay lại trải nghiệm đầy đủ trong ứng dụng.

33eb8ff3d4035978.gif

Xoá các thay đổi về chế độ phát trong vòng đời

Vì tính năng phát trong nền hiện được hỗ trợ, nên bạn có thể xoá 2 khối LifecycleEventEffect trong PlayerScreen.kt để quá trình phát có thể tiếp tục khi người dùng rời khỏi ứng dụng, bao gồm cả khi các nút điều khiển phát hiển thị trong màn hình trước.

Tạm dừng phát khi rời khỏi màn hình trình phát

Vì trình phát thực tế (hiện nằm trong PlaybackService) không được đóng khi rời khỏi màn hình trình phát, nên bạn cần thêm lệnh gọi để tạm dừng quá trình phát khi rời khỏi trình phát để duy trì hành vi trước. Để làm việc này, bạn có thể cập nhật cách triển khai phương thức onCleared của PlayerViewModel:

PlayerViewModel.kt

override fun onCleared() {
    super.onCleared()
    _player.value?.apply {
        pause()
        release()
    }
}

7. Cập nhật tệp kê khai

Cuối cùng, để cho biết ứng dụng của bạn có hỗ trợ âm thanh khi lái xe, bạn cần thêm phần tử <uses-feature> sau đây vào tệp kê khai của ứng dụng.

AndroidManifest.xml

<application>
    <uses-feature android:name="com.android.car.background_audio_while_driving" android:required="false">
</application>

8. Xin chúc mừng

Bạn đã thêm thành công tính năng hỗ trợ phát âm thanh khi lái xe vào một ứng dụng video. Bây giờ là lúc áp dụng kiến thức đã học vào ứng dụng của riêng bạn!

Tài liệu đọc thêm