Trang này mô tả cách triển khai AppCard.
Bước 1: Thêm tất cả các mục nhập
Cách thêm các lệnh nhập:
static_libs: [ … "car-app-card", ],
Bước 2: Thêm SimpleAppCardContentProvider vào tệp kê khai
Nhớ thay thế
android:authorities(in đậm) bằng tên gói của bạn.<!-- App Card Content Provider that is required to communicate relevant App Cards with the system android.car.permission.BIND_APP_CARD_PROVIDER is an essential permission that will only allow the system to communicate with the AppCardContentProvider The content provider must also be exported and enabled --> <provider android:name=".SimpleAppCardContentProvider" android:authorities="com.example.appcard.sample" android:permission="@string/host_permission" android:exported="true" android:enabled="true"> <intent-filter> <!-- This intent filter will allow the system to find and connect with the application's AppCardContentProvider --> <action android:name="com.android.car.appcard.APP_CARD_PROVIDER" /> </intent-filter> </provider>
Bước 3: Thêm SimpleAppCardContentProvider vào tệp kê khai
Cách thêm
SimpleAppCardContentProvidervào tệp kê khai:class SimpleAppCardContentProvider : AppCardContentProvider() { /** Must return same authority as defined in manifest */ override val authority: String = AUTHORITY /** Setup [AppCardContentProvider] and its constituents */ override fun onCreate(): Boolean { return super.onCreate() } /** Setup an [AppCard] that is being requested */ override fun onAppCardAdded(id: String, ctx: AppCardContext): AppCard { return when (id) { APPCARD_ID -> //TODO: create app card else -> throw IllegalStateException("Unidentified app card ID: $id") } } /** List of supported [AppCard] IDs */ override val appCardIds: List<String> = listOf(APPCARD_ID).toMutableList() /** Clean up when an [AppCard] is removed */ override fun onAppCardRemoved(id: String) { when (id) { APPCARD_ID -> //TODO: create app card } } /** Handle an [AppCardContext] change for a particular [AppCard] ID */ override fun onAppCardContextChanged( id: String, appCardContext: AppCardContext ) { when (id) { APPCARD_ID -> //TODO: update AppCardContext } } companion object { private const val AUTHORITY = "com.example.appcard.sample" private const val APPCARD_ID = "sampleAppCard" } }
Bước 4: Tạo AppCard
Cách tạo AppCard:
override fun onAppCardAdded(id: String, ctx: AppCardContext): AppCard { return when (id) { APPCARD_ID -> createAppCard(ctx) else -> throw IllegalStateException("Unidentified app card ID: $id") } } private fun createAppCard(appCardContext: AppCardContext): ImageAppCard { return ImageAppCard.newBuilder(APPCARD_ID) .setPrimaryText("Hello") .setSecondaryText("World") .setHeader( Header.newBuilder("header") .setTitle("Code Lab") .build() ) .addButton( Button.newBuilder( "button", Button.ButtonType.PRIMARY, object : OnClickListener { override fun onClick() { //no-op } } ) .setText("Click me!") .build() ) .build() }
Ví dụ:

Hình 1. Tạo một AppCard.
Bước 5: Bật công cụ nhấp vào nút
Cách bật thiết bị nhấp chuột:
private var clickCounter = 0
private fun createAppCard(appCardContext: AppCardContext): ImageAppCard {
...
.addButton(
Button.newBuilder(
"button",
Button.ButtonType.PRIMARY,
object : OnClickListener {
override fun onClick() {
clickCounter++
sendAppCardUpdate(createAppCard(appCardContext))
}
}
)
.setText(
if (clickCounter == 0) "Click me!" else "Clicked: $clickCounter"
)
.build()
)
...
}
override fun onAppCardRemoved(id: String) {
when (id) {
APPCARD_ID -> clickCounter = 0
}
}
Ví dụ:

Hình 2. Bật công cụ nhấp vào nút.
Bước 6: Cập nhật ảnh tiêu đề
Cách cập nhật hình ảnh trong tiêu đề:
private fun createAppCard(appCardContext: AppCardContext): ImageAppCard { val headerImageSize = appCardContext.imageAppCardContext.getMaxImageSize(Header::class.java) val logo = resToBitmap( android.R.drawable.ic_menu_compass, headerImageSize.width, headerImageSize.height ) ... .setHeader( Header.newBuilder("header") .setTitle("Code Lab") .setImage( Image.newBuilder("image") .setContentScale(Image.ContentScale.FILL_BOUNDS) .setColorFilter(Image.ColorFilter.TINT) .setImageData(logo) .build() ) .build() ) ... } private fun resToBitmap(res: Int, width: Int, height: Int): Bitmap { val drawable = context?.getDrawable(res) return drawableToBitmap(drawable!!, width, height) } private fun drawableToBitmap(d: Drawable, width: Int, height: Int): Bitmap { val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val canvas = Canvas(bitmap) val left = 0 val top = 0 d.setBounds(left, top, canvas.width, canvas.height) d.draw(canvas) return bitmap } ``` For example:  **Figure 3.** Change the name to the header.Lặp lại quy trình này để thêm hình ảnh vào bất kỳ thành phần nào hỗ trợ hình ảnh.
Bước 7: Thêm các lượt tương tác khác
Cách tạo một thanh tiến trình có các nút điều khiển:
private var progressOn = false private var progressTimer: Timer? = null private var progressCounter = 0 override fun onAppCardRemoved(id: String) { when (id) { APPCARD_ID -> { clickCounter = 0 progressCounter = 0 progressTimer?.cancel() } } } private fun createAppCard(appCardContext: AppCardContext): ImageAppCard { val buttonImageSize = appCardContext.imageAppCardContext.getMaxImageSize(Button::class.java) val progressPlayPauseImage = resToBitmap( if (progressOn) { android.R.drawable.ic_media_pause } else { android.R.drawable.ic_media_play }, buttonImageSize.width, buttonImageSize.height ) ... .setProgressBar( createProgressBar() ) .addButton( Button.newBuilder( "progressButton", Button.ButtonType.NO_BACKGROUND, object : OnClickListener { override fun onClick() { progressOn = !progressOn if (progressOn) { progressTimer = Timer() progressTimer?.scheduleAtFixedRate(object : TimerTask() { override fun run() { progressCounter++ if (progressCounter > 60) progressCounter = 0 sendAppCardComponentUpdate(APPCARD_ID, createProgressBar()) } }, SECONDS_TO_MS, SECONDS_TO_MS) } else { progressTimer?.cancel() progressTimer = null } sendAppCardUpdate(createAppCard(appCardContext)) } } ) .setImage( Image.newBuilder("buttonImage") .setContentScale(Image.ContentScale.FILL_BOUNDS) .setColorFilter(Image.ColorFilter.TINT) .setImageData(progressPlayPauseImage) .build() ) .build() ) ... } private fun createProgressBar(): ProgressBar { return ProgressBar.newBuilder(PROGRESS_BAR_ID, 0, 60) .setProgress(progressCounter) .build() } companion object { ... private const val PROGRESS_BAR_ID = "progress" private const val SECONDS_TO_MS = 1000L }
Chúng tôi đã thêm nút Phát hoặc Tạm dừng vào thanh tiến trình. Nút này có thể được cập nhật mỗi giây. Do hạn chế về kích thước, hãy xem setText trên nút của thiết bị nhấp chuột được thêm vào để phản ánh số lượt nhấp, .setText("$clickCounter")
Hình 4. Thêm nút. |
Hình 5. Nút được kết xuất. |
Bước 8: Khởi chạy hoạt động
Miễn là ứng dụng của bạn tuân thủ
background-starts#exceptions, bạn có thể chạy một hoạt động từonClickListenercủa nút.class SampleRoutingActivity : AppCompatActivity() { override fun onStart() { super.onStart() val intent = Intent(ACTION_LOCATION_SOURCE_SETTINGS).apply { setFlags(FLAG_ACTIVITY_CLEAR_TOP) } startActivity(intent) finish() } }Để bắt đầu hoạt động này, hãy thêm một nút vào AppCard. Nếu không có, hãy thêm một hoạt động định tuyến vào ứng dụng của bạn:
override fun onStart() { super.onStart() val intent = Intent(ACTION_LOCATION_SOURCE_SETTINGS).apply { setFlags(FLAG_ACTIVITY_CLEAR_TOP) } startActivity(intent) finish() } }Khi lớp này được gọi, người dùng sẽ được chuyển hướng đến phần cài đặt Vị trí.
setFlags(FLAG_ACTIVITY_CLEAR_TOP)được áp dụng để đảm bảo người dùng không thể quay lại hoạt động ban đầu.Thêm một nút vào AppCard để bắt đầu hoạt động:
private fun createAppCard(appCardContext: AppCardContext): ImageAppCard { val locationImage = resToBitmap( android.R.drawable.ic_menu_call, buttonImageSize.width, buttonImageSize.height ) ... .addButton( Button.newBuilder( "activityButton", Button.ButtonType.SECONDARY, object : OnClickListener { override fun onClick() { // no-op } } ) .setImage( Image.newBuilder("locationButtonImage") .setContentScale(Image.ContentScale.FILL_BOUNDS) .setColorFilter(Image.ColorFilter.TINT) .setImageData(locationImage) .build() ) .setIntent( RoutingActivityIntent .newBuilder("com.example.appcard.sample.SampleRoutingActivity") .build() ) .build() ) ... }
Do hạn chế về không gian, nút clicker đã bị xoá trong máy chủ AppCard. AppCard sẽ xuất hiện như sau:

Hình 6. AppCard không có nút nhấp.