این صفحه نحوه پیادهسازی AppCard را شرح میدهد.
مرحله ۱: افزودن همه واردات
برای افزودن واردات:
static_libs: [ … "car-app-card", ],
مرحله ۲: SimpleAppCardContentProvider را به مانیفست خود اضافه کنید
حتماً
android:authorities(بهصورت پررنگ) را با نام بستهتان جایگزین کنید.<!-- 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>
مرحله ۳: SimpleAppCardContentProvider را به مانیفست اضافه کنید
برای افزودن
SimpleAppCardContentProviderبه مانیفست: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" } }
مرحله ۴: ایجاد AppCard
برای ایجاد 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() }
برای مثال:

شکل ۱. AppCard بساز.
مرحله ۵: فعال کردن کلیککننده دکمه
برای فعال کردن کلیکر:
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
}
}
برای مثال:

شکل ۲. کلیککننده دکمه را فعال کنید.
مرحله ۶: بهروزرسانی تصویر سرایند
برای بهروزرسانی تصویر در سرصفحه:
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.این فرایند را تکرار کنید تا به هر مؤلفهای که از آن پشتیبانی میکند تصویر اضافه کنید.
مرحله ۷: افزودن تعاملهای بیشتر
برای ایجاد نوار پیشرفت با کنترلها:
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 }
دکمه پخش یا مکث را به نوار پیشرفت اضافه کردیم که میتواند هر ثانیه بهروز شود. بهدلیل محدودیتهای اندازه، setText را روی دکمه کلیککننده ببینید
که برای نشان دادن تعداد کلیکها اضافه شده است، .setText("$clickCounter")
شکل ۴. دکمهای اضافه کنید. |
شکل ۵. دکمه پردازششده. |
مرحله ۸: راهاندازی فعالیت
بهشرطی که برنامهتان با [
background-starts#exceptions][1] مطابقت داشته باشد، میتوانید فعالیتی را ازonClickListenerدکمه راهاندازی کنید.class SampleRoutingActivity : AppCompatActivity() { override fun onStart() { super.onStart() val intent = Intent(ACTION_LOCATION_SOURCE_SETTINGS).apply { setFlags(FLAG_ACTIVITY_CLEAR_TOP) } startActivity(intent) finish() } }برای شروع فعالیت، دکمهای در AppCard اضافه کنید. اگر هیچ فعالیتی وجود ندارد، فعالیت مسیریابی به برنامهتان اضافه کنید:
override fun onStart() { super.onStart() val intent = Intent(ACTION_LOCATION_SOURCE_SETTINGS).apply { setFlags(FLAG_ACTIVITY_CLEAR_TOP) } startActivity(intent) finish() } }وقتی کلاس فراخوانی میشود، کاربر به تنظیمات مکان هدایت میشود.
setFlags(FLAG_ACTIVITY_CLEAR_TOP)اعمال میشود تا اطمینان حاصل شود کاربر نمیتواند به فعالیت اصلی برگردد.دکمهای در AppCard برای شروع فعالیت اضافه کنید:
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() ) ... }
بهدلیل محدودیتهای فضا، دکمه کلیککننده در میزبان AppCard برداشته شد. AppCard بهصورت زیر نشان داده میشود:

شکل ۶. AppCard بدون دکمه کلیککننده.
[1]: https://developer.android.com/guide/components/activities/background-starts#exceptions