جزییات فنی

این بخش جزئیات فنی مربوط به برنامه مرجع مرکز کنترل را ارائه می‌دهد.

مرکز کنترل یک برنامه‌ی مستقل، ممتاز و دارای امضای سیستمی است که به حداقل نسخه‌ی SDK 35 (اندروید V (سطح API 35)) نیاز دارد. این برنامه برای استفاده System APIs در system/priv-app نصب می‌شود. برای خواندن اطلاعات رسانه‌ای، برنامه باید دارای امضای پلتفرم باشد. می‌توانید برنامه را از طریق بی‌سیم (OTA) به‌روزرسانی کنید.

خدمات پس زمینه

برنامه مرکز کنترل برای عملکرد خود به یک سرویس پس‌زمینه متکی است. Control Center Service در حالت user-post-unlocked در چرخه حیات کاربر توسط Vendor ServiceController آغاز می‌شود. مرکز کنترل باید همیشه فعال باشد و در پس‌زمینه ارتباط برقرار کند - برنامه نمی‌تواند به باز شدن برنامه توسط کاربر متکی باشد.

Control Center Service با استفاده از API ارتباطات به نمونه‌های دیگر خود در مناطق دیگر ساکنین متصل شده و با آنها ارتباط برقرار می‌کند. خواندن راهنمای ادغام برای درک چگونگی برقراری ارتباط نمونه‌های مرکز کنترل در هر کاربر و ارسال و دریافت داده‌ها ضروری است.

نموداری که سرویس مرکز کنترل را که توسط Vendor ServiceController آغاز می‌شود، نشان می‌دهد.
شکل 5. سرویس مرکز کنترل که توسط Vendor ServiceController آغاز شده است.

ارتباطات

پس از اتصال ، Control Center Service با اشیاء protobuf که اطلاعات را منتقل می‌کنند، ارتباط برقرار می‌کند. برای انتقال protobuf به منطقه مسکونی دیگر با استفاده از Communication APIs ، protobuf به یک byte array تبدیل می‌شود، یک payload object ایجاد می‌شود و Payload از طریق CarOccupantConnectionManager#sendPayload ارسال می‌شود.

message ControlCenterPayload {
    required Type messageType = 1;
    // ...
    enum Type {
       MEDIA_STATUS = 0;
       MEDIA_COMMAND = 1;
       INPUT_LOCK_COMMAND = 2;
       INPUT_LOCK_SUCCESSFUL = 3;
       CANCEL_AUDIO_REQUEST = 4;
       MIRRORING_REQUEST_RECEIVER_DECISION = 5;
       MIRRORING_SESSION_ENDED = 6;
    }
}

private fun parsePayload(
    senderZone: OccupantZoneInfo,
    payload: Payload
) {
     val parsedPayload =
         ControlCenterPayload.parseFrom(payload.bytes)
             when (parsedPayload.messageType) {
                 ControlCenterPayload.Type.MEDIA_STATUS -> {
                     // logic here
                 }
             }
             //…
}

داده‌ها

اطلاعات مربوط به مناطق مسکونی در مرکز کنترل به شکل اشیاء OccupantZoneData ذخیره می‌شود. تغییرات در OccupantZoneData محلی از طریق Comms API به سایر نمونه‌های مرکز کنترل ارسال می‌شود.

وقتی Payload دریافتی تجزیه می‌شود، داده‌های تجزیه‌شده به OccupantZoneStateRepository محلی منتقل می‌شوند که به نوبه خود، viewها را از تغییر مطلع می‌کند. بیشتر داده‌ها بین کلاس‌هایی با Kotlin flows on Android منتقل می‌شوند.

رسیدگی به درخواست‌های مربوط به بلندگوی کابین

برای اینکه راننده همیشه بتواند درخواست‌های پخش صدا از بلندگوهای کابین توسط مسافران را دریافت کند، پس از ایجاد، Control Center Service راننده، Primary ZoneMedia Audio RequestCallback را ثبت می‌کند .

فراخوانی‌های CarAudioManager#requestMediaAudioOnPrimaryZone به سرویس مرکز کنترل راننده اطلاع داده می‌شود. Control Center Service راننده با ایجاد یک اعلان هشدار (HUN) که می‌تواند از طریق CarAudioManager#allowMediaAudioOnPrimaryZone(boolean) پذیرفته یا رد شود، درخواست‌ها را مدیریت می‌کند.

تماشای همزمان ویدیو با سایر صفحه نمایش‌ها

قابلیت تماشای همزمان به لطف Task Mirroring APIs در CarActivityManager کار می‌کند. TaskMirroringManager ابتدا بسته برنامه در حال پخش MediaSession را در CarActivityManager#getVisibleTasks جستجو می‌کند و سپس یک VirtualDisplay ایجاد می‌کند و وظیفه قابل مشاهده را از طریق CarActivityManager#moveRootTaskToDisplay به این نمایشگر منتقل می‌کند.

این یک توکن IBinder را برمی‌گرداند که MirroredSurfaceView می‌تواند از آن در یک طرح‌بندی برای نمایش وظیفه از طریق MirroredSurfaceView#mirrorSurface استفاده کند. شیء Communication API Payload این توکن را به سایر مناطق اشغالی ارسال می‌کند.

هر نمونه از مرکز کنترل در آن مناطق مسکونی، یک Mirroring activity را راه‌اندازی می‌کند و از آن توکن برای پر کردن MirroredSurfaceView استفاده می‌کند.

جریان یک توکن آینه‌ای برای نمایش یک وظیفه در صفحه نمایش دیگر.
شکل ۶. بازتاب جریان توکن.

APIهای آینه‌سازی وظایف

مرکز کنترل از این APIهای آینه‌سازی وظایف استفاده می‌کند:

CarActivityManager#getVisibleTasks(int displayId)
<ActivityManager.RunningTaskInfo> برای نمایش فرستنده فراخوانی شد.

CarActivityManager#moveRootTaskToDisplay(int virtualDisplayId)
وظیفه قابل مشاهده انتخاب شده را به یک نمایشگر مجازی ایجاد شده منتقل می‌کند.

CarActivityManager#createTaskMirroringToken(int taskId)
یک وظیفه برای انعکاس توکن IBinder ایجاد می‌کند و باید پس از انتقال وظیفه به نمایشگر مجازی فراخوانی شود.

MirroredSurfaceView#mirrorSurface(IBinder token)
یک شیء نمای سفارشی که از توکن برای نمایش محتویات |نمایش مجازی استفاده می‌کند.

محدودیت‌های آینه‌سازی وظایف در مرکز کنترل

مرکز کنترل فقط از آینه‌سازی وظایف برای برنامه‌های MediaSession پشتیبانی می‌کند. با این حال، API می‌تواند هر وظیفه‌ای را آینه‌سازی کند. نمایش مجازی با ابعاد نمایشگر فرستنده ساخته می‌شود. اگر نمایشگر گیرنده از وضوح و ابعاد متفاوتی استفاده کند، نمایشگر مجازی در مرکز صفحه نمایش ظاهر می‌شود.

وظایف قابل مشاهده سطحی

مرکز کنترل، شاسی Theme.CarUi.NoToolbar را به یک پنجره شفاف تبدیل می‌کند. این بدان معناست که وقتی مرکز کنترل روی یک وظیفه باز می‌شود، وظیفه در CarActivityManager#getVisibleTasks برگردانده می‌شود، که امکان آینه‌سازی وظیفه را فراهم می‌کند.

دریافت اطلاعات آینه کاری

مرکز کنترل، سایر برنامه‌ها را از جلسات آینه‌ای مطلع می‌کند. برای دریافت به‌روزرسانی‌ها، برنامه‌ها باید به Control Center Service متصل شوند و یک کلاس Handler را به عنوان کلاینت ارسال کنند که Messages از Control Center Service دریافت و مدیریت می‌کند.

برنامه‌های کلاینت می‌توانند نام بسته‌ی برنامه‌ی آینه‌ای شده را دریافت کنند و با استفاده از این کلیدها، یک intent URI برای فعالیت در مرکز کنترل میزبان برنامه‌ی آینه‌ای شده، راه‌اندازی کنند:

  • _config_msg_mirroring_pkg_name_key_
  • _config_msg_mirroring_redirect_uri_key_

این پیکربندی‌ها باید در منابع برنامه کلاینت و منابع مرکز کنترل وجود داشته باشند.

برنامه‌های کلاینت اطلاعات آینه‌ای را از مرکز کنترل دریافت می‌کنند.
شکل ۷. دریافت اطلاعات آینه‌سازی از مرکز کنترل.

مرکز کنترل اشکال‌زدایی

کلاس Logger لاگ‌های مرکز کنترل را مدیریت می‌کند، که می‌توان آن‌ها را طوری پیکربندی کرد که لاگ‌ها را اجباری کنند.

class Logger(cls: Class<*>) {

   companion object {
       private const val FORCE_LOGS = false
   }

   private val tag: String

   init {
       tag = cls.simpleName
   }

   fun v(message: String) {
       if (Log.isLoggable(tag, Log.VERBOSE) || FORCE_LOGS) {
           Log.v(tag, message)
       }
   }
...

برنامه سیستم و قابلیت به‌روزرسانی

از آنجا که مرکز کنترل یک برنامه سیستمی است و به دلیل استفاده از مجوزهای فقط امضا، توسط پلتفرم امضا شده است، مرکز کنترل باید از قبل روی دستگاه نصب شده باشد و فقط می‌تواند به صورت OTA به‌روزرسانی شود، مشابه برنامه Car Media .

ساخت مرکز کنترل از منبع

برای دریافت کد منبع مرکز کنترل، به «ادغام برنامه‌های دسته‌بندی نشده» مراجعه کنید.

حریم خصوصی کاربر با نمایشگرهای چندگانه

مرکز کنترل به همه سرنشینان خودرو اجازه می‌دهد اطلاعات رسانه‌ای را در همه نمایشگرها مشاهده کنند. گوگل توصیه می‌کند برای اطلاع‌رسانی به کاربران، یک اطلاعیه حریم خصوصی غیر مسدودکننده درج کنید. گوگل توصیه می‌کند این کار را در سطح سیستم، هنگام ورود به یک نمایشگر، انجام دهید.