Thư viện ứng dụng Android cho Ô tô cho phép bạn mang các ứng dụng điều hướng, địa điểm yêu thích (POI) và Internet của vạn vật (IOT) lên ô tô. Thư viện này cung cấp một bộ mẫu được thiết kế để đáp ứng các tiêu chuẩn về sự phân tâm của người lái xe, đồng thời quan tâm đến những chi tiết như sự đa dạng của các yếu tố trên màn hình ô tô và phương thức đầu vào.
Hướng dẫn này cung cấp thông tin tổng quan về các tính năng và khái niệm chính của thư viện, đồng thời hướng dẫn bạn qua quy trình thiết lập một ứng dụng đơn giản. Để biết phần giới thiệu từng bước đầy đủ, hãy xem lớp học lập trình Tìm hiểu kiến thức cơ bản về Thư viện ứng dụng cho ô tô.
Trước khi bắt đầu
- Xem các trang Design for Driving (Design cho hoạt động lái xe) bao gồm Thư viện ứng dụng cho ô tô
- Tổng quan về danh mục Ứng dụng điều hướng và Các ứng dụng khác liên quan đến hoạt động lái xe
- Tổng quan về Tạo ứng dụng bằng mẫu
- Thành phần bao gồm Mẫu và Các thành phần mẫu
- Luồng mẫu minh hoạ các mẫu trải nghiệm người dùng thường gặp
- Yêu cầu về ứng dụng theo mẫu
- Xem các thuật ngữ và khái niệm chính trong phần sau.
- Làm quen với Giao diện người dùng hệ thống Android Auto và mẫu thiết kế Android Automotive OS.
- Xem phần Ghi chú phát hành.
- Xem phần Ứng dụng mẫu.
Các thuật ngữ và khái niệm chính
- Mô hình và mẫu
- Giao diện người dùng được biểu thị bằng một biểu đồ gồm các đối tượng mô hình có thể được sắp xếp cùng nhau theo nhiều cách, tuỳ theo mẫu chứa chúng cho phép. Mẫu là một tập hợp con gồm các mô hình có thể đóng vai trò là gốc trong các biểu đồ đó. Mô hình bao gồm thông tin sẽ hiển thị với người dùng dưới dạng văn bản và hình ảnh, cũng như các thuộc tính để định cấu hình các khía cạnh về giao diện của thông tin đó, ví dụ: màu văn bản hoặc kích thước hình ảnh. Máy chủ lưu trữ chuyển đổi các mô hình thành những khung hiển thị được thiết kế để đáp ứng các tiêu chuẩn về sự phân tâm của người lái xe, đồng thời quan tâm đến những chi tiết như sự đa dạng của các yếu tố trên màn hình ô tô và phương thức đầu vào.
- Máy chủ lưu trữ
- Máy chủ lưu trữ là thành phần phụ trợ giúp triển khai chức năng do API của thư viện cung cấp để ứng dụng của bạn có thể chạy trên ô tô. Máy chủ lưu trữ đảm nhận nhiều trách nhiệm, từ việc khám phá ứng dụng và quản lý vòng đời của ứng dụng cho đến việc chuyển đổi mô hình thành khung hiển thị, cũng như thông báo cho ứng dụng về hoạt động tương tác của người dùng. Trên các thiết bị di động, máy chủ lưu trữ này được Android Auto triển khai. Trên Android Automotive OS, máy chủ lưu trữ này được cài đặt dưới dạng một ứng dụng hệ thống.
- Các hạn chế khi dùng mẫu
- Các mẫu khác nhau thực thi các hạn chế về nội dung trong mô hình của chúng. Ví dụ: mẫu dạng danh sách có giới hạn về số lượng mục có thể hiển thị với người dùng. Các mẫu cũng có những hạn chế về cách kết nối để tạo thành luồng nhiệm vụ. Ví dụ: ứng dụng chỉ có thể đẩy tối đa 5 mẫu vào ngăn xếp màn hình. Hãy xem phần Các hạn chế khi dùng mẫu để biết thêm thông tin.
Screen
Screen
là một lớp do thư viện cung cấp. Đây chính là lớp mà các ứng dụng triển khai để quản lý giao diện người dùng được hiển thị với người dùng. MộtScreen
có một vòng đời và cung cấp cơ chế để ứng dụng gửi mẫu cần hiển thị khi người dùng nhìn thấy màn hình. Bạn cũng có thể đẩy và kéo các thực thểScreen
đến và từ một ngăn xếpScreen
. Điều này đảm bảo các thực thể đó tuân thủ các hạn chế về luồng mẫu.CarAppService
CarAppService
là một lớpService
trừu tượng mà ứng dụng của bạn phải triển khai và xuất để được máy chủ lưu trữ khám phá và quản lý.CarAppService
của ứng dụng chịu trách nhiệm xác thực rằng kết nối của máy chủ lưu trữ có thể tin cậy được bằng cách sử dụngcreateHostValidator
và sau đó cung cấp các thực thểSession
cho từng kết nối bằngonCreateSession
.Session
Session
là một lớp trừu tượng mà ứng dụng của bạn phải triển khai và trả về bằngCarAppService.onCreateSession
. Lớp này đóng vai trò là điểm vào để hiển thị thông tin trên màn hình ô tô. Nó có vòng đời thông báo trạng thái hiện tại của ứng dụng trên màn hình ô tô, chẳng hạn như thời điểm ứng dụng hiển thị hoặc bị ẩn.Khi
Session
khởi động, chẳng hạn như khi ứng dụng chạy lần đầu tiên, máy chủ lưu trữ yêu cầuScreen
ban đầu hiển thị bằng phương thứconCreateScreen
.
Cài đặt Thư viện ứng dụng cho ô tô
Xem trang phát hành thư viện Jetpack để biết hướng dẫn về cách thêm thư viện vào ứng dụng của bạn.
Định cấu hình tệp kê khai của ứng dụng
Trước khi bạn có thể tạo ứng dụng cho ô tô, hãy định cấu hình tệp kê khai của ứng dụng như sau.
Khai báo CarAppService
Máy chủ lưu trữ kết nối ứng dụng của bạn thông qua quá trình triển khai CarAppService
. Bạn khai báo dịch vụ này trong tệp kê khai của mình để cho phép máy chủ lưu trữ khám phá và kết nối với ứng dụng của bạn.
Bạn cũng cần khai báo danh mục ứng dụng của mình trong phần tử <category>
trong bộ lọc ý định của ứng dụng. Xem danh sách các danh mục ứng dụng được hỗ trợ để biết các giá trị được phép cho phần tử này.
Đoạn mã sau đây cho biết cách khai báo dịch vụ ứng dụng ô tô cho ứng dụng địa điểm yêu thích trong tệp kê khai của bạn:
<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>
Danh mục ứng dụng được hỗ trợ
Khai báo danh mục ứng dụng của bạn bằng cách thêm một hoặc nhiều giá trị cho danh mục sau vào bộ lọc ý định khi bạn khai báo CarAppService
của mình như được mô tả trong phần trước:
androidx.car.app.category.NAVIGATION
: một ứng dụng cung cấp thông tin chỉ đường từng chặng. Hãy xem phần Tạo ứng dụng chỉ đường cho ô tô để biết thêm tài liệu về danh mục này.androidx.car.app.category.POI
: một ứng dụng cung cấp chức năng liên quan đến việc tìm kiếm các địa điểm yêu thích như điểm đỗ xe, trạm sạc và trạm xăng. Hãy xem phần Tạo ứng dụng địa điểm yêu thích cho ô tô để biết thêm tài liệu về danh mục này.androidx.car.app.category.IOT
: Một ứng dụng cho phép người dùng thực hiện các thao tác liên quan trên các thiết bị thông minh ngay trên ô tô. Hãy xem phần Tạo ứng dụng Internet của vạn vật cho ô tô để biết thêm tài liệu về danh mục này.
Hãy xem phần Chất lượng ứng dụng Android cho ô tô để biết nội dung mô tả chi tiết của từng danh mục và tiêu chí xếp ứng dụng vào các danh mục đó.
Chỉ định tên và biểu tượng ứng dụng
Bạn cần chỉ định tên và biểu tượng ứng dụng mà máy chủ lưu trữ có thể dùng để biểu thị ứng dụng của bạn trong giao diện người dùng hệ thống.
Bạn có thể chỉ định tên và biểu tượng ứng dụng dùng để biểu thị ứng dụng của bạn bằng cách dùng thuộc tính label
và icon
trong CarAppService
:
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
Nếu nhãn hoặc biểu tượng không được khai báo trong phần tử <service>
, máy chủ lưu trữ sẽ quay lại dùng các giá trị được chỉ định cho phần tử <application>
.
Đặt giao diện tuỳ chỉnh
Để đặt giao diện tuỳ chỉnh cho ứng dụng dành cho ô tô, hãy thêm phần tử <meta-data>
vào tệp kê khai của bạn như sau:
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
Sau đó, khai báo tài nguyên kiểu để đặt các thuộc tính sau đây cho giao diện tuỳ chỉnh của ứng dụng dành cho ô tô:
<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>
Cấp độ Car App API (API Ứng dụng dành cho ô tô)
Thư viện ứng dụng cho ô tô xác định các cấp độ API riêng để bạn có thể biết tính năng nào của thư viện được máy chủ lưu trữ mẫu trên xe hỗ trợ.
Để truy xuất Cấp độ Car App API cao nhất được máy chủ lưu trữ hỗ trợ, hãy sử dụng phương thức getCarAppApiLevel()
.
Khai báo Cấp độ Car App API thấp nhất được ứng dụng của bạn hỗ trợ trong tệp AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
Xem tài liệu liên quan đến chú giải RequiresCarApi
để biết chi tiết về cách duy trì khả năng tương thích ngược và khai báo cấp độ API thấp nhất cần thiết để sử dụng một tính năng. Để biết định nghĩa về cấp độ API nào cần cho việc sử dụng một tính năng nhất định của Thư viện ứng dụng cho ô tô, hãy xem tài liệu tham khảo về CarAppApiLevels
.
Tạo CarAppService và Phiên của bạn
Ứng dụng của bạn cần mở rộng lớp CarAppService
và triển khai phương thức onCreateSession
của lớp để trả về thực thể Session
tương ứng với kết nối hiện tại đến máy chủ lưu trữ:
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(); } ... }
Thực thể Session
chịu trách nhiệm trả về thực thể Screen
để dùng trong lần đầu tiên khởi động ứng dụng:
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()); } ... }
Để xử lý các tình huống trong đó ứng dụng mà bạn tạo cho ô tô cần khởi động từ một màn hình không phải là màn hình chính hoặc màn hình đích của ứng dụng, chẳng hạn như xử lý các đường liên kết sâu, bạn có thể chuẩn bị trước một ngăn xếp lui của các màn hình bằng cách sử dụng ScreenManager.push
trước khi quay lại từ onCreateScreen
.
Khi bạn chuẩn bị trước một ngăn xếp lui, người dùng có thể từ màn hình đầu tiên mà ứng dụng của bạn đang hiển thị quay lại các màn hình trước đó.
Tạo màn hình bắt đầu
Bạn tạo các màn hình do ứng dụng của bạn hiển thị bằng cách xác định các lớp mở rộng lớp Screen
, đồng thời triển khai phương thức onGetTemplate
của lớp để trả về thực thể Template
biểu thị trạng thái của giao diện người dùng cần hiển thị trên màn hình ô tô.
Đoạn mã sau đây cho biết cách khai báo Screen
sử dụng một mẫu PaneTemplate
để hiển thị chuỗi "Hello world!":
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(); } }
Lớp CarContext
Lớp CarContext
là một lớp con ContextWrapper
có thể truy cập vào thực thể Session
và Screen
của bạn. Lớp này cung cấp quyền truy cập vào các dịch vụ dành cho ô tô, chẳng hạn như ScreenManager
để quản lý ngăn xếp màn hình; AppManager
cho chức năng chung liên quan đến ứng dụng (chẳng hạn như truy cập vào đối tượng Surface
để vẽ bản đồ của ứng dụng chỉ đường); và NavigationManager
được các ứng dụng chỉ đường từng chặng sử dụng để truyền đạt siêu dữ liệu chỉ đường cũng như các sự kiện khác liên quan đến việc chỉ đường với máy chủ lưu trữ.
Hãy xem phần Truy cập vào mẫu chỉ đường để biết danh sách đầy đủ chức năng của thư viện có sẵn cho các ứng dụng chỉ đường.
CarContext
cũng cung cấp chức năng khác, chẳng hạn như cho phép bạn dùng cấu hình từ màn hình ô tô để tải tài nguyên có thể vẽ, dùng các ý định để khởi động một ứng dụng trên ô tô, đồng thời cho biết liệu ứng dụng chỉ đường của bạn có nên hiển thị bản đồ ở chế độ tối hay không.
Triển khai hoạt động chỉ đường trên màn hình
Các ứng dụng thường hiển thị một số màn hình khác nhau, mỗi màn hình có thể sử dụng các mẫu khác nhau mà người dùng có thể điều hướng khi tương tác với giao diện hiển thị trên màn hình.
Lớp ScreenManager
mang đến một ngăn xếp màn hình giúp bạn đẩy các màn hình có thể bật tự động khi người dùng chọn nút quay lại trên màn hình ô tô hoặc sử dụng nút quay lại phần cứng hiện có trong một số mẫu ô tô.
Đoạn mã sau đây cho biết cách thêm thao tác quay lại vào tin nhắn mẫu, cũng như thao tác đẩy một màn hình mới khi được người dùng chọn:
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();
Đối tượng Action.BACK
là một Action
tiêu chuẩn sẽ tự động gọi ScreenManager.pop
.
Bạn có thể dùng thực thể OnBackPressedDispatcher
trong CarContext
để ghi đè hành vi này.
Để giúp đảm bảo ứng dụng an toàn khi sử dụng trong quá trình lái xe, ngăn xếp màn hình có thể có độ sâu tối đa là 5 màn hình. Hãy xem phần Các hạn chế khi dùng mẫu để biết thêm thông tin chi tiết.
Làm mới nội dung của một mẫu
Ứng dụng của bạn có thể yêu cầu vô hiệu hoá nội dung của một Screen
bằng cách gọi phương thức Screen.invalidate
.
Sau đó, máy chủ lưu trữ sẽ gọi lại phương thức Screen.onGetTemplate
của ứng dụng để truy xuất mẫu có nội dung mới.
Khi làm mới Screen
, bạn phải hiểu rằng có thể cập nhật nội dung cụ thể trong mẫu đó để máy chủ lưu trữ không tính mẫu mới vào hạn mức mẫu.
Hãy xem phần Các hạn chế khi dùng mẫu để biết thêm thông tin.
Bạn nên cấu trúc các màn hình sao cho có mối liên kết một với một giữa Screen
và kiểu mẫu trả về thông qua quá trình triển khai onGetTemplate
.
Tương tác với người dùng
Ứng dụng của bạn có thể tương tác với người dùng bằng các mẫu tương tự như ứng dụng di động.
Xử lý hoạt động đầu vào của người dùng
Ứng dụng của bạn có thể phản hồi hoạt động đầu vào của người dùng bằng cách chuyển các trình nghe thích hợp đến các mô hình hỗ trợ chúng. Đoạn mã sau đây cho biết cách tạo một mô hình Action
sẽ đặt OnClickListener
để gọi lại phương thức do mã của ứng dụng xác định:
Kotlin
val action = Action.Builder() .setTitle("Navigate") .setOnClickListener(::onClickNavigate) .build()
Java
Action action = new Action.Builder() .setTitle("Navigate") .setOnClickListener(this::onClickNavigate) .build();
Sau đó, phương thức onClickNavigate
có thể khởi động ứng dụng chỉ đường mặc định trên ô tô bằng cách dùng phương thức 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); }
Để biết thêm thông tin về cách khởi động các ứng dụng, bao gồm cả hình thức của ý định ACTION_NAVIGATE
, hãy xem phần Khởi động ứng dụng dành cho ô tô bằng ý định.
Một số thao tác, chẳng hạn như các thao tác yêu cầu hướng dẫn người dùng tiếp tục tương tác trên các thiết bị di động của họ, chỉ được phép thực hiện khi ô tô đã đỗ.
Bạn có thể dùng ParkedOnlyOnClickListener
để triển khai các thao tác đó. Nếu ô tô chưa đỗ, máy chủ lưu trữ sẽ hiển thị một chỉ báo cho người dùng biết rằng thao tác đó không được phép thực hiện trong trường hợp này. Nếu ô tô đang đỗ, mã sẽ thực thi bình thường. Đoạn mã sau cho biết cách sử dụng ParkedOnlyOnClickListener
để mở một màn hình cài đặt trên thiết bị di động:
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();
Hiện thông báo
Các thông báo gửi đến thiết bị di động chỉ hiện trên màn hình ô tô nếu chúng được mở rộng bằng CarAppExtender
.
Bạn có thể đặt một số thuộc tính của thông báo như tiêu đề nội dung, văn bản, biểu tượng và thao tác trong CarAppExtender
. Những thuộc tính này sẽ ghi đè các thuộc tính của thông báo đó khi chúng xuất hiện trên màn hình ô tô.
Đoạn mã sau đây cho biết cách gửi một thông báo tới màn hình ô tô hiển thị một tiêu đề khác với tiêu đề hiện trên thiết bị di động:
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();
Thông báo có thể ảnh hưởng đến các phần sau trên giao diện người dùng:
- Thông báo quan trọng (HUN) có thể hiển thị với người dùng.
- Bạn có thể thêm mục nhập trong trung tâm thông báo theo tuỳ ý với huy hiệu hiển thị trên thanh thông báo.
- Đối với các ứng dụng chỉ đường, thông báo có thể hiển thị trong tiện ích thanh thông báo như mô tả trong phần Thông báo từng chặng.
Bạn có thể chọn cách định cấu hình các thông báo của ứng dụng để tác động đến từng phần tử trong các phần tử giao diện người dùng đó bằng cách sử dụng mức độ ưu tiên của thông báo như mô tả trong tài liệu CarAppExtender
.
Nếu NotificationCompat.Builder.setOnlyAlertOnce
được gọi với giá trị true
, thì thông báo có mức độ ưu tiên cao chỉ hiển thị dưới dạng HUN một lần.
Để biết thêm thông tin về cách thiết kế các thông báo của ứng dụng dành cho ô tô, hãy xem phần Thông báo trên Google Design for Driving (Google Design cho hoạt động lái xe).
Hiện thông báo ngắn
Ứng dụng của bạn có thể hiện một thông báo ngắn bằng CarToast
như trong đoạn mã này:
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
Yêu cầu cấp quyền
Nếu ứng dụng của bạn cần quyền truy cập vào dữ liệu hoặc thao tác bị hạn chế, chẳng hạn như thông tin vị trí, thì các quy tắc chuẩn về quyền trên Android sẽ được áp dụng. Để yêu cầu quyền, bạn có thể sử dụng phương thức CarContext.requestPermissions()
.
Trên Android Auto, hộp thoại cấp quyền cho người dùng sẽ xuất hiện trên điện thoại.
Theo mặc định, sẽ không có nền phía sau hộp thoại đó. Để đặt nền tuỳ chỉnh, hãy khai báo giao diện ứng dụng dành cho ô tô trong tệp AndroidManifest.xml
rồi đặt thuộc tính carPermissionActivityLayout
cho giao diện ứng dụng dành cho ô tô của bạn.
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
Sau đó, đặt thuộc tính carPermissionActivityLayout
cho giao diện ứng dụng dành cho ô tô:
<resources> <style name="MyCarAppTheme"> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
Trái với việc sử dụng API Android chuẩn, khi sử dụng CarContext.requestPermissions()
, bạn không cần chạy Activity
của riêng mình để tạo hộp thoại cấp quyền. Hơn nữa, bạn có thể dùng cùng một mã trên cả Android Auto và Android Automotive OS, thay vì phải tạo các luồng phụ thuộc vào nền tảng.
Khởi động ứng dụng dành cho ô tô bằng ý định
Bạn có thể gọi phương thức CarContext.startCarApp
để thực hiện một trong các thao tác sau:
- Mở trình quay số để gọi điện thoại.
- Bắt đầu chỉ đường từng chặng đến một vị trí bằng ứng dụng chỉ đường mặc định trên ô tô.
- Khởi động ứng dụng của riêng bạn bằng ý định.
Ví dụ sau đây cho biết cách tạo thông báo bằng thao tác mở ứng dụng của bạn với màn hình hiển thị chi tiết về việc đặt chỗ đỗ xe.
Bạn mở rộng bản sao thông báo bằng ý định nội dung chứa PendingIntent
gói ý định tường minh cho thao tác của ứng dụng:
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());
Ứng dụng của bạn cũng phải khai báo một BroadcastReceiver
được gọi để xử lý ý định khi người dùng chọn thao tác trong giao diện thông báo và gọi CarContext.startCarApp
với ý định bao gồm URI của dữ liệu:
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))); } } }
Cuối cùng, phương thức Session.onNewIntent
trong ứng dụng của bạn xử lý ý định này bằng cách đẩy màn hình đặt chỗ đỗ xe lên ngăn xếp, nếu màn hình này chưa ở trên cùng:
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())); } } }
Hãy xem phần Hiện thông báo để biết thêm thông tin về cách xử lý các thông báo đối với ứng dụng dành cho ô tô.
Các hạn chế khi dùng mẫu
Máy chủ lưu trữ giới hạn số lượng mẫu hiển thị cho một tác vụ nhất định ở mức tối đa là 5 mẫu, trong đó mẫu cuối cùng phải là một trong các kiểu sau:
Lưu ý rằng giới hạn này áp dụng cho số lượng mẫu chứ không phải số lượng thực thể Screen
trong ngăn xếp. Ví dụ: nếu một ứng dụng gửi 2 mẫu khi ở màn hình A rồi đẩy màn hình B thì giờ đây ứng dụng đó có thể gửi thêm 3 mẫu nữa. Ngoài ra, nếu mỗi màn hình được cấu trúc để gửi một mẫu duy nhất, thì ứng dụng đó có thể đẩy 5 thực thể màn hình vào ngăn xếp ScreenManager
.
Những hạn chế này có các trường hợp đặc biệt như: làm mới mẫu, thao tác quay lại và đặt lại.
Làm mới mẫu
Một số cập nhật nội dung nhất định không được tính vào giới hạn mẫu. Nói chung, nếu một ứng dụng đẩy một mẫu mới cùng kiểu và chứa cùng nội dung chính với mẫu trước đó thì mẫu mới sẽ không được tính vào hạn mức. Ví dụ: việc cập nhật trạng thái chuyển đổi của một hàng trong ListTemplate
không được tính vào hạn mức. Hãy xem tài liệu về từng mẫu để tìm hiểu thêm về những kiểu cập nhật nội dung có thể được coi là làm mới.
Thao tác quay lại
Để kích hoạt các luồng phụ trong một nhiệm vụ, máy chủ lưu trữ sẽ phát hiện thời điểm một ứng dụng bật Screen
từ ngăn xếp ScreenManager
, đồng thời cập nhật hạn mức còn lại dựa trên số lượng mẫu mà ứng dụng đang lùi lại.
Ví dụ: nếu ứng dụng gửi 2 mẫu khi ở màn hình A, sau đó đẩy màn hình B và gửi thêm 2 mẫu nữa, thì ứng dụng còn lại một hạn mức. Sau đó, nếu ứng dụng quay lại màn hình A, máy chủ lưu trữ sẽ đặt lại hạn mức thành 3 vì ứng dụng đã lùi lại 2 mẫu.
Lưu ý rằng, khi quay lại một màn hình, ứng dụng phải gửi mẫu cùng kiểu với mẫu được màn hình đó gửi lần cuối. Việc gửi bất kỳ kiểu mẫu nào khác đều gây ra lỗi. Tuy nhiên, miễn là kiểu đó vẫn giữ nguyên trong thao tác quay lại, thì ứng dụng có thể tự do sửa đổi nội dung của mẫu mà không ảnh hưởng đến hạn mức.
Thao tác đặt lại
Một số mẫu nhất định có ngữ nghĩa đặc biệt biểu thị việc kết thúc một nhiệm vụ. Ví dụ: NavigationTemplate
là một khung hiển thị dự kiến sẽ ở lại màn hình đó và được làm mới bằng các hướng dẫn từng chặng mới để người dùng sử dụng. Khi đạt đến một trong các mẫu này, máy chủ lưu trữ sẽ đặt lại hạn mức mẫu, xử lý mẫu đó như thể đó là bước đầu tiên của một nhiệm vụ mới. Điều này cho phép ứng dụng bắt đầu một nhiệm vụ mới.
Hãy xem tài liệu về từng mẫu để biết mẫu nào kích hoạt thao tác đặt lại trên máy chủ lưu trữ.
Nếu máy chủ nhận được một ý định khởi động ứng dụng từ thao tác thông báo hoặc từ trình chạy thì hạn mức cũng được đặt lại. Cơ chế này cho phép ứng dụng bắt đầu một luồng nhiệm vụ mới từ thông báo và cơ chế này vẫn đúng ngay cả khi ứng dụng đã bị ràng buộc và ở nền trước.
Hãy xem phần Hiện thông báo để biết thêm thông tin về cách hiện thông báo của ứng dụng trên màn hình ô tô. Hãy xem phần Khởi động ứng dụng dành cho ô tô bằng ý định để biết thông tin về cách khởi động ứng dụng của bạn từ thao tác thông báo.
API Kết nối
Bạn có thể xác định xem ứng dụng của mình đang chạy trên Android Auto hay Android Automotive OS bằng cách sử dụng API CarConnection
để truy xuất thông tin kết nối trong thời gian chạy.
Ví dụ: trong Session
của ứng dụng dành cho ô tô, hãy khởi chạy CarConnection
và đăng ký nhận bản cập nhật LiveData
:
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
Sau đó, trong trình quan sát, bạn có thể phản ứng với các thay đổi về trạng thái kết nối:
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 (API Giới hạn)
Nhiều loại ô tô có thể cho phép hiển thị số lượng thực thể Item
khác nhau cho người dùng tại một thời điểm. Hãy dùng ConstraintManager
để kiểm tra giới hạn nội dung trong thời gian chạy và đặt số lượng mục thích hợp trong mẫu của bạn.
Hãy bắt đầu bằng cách nhận ConstraintManager
từ CarContext
:
Kotlin
val manager = carContext.getCarService(ConstraintManager::class.java)
Java
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);
Sau đó, bạn có thể truy vấn đối tượng ConstraintManager
được truy xuất để biết giới hạn nội dung liên quan. Ví dụ: để nhận được số mục có thể hiển thị trong một lưới, hãy gọi getContentLimit
bằng CONTENT_LIMIT_TYPE_GRID
:
Kotlin
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
Java
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
Thêm một quy trình đăng nhập
Nếu ứng dụng của bạn cung cấp trải nghiệm đăng nhập cho người dùng, bạn có thể sử dụng các mẫu như SignInTemplate
và LongMessageTemplate
với Car App API (API Ứng dụng dành cho ô tô) cấp 2 trở lên để xử lý việc đăng nhập vào ứng dụng trên đầu phát trung tâm của ô tô.
Để tạo một SignInTemplate
, hãy xác định SignInMethod
. Thư viện ứng dụng cho ô tô hiện hỗ trợ các phương thức đăng nhập sau:
InputSignInMethod
để đăng nhập bằng tên người dùng/mật khẩu.PinSignInMethod
để đăng nhập bằng mã PIN, trong đó người dùng liên kết tài khoản của họ từ điện thoại bằng mã PIN hiện trên đầu phát trung tâm.ProviderSignInMethod
để đăng nhập thông qua nhà cung cấp, chẳng hạn như Đăng nhập bằng Google và Một lần chạm.QRCodeSignInMethod
để đăng nhập bằng mã QR, trong đó người dùng quét một mã QR để hoàn tất quy trình đăng nhập trên điện thoại của họ. Phương thức này sử dụng được với API Ô tô cấp 4 trở lên.
Ví dụ: để triển khai một mẫu thu thập mật khẩu của người dùng, hãy bắt đầu bằng cách tạo InputCallback
để xử lý và xác thực hoạt động đầu vào của người dùng:
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. } };
Cần có InputCallback
cho 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();
Cuối cùng, hãy sử dụng InputSignInMethod
mới của bạn để tạo 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();
Sử dụng AccountManager
Các ứng dụng trên Android Automotive OS có trình xác thực thì phải sử dụng AccountManager vì những lý do sau:
- Trải nghiệm người dùng tốt hơn và dễ dàng quản lý tài khoản: Người dùng có thể dễ dàng quản lý tất cả tài khoản của họ trên trình đơn tài khoản trong phần cài đặt hệ thống, bao gồm cả hoạt động đăng nhập và đăng xuất.
- Trải nghiệm "khách": Vì ô tô là thiết bị dùng chung, nên các OEM có thể cung cấp trải nghiệm khách trong xe khi không thể thêm tài khoản.
Thêm các biến thể chuỗi văn bản
Kích thước màn hình ô tô khác nhau có thể hiện lượng văn bản khác nhau. Với Car App API (API Ứng dụng dành cho ô tô) cấp 2 trở lên, bạn có thể chỉ định nhiều biến thể của một chuỗi văn bản để phù hợp nhất với màn hình. Để biết các biến thể văn bản được chấp nhận ở nơi nào, hãy tìm các mẫu và thành phần có CarText
.
Bạn có thể thêm các biến thể chuỗi văn bản vào CarText
bằng phương thức 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();
Sau đó, bạn có thể sử dụng CarText
này chẳng hạn làm văn bản chính của GridItem
.
Kotlin
GridItem.Builder() .addTitle(itemTitle) ... .build()
Java
new GridItem.Builder() .addTitle(itemTitle) ... build();
Thêm các chuỗi theo thứ tự từ được ưa thích nhất đến ít được ưa thích nhất, ví dụ: từ dài nhất đến ngắn nhất. Máy chủ lưu trữ chọn chuỗi có độ dài thích hợp tuỳ theo khoảng không gian hiện có trên màn hình ô tô.
Thêm các biểu tượng ô tô cùng dòng cho các hàng
Bạn có thể thêm các biểu tượng cùng dòng với văn bản để giúp ứng dụng của mình trở nên bắt mắt thông qua CarIconSpan
.
Hãy xem tài liệu liên quan đến CarIconSpan.create
để biết thêm thông tin về cách tạo những span này. Hãy xem phần Spantastic text styling with Spans (Tạo kiểu văn bản spantastic (tuyệt vời) bằng span) để biết thông tin tổng quan về cách hoạt động của việc định kiểu văn bản bằng 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();
Car Hardware API (API Phần cứng ô tô)
Bắt đầu với Car App API (API Ứng dụng dành cho ô tô) cấp 3, Thư viện ứng dụng cho ô tô có API mà bạn có thể dùng để truy cập vào các thuộc tính và cảm biến của xe.
Yêu cầu
Để sử dụng các API đó với Android Auto, hãy bắt đầu bằng cách thêm một phần phụ thuộc trên androidx.car.app:app-projected
vào tệp build.gradle
cho mô-đun Android Auto của bạn. Đối với Android Automotive OS, hãy thêm một phần phụ thuộc trên androidx.car.app:app-automotive
vào tệp build.gradle
cho mô-đun Android Automotive OS.
Ngoài ra, trong tệp AndroidManifest.xml
, bạn phải khai báo các quyền liên quan cần để yêu cầu dữ liệu ô tô mà bạn muốn sử dụng. Lưu ý rằng người dùng cũng phải cấp các quyền này cho bạn. Bạn có thể dùng cùng một mã trên cả Android Auto và Android Automotive OS, thay vì phải tạo các luồng phụ thuộc vào nền tảng. Tuy nhiên, các quyền cần thiết sẽ khác nhau.
CarInfo
Bảng này mô tả các thuộc tính do API CarInfo
hiển thị và những quyền bạn cần để yêu cầu sử dụng các thuộc tính đó:
Phương thức | Thuộc tính | Quyền đối với Android Auto | Quyền đối với Android Automotive OS |
---|---|---|---|
fetchModel |
Hãng xe, mẫu xe, năm sản xuất | android.car.permission.CAR_INFO |
|
fetchEnergyProfile |
Loại đầu nối xe điện, loại nhiên liệu | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
addTollListener
removeTollListener |
Trạng thái thẻ thu phí cầu đường, loại thẻ thu phí cầu đường | ||
addEnergyLevelListener
removeEnergyLevelListener |
Mức pin, mức nhiên liệu, mức nhiên liệu thấp, quãng đường còn đi được | 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 |
addSpeedListener
removeSpeedListener |
Tốc độ thô, tốc độ hiển thị (hiện trên màn hình cụm đồng hồ của ô tô) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED ,android.car.permission.READ_CAR_DISPLAY_UNITS |
addMileageListener
removeMileageListener |
Quãng đường trên công tơ mét | com.google.android.gms.permission.CAR_MILEAGE |
Dữ liệu này không có sẵn trên Android Automotive OS cho các ứng dụng được cài đặt từ Cửa hàng Play. |
Ví dụ: để biết quãng đường còn đi được, hãy tạo thực thể cho đối tượng CarInfo
, sau đó tạo và đăng ký 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);
Đừng cho rằng dữ liệu từ ô tô luôn có sẵn.
Nếu gặp lỗi, hãy kiểm tra trạng thái của giá trị bạn đã yêu cầu để hiểu rõ hơn lý do khiến bạn không truy xuất được dữ liệu mình yêu cầu. Hãy xem tài liệu tham khảo để biết định nghĩa đầy đủ về lớp CarInfo
.
CarSensors
Lớp CarSensors
cho phép bạn truy cập vào gia tốc kế, con quay hồi chuyển, la bàn và dữ liệu vị trí của xe. Tính sẵn có của các giá trị này có thể phụ thuộc vào OEM. Định dạng của dữ liệu từ gia tốc kế, con quay hồi chuyển và la bàn giống như định dạng bạn nhận được từ API SensorManager
. Ví dụ: để kiểm tra hướng của xe, hãy làm như sau:
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);
Để truy cập vào dữ liệu vị trí từ ô tô, bạn cũng cần khai báo và yêu cầu quyền android.permission.ACCESS_FINE_LOCATION
.
Kiểm thử
Để mô phỏng dữ liệu cảm biến khi kiểm thử trên Android Auto, hãy tham khảo phần Cảm biến và Cấu hình cảm biến trong hướng dẫn Đầu phát trung tâm trên máy tính. Để mô phỏng dữ liệu cảm biến khi kiểm thử trên Android Automotive OS, hãy tham khảo phần Mô phỏng trạng thái phần cứng trong hướng dẫn Trình mô phỏng Android Automotive OS.
Vòng đời của CarAppService, Phiên và Màn hình
Các lớp Session
và Screen
triển khai giao diện LifecycleOwner
. Khi người dùng tương tác với ứng dụng, phương thức gọi lại trong vòng đời của các đối tượng Session
và Screen
sẽ được gọi, như mô tả trong biểu đồ sau đây.
Vòng đời của CarAppService và Phiên
Session
.Để biết thông tin đầy đủ, hãy xem tài liệu về phương thức Session.getLifecycle
.
Vòng đời của màn hình
Screen
.Để biết thông tin đầy đủ, hãy xem tài liệu về phương thức Screen.getLifecycle
.
Ghi âm bằng micrô trên ô tô
Khi dùng API CarAudioRecord
và CarAppService
của ứng dụng, bạn có thể cho phép ứng dụng truy cập vào micrô trên ô tô của người dùng. Người dùng cần cấp cho ứng dụng của bạn quyền truy cập vào micrô trên ô tô. Ứng dụng của bạn có thể ghi âm và xử lý thông tin đầu vào của người dùng ngay trong ứng dụng.
Quyền ghi âm
Trước khi ghi âm, bạn phải khai báo quyền ghi âm trong AndroidManifest.xml
và yêu cầu người dùng cấp quyền đó.
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
...
</manifest>
Bạn cần yêu cầu quyền ghi âm trong thời gian chạy. Hãy xem phần Yêu cầu cấp quyền để biết thông tin về cách yêu cầu cấp quyền trong ứng dụng dành cho ô tô của bạn.
Ghi âm
Sau khi người dùng cấp quyền ghi âm, bạn có thể ghi âm và xử lý bản ghi đó.
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();
Quyền phát âm thanh
Khi ghi âm từ micrô trên ô tô, trước tiên, hãy lấy quyền phát âm thanh để đảm bảo rằng mọi nội dung nghe nhìn đang phát đều dừng lại. Nếu bạn mất quyền phát âm thanh, hãy dừng ghi âm.
Dưới đây là ví dụ về cách lấy quyền phát âm thanh:
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
Thư viện kiểm thử
Thư viện kiểm thử của Android cho Ô tô cung cấp các lớp phụ trợ mà bạn có thể sử dụng để xác thực hành vi của ứng dụng trong một môi trường thử nghiệm.
Ví dụ: SessionController
cho phép bạn mô phỏng một kết nối đến máy chủ lưu trữ và xác minh rằng Screen
và Template
được tạo và trả về là chính xác.
Hãy tham khảo phần Ứng dụng mẫu để biết các ví dụ về cách sử dụng.
Báo cáo sự cố Thư viện ứng dụng Android cho Ô tô
Nếu bạn thấy thư viện có lỗi, hãy báo cáo lỗi đó bằng Công cụ theo dõi lỗi của Google. Hãy nhớ điền tất cả thông tin được yêu cầu vào mẫu báo cáo lỗi.
Trước khi báo lỗi mới, vui lòng kiểm tra xem lỗi đó có trong bản ghi chú phát hành của thư viện hay không hoặc có được báo cáo trong danh sách lỗi hay không. Bạn có thể đăng ký theo dõi và tán thành các lỗi bằng cách nhấp vào dấu sao cho một lỗi trong công cụ theo dõi. Để biết thêm thông tin, hãy xem bài viết Đăng ký theo dõi lỗi.