استخدام واجهة برمجة التطبيقات Instrument Cluster API (إحدى واجهات برمجة التطبيقات في Android) لعرض تطبيقات التنقّل، بما في ذلك "خرائط Google"، على شاشة ثانوية في السيارة، مثل الشاشة خلف عجلة القيادة على لوحة العدادات توضّح هذه الصفحة كيفية إنشاء خدمة للتحكّم في الشاشة الثانوية ودمج الخدمة مع CarService حتى تتمكّن تطبيقات التنقّل من عرض واجهة مستخدم.
المصطلحات
تُستخدَم المصطلحات التالية في هذه الصفحة.
CarManager يتيح للتطبيقات الخارجية تشغيل نشاط على مجموعة العدادات وتلقّي عمليات رد الاتصال عندما تكون مجموعة العدادات جاهزة لعرض الأنشطة.android:singleUser في أي وقت، لا يتم تشغيل أكثر من مثيل واحد للخدمة على نظام Android.المتطلبات الأساسية
قبل المتابعة، تأكَّد من توفّر العناصر التالية:
- بيئة تطوير تطبيقات Android لإعداد بيئة تطوير Android، يُرجى الاطّلاع على متطلبات الإصدار.
- تنزيل رمز المصدر لنظام التشغيل Android احصل على أحدث إصدار من رمز المصدر لنظام التشغيل Android من فرع pi-car-release (أو إصدار أحدث) على الرابط https://android.googlesource.com.
- وحدة التحكم الرئيسية (HU): جهاز Android يعمل بالإصدار 9 (أو إصدار أحدث) يجب أن يتضمّن هذا الجهاز شاشة عرض خاصة به وأن يكون قادرًا على عرض إصدارات جديدة من Android.
- يجب أن تكون لوحة العدادات إحدى الحالات التالية:
- شاشة عرض ثانوية خارجية متصلة بوحدة التحكم الرئيسية إذا كان جهازك يتيح إدارة شاشات عرض متعددة.
- وحدة مستقلة: أي وحدة حسابية متصلة بوحدة HU عبر اتصال شبكة، ويمكنها تلقّي وعرض بث فيديو على شاشتها الخاصة
- شاشة محاكية أثناء التطوير، يمكنك استخدام إحدى البيئات المحاكية التالية:
- شاشات ثانوية تمت محاكاتها لتفعيل شاشة ثانوية محاكاة على أي توزيع لنظام التشغيل Android من مشروع AOSP، انتقِل إلى إعدادات خيارات المطوّرين في تطبيق النظام الإعدادات، ثم اختَر محاكاة شاشات ثانوية. هذا الإعداد يعادل توصيل شاشة ثانوية فعلية، مع العلم أنّ هذه الشاشة تكون متراكبة على الشاشة الأساسية.
- لوحة عدادات محاكية يتضمّن محاكي Android المتوافق مع AAOS خيارًا لعرض مجموعة أدوات القياس باستخدام ClusterRenderingService.
بنية الدمج
مكوّنات عملية الدمج
يتألف أي دمج لواجهة Instrument Cluster API من المكوّنات الثلاثة التالية:
CarService- تطبيقات التنقّل
- خدمة مجموعة العدادات الخاصة بالمصنّع الأصلي للجهاز

CarService
تعمل CarService كوسيط بين تطبيقات التنقّل والسيارة، ما يضمن عدم تفعيل أكثر من تطبيق تنقّل واحد في أي وقت، كما يضمن أنّ التطبيقات التي لديها إذن android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL هي فقط التي يمكنها إرسال البيانات إلى السيارة.
يبدأ CarService جميع الخدمات الخاصة بالسيارة ويوفّر إمكانية الوصول إلى هذه الخدمات من خلال سلسلة من أدوات الإدارة. للتفاعل مع الخدمات، يمكن للتطبيقات التي تعمل في السيارة الوصول إلى أدوات الإدارة هذه.
لتنفيذ لوحة العدادات، على مصنّعي السيارات الأصليين إنشاء عملية تنفيذ مخصّصة لـ InstrumentClusterRendererService وتعديل ClusterRenderingService.
عند عرض مجموعة العدادات، تقرأ CarService المفتاح InstrumentClusterRendererService الخاص بـ ClusterRenderingService أثناء عملية التشغيل لتحديد موقع تنفيذ InstrumentClusterService. في AOSP، يشير هذا الإدخال
إلى خدمة عرض التنفيذ النموذجي لمجموعة Navigation State API:
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
تم إعداد الخدمة المشار إليها في هذا الإدخال وربطها بـ CarService. عندما تطلب تطبيقات التنقّل، مثل "خرائط Google"، CarInstrumentClusterManager، يوفّر CarService أداة إدارة تعدّل حالة شاشة مجموعة العدادات من InstrumentClusterRenderingService المرتبط.
(في هذه الحالة، يشير مصطلح مرتبط إلى خدمات
Android.)
خدمة "مجموعة العدادات"
على الشركات المصنّعة للأجهزة الأصلية إنشاء حزمة تطبيق Android (APK) تحتوي على فئة فرعية من ClusterRenderingService.
يخدم هذا الصف غرضَين:
- توفّر واجهة بين Android وجهاز عرض مجموعة العدادات (الغرض من هذه الصفحة).
- يتلقّى هذا التطبيق مستجدات بشأن حالة التنقّل ويعرضها، مثل إرشادات التنقّل المفصّلة.
بالنسبة إلى الغرض الأول، يجب أن تعمل عمليات تنفيذ InstrumentClusterRendererService من قِبل الشركات المصنّعة الأصلية على تهيئة الشاشة الثانوية المستخدَمة لعرض المعلومات على الشاشات في مقصورة السيارة، وأن تنقل هذه المعلومات إلى CarService من خلال استدعاء الطريقتَين InstrumentClusterRendererService.setClusterActivityOptions() وInstrumentClusterRendererService.setClusterActivityState().
بالنسبة إلى الوظيفة الثانية، يجب أن توفّر خدمة "لوحة العدادات" تنفيذًا لواجهة ClusterRenderingService التي تتلقّى أحداث تعديل حالة التنقّل، ويتم ترميزها على النحو eventType، كما يتم ترميز بيانات الأحداث في حزمة.
تسلسل الدمج
يوضّح المخطّط البياني التالي عملية تنفيذ حالة التنقّل التي تعرض التعديلات:
في هذا الرسم التوضيحي، تشير الألوان إلى ما يلي:
- أصفر
CarServiceوCarNavigationStatusManagerمقدَّمان من نظام Android الأساسي. لمزيد من المعلومات، يُرجى الاطّلاع على السيارة و CAR_NAVIGATION_SERVICE. - أزرق سماوي:
InstrumentClusterRendererServiceالتي نفّذها المصنّع الأصلي للجهاز - أرجواني: تطبيق "التنقّل" الذي تنفّذه Google ومطوّرو تطبيقات تابعون لجهات خارجية
- أخضر
CarAppFocusManager. لمزيد من المعلومات، يُرجى الاطّلاع على استخدام واجهة برمجة التطبيقات CarAppFocusManager أدناه و CarAppFocusManager.
يتّبع تدفّق معلومات "حالة التنقّل" التسلسل التالي:
- تُعدّ الدالة
CarServiceInstrumentClusterRenderingService. - أثناء عملية الإعداد، يضيف
InstrumentClusterRenderingServiceإلىCarServiceما يلي:- خصائص شاشة لوحة العدادات، مثل الحدود غير المحجوبة (يمكنك الاطّلاع على مزيد من التفاصيل حول الحدود غير المحجوبة لاحقًا).
- خيارات الأنشطة المطلوبة لتشغيل الأنشطة داخل شاشة "مجموعة العدادات" لمزيد من المعلومات، يُرجى الاطّلاع على ActivityOptions.
- تطبيق تنقّل (مثل "خرائط Google" لنظام Android Automotive أو أي تطبيق خرائط
يتضمّن الأذونات المطلوبة):
- يمكن الحصول على
CarAppFocusManagerباستخدام فئة Car من car-lib. - قبل بدء عرض الاتجاهات المفصّلة، يتم إجراء مكالمات إلى
CarAppFocusManager.requestFocus()لتمريرCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONكمَعلمةappType.
- يمكن الحصول على
- تُرسل
CarAppFocusManagerهذا الطلب إلىCarService. في حال منح الإذن، يفحصCarServiceحزمة تطبيق الملاحة ويحدّد موقع نشاط تم وضع علامة عليه باستخدام الفئةandroid.car.cluster.NAVIGATION. - إذا تم العثور على، يستخدم تطبيق التنقّل
ActivityOptionsالذي أبلغ عنهInstrumentClusterRenderingServiceلتشغيل النشاط ويتضمّن خصائص العرض في لوحة العدادات كإضافات في الهدف.
دمج واجهة برمجة التطبيقات
يجب أن يستوفي تنفيذ InstrumentClusterRenderingService الشروط التالية:
- يجب أن يتم تحديدها كخدمة سينغلتون من خلال إضافة القيمة التالية إلى ملف AndroidManifest.xml. هذا الإجراء ضروري لضمان تشغيل نسخة واحدة من خدمة "لوحة العدادات"، حتى أثناء عملية الإعداد والتبديل بين المستخدمين:
android:singleUser="true" - يجب أن يكون لديك إذن النظام
BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. يضمن ذلك عدم ربط خدمة عرض لوحة العدادات المضمّنة كجزء من صورة نظام Android إلا من خلالCarService:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
تنفيذ InstrumentClusterRenderingService
لإنشاء الخدمة، اتّبِع الخطوات التالية:
- اكتب فئة تتوسّع من
ClusterRenderingService
ثم أضِف إدخالاً مطابقًا إلى ملف
AndroidManifest.xml. تتحكّم هذه الفئة في شاشة مجموعة العدادات ويمكنها (اختياريًا) عرض بيانات واجهة برمجة التطبيقات الخاصة بحالة التنقل. - أثناء
onCreate()، استخدِم هذه الخدمة لبدء التواصل مع أجهزة العرض. والخيارات المتاحة هي:- تحديد الشاشة الثانوية التي سيتم استخدامها للوحة العدادات
- أنشئ شاشة عرض افتراضية لكي يعرض تطبيق "لوحة العدادات" الصورة المعروضة وينقلها إلى وحدة خارجية (باستخدام تنسيق بث فيديو، مثل H.264).
- عندما يكون العرض الموضّح أعلاه جاهزًا، يجب أن تستدعي هذه الخدمة
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()لتحديدActivityOptionsالدقيق الذي يجب استخدامه لعرض نشاط على لوحة العدادات. استخدِم المَعلمات التالية:category.ClusterRenderingService.ActivityOptions.مثيلActivityOptionsيمكن استخدامه لتشغيل نشاط في مجموعة العدادات على سبيل المثال، من نموذج عملية تنفيذ لوحة العدادات على AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- عندما تكون لوحة العدادات جاهزة لعرض الأنشطة، يجب أن تستدعي هذه الخدمة
InstrumentClusterRenderingService#setClusterActivityState(). استخدِم المَعلمات التالية:categoryClusterRenderingService.stateحزمة تم إنشاؤها باستخدام ClusterRenderingService. احرص على تقديم البيانات التالية:visibleيحدّد هذا الإعداد مجموعة العدادات على أنّها مرئية وجاهزة لعرض المحتوى.unobscuredBoundsمستطيل يحدّد المساحة ضمن شاشة لوحة العدادات التي يمكن عرض المحتوى فيها بأمان. على سبيل المثال، المناطق التي تغطيها المؤشرات.
- تجاوز طريقة
Service#dump()والإبلاغ عن معلومات الحالة المفيدة في تصحيح الأخطاء (راجِع dumpsys لمزيد من المعلومات).
مثال على عملية تنفيذ InstrumentClusterRenderingService
يوضّح المثال التالي عملية InstrumentClusterRenderingServiceتنفيذ تنشئ VirtualDisplay لعرض محتوى InstrumentCluster على شاشة عرض فعلية بعيدة.
بدلاً من ذلك، يمكن أن يمرّر هذا الرمز displayId لشاشة عرض ثانوية مادية متصلة بوحدة التحكم الرئيسية، إذا كان من المعروف أنّها متاحة.
/** * Sample {@link InstrumentClusterRenderingService} implementation */ public class SampleClusterServiceImpl extends InstrumentClusterRenderingService { // Used to retrieve or create displays private final DisplayManager mDisplayManager; // Unique identifier for the display to be used for instrument // cluster private final String mUniqueId = UUID.randomUUID().toString(); // Format of the instrument cluster display private static final int DISPLAY_WIDTH = 1280; private static final int DISPLAY_HEIGHT = 720; private static final int DISPLAY_DPI = 320; // Area not covered by instruments private static final int DISPLAY_UNOBSCURED_LEFT = 40; private static final int DISPLAY_UNOBSCURED_TOP = 0; private static final int DISPLAY_UNOBSCURED_RIGHT = 1200; private static final int DISPLAY_UNOBSCURED_BOTTOM = 680; @Override public void onCreate() { super.onCreate(); // Create a virtual display to render instrument cluster activities on mDisplayManager = getSystemService(DisplayManager.class); VirtualDisplay display = mDisplayManager.createVirtualDisplay( mUniqueId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DPI, null, 0 /* flags */, null, null); // Do any additional initialization (e.g.: start a video stream // based on this virtual display to present activities on a remote // display). onDisplayReady(display.getDisplay()); } private void onDisplayReady(Display display) { // Report activity options that should be used to launch activities on // the instrument cluster. String category = CarInstrumentClusterManager.CATEGORY_NAVIGATION; ActionOptions options = ActivityOptions.makeBasic() .setLaunchDisplayId(display.getDisplayId()); setClusterActivityOptions(category, options); // Report instrument cluster state. Rect unobscuredBounds = new Rect(DISPLAY_UNOBSCURED_LEFT, DISPLAY_UNOBSCURED_TOP, DISPLAY_UNOBSCURED_RIGHT, DISPLAY_UNOBSCURED_BOTTOM); boolean visible = true; ClusterActivityState state = ClusterActivityState.create(visible, unobscuredBounds); setClusterActivityState(category, options); } }
استخدام CarAppFocusManager API
توفّر واجهة برمجة التطبيقات CarAppFocusManager طريقة باسم getAppTypeOwner()، تتيح لخدمة مجموعة العدادات التي تكتبها الشركات المصنّعة للأجهزة الأصلية معرفة تطبيق التنقّل الذي لديه إطار التركيز في أي وقت. يمكن لمصنّعي المعدات الأصلية استخدام طريقة CarAppFocusManager#addFocusListener() الحالية، ثم استخدام getAppTypeOwner() لمعرفة التطبيق الذي يتم التركيز عليه. باستخدام هذه المعلومات، يمكن لمصنّعي المعدات الأصلية إجراء ما يلي:
- بدِّل النشاط المعروض في مجموعة العدادات إلى نشاط المجموعة الذي يوفّره تطبيق التنقّل الذي يتم التركيز عليه.
- يمكنه رصد ما إذا كان تطبيق التنقّل الذي تم التركيز عليه يتضمّن نشاطًا مجمّعًا أم لا. إذا لم يكن تطبيق التنقّل المركّز يتضمّن نشاطًا مجمّعًا (أو إذا كان هذا النشاط غير مفعّل)، يمكن لمصنّعي المعدات الأصلية إرسال هذه الإشارة إلى شاشة عرض معلومات السائق في السيارة ليتم تخطّي جزء التنقّل من الشاشة المجمّعة بالكامل.
استخدِم CarAppFocusManager لضبط والبحث عن تركيز التطبيق الحالي، مثل
التنقّل النشط أو طلب صوتي. عادةً ما يتم تشغيل مثيل واحد فقط من هذا النوع من التطبيقات (أو التركيز عليه) في النظام.
استخدِم طريقة CarAppFocusManager#addFocusListener(..) للاستماع إلى تغييرات التركيز في التطبيق:
import android.car.CarAppFocusManager; ... Car car = Car.createCar(this); mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE); mAppFocusManager.addFocusListener(this, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION); ... public void onAppFocusChanged(int appType, boolean active) { // Use the CarAppFocusManager#getAppTypeOwner(appType) method call // to retrieve a list of active package names }
استخدِم طريقة CarAppFocusManager#getAppTypeOwner(..) لاسترداد أسماء الحِزم الخاصة بالمالك الحالي لنوع تطبيق معيّن محل التركيز. قد تعرض هذه الطريقة أكثر من اسم حزمة واحدة إذا كان المالك الحالي يستخدم ميزة android:sharedUserId.
import android.car.CarAppFocusManager; ... Car car = Car.createCar(this); mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE); List<String> focusOwnerPackageNames = mAppFocusManager.getAppTypeOwner( CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION); if (focusOwnerPackageNames == null || focusOwnerPackageNames.isEmpty()) { // No Navigation app has focus // OEM may choose to show their default cluster view } else { // focusOwnerPackageNames // Use the PackageManager to retrieve the cluster activity for the package(s) // returned in focusOwnerPackageNames } ...
تحديد تطبيقات النماذج
بالنسبة إلى تطبيقات التنقّل المستندة إلى النماذج والتي تستخدم مكتبة تطبيقات السيارات، تعرض الدالة CarAppFocusManager#getAppTypeOwner() اسم حزمة المضيف
(مثلاً، com.google.android.apps.automotive.templates.host)
لأنّ المضيف يحتفظ بتركيز النظام نيابةً عن تطبيق العميل.
لتحديد تطبيق العميل الذي يتم التنقّل فيه، يمكن لمصنّعي المعدات الأصلية استخراج اسم الحزمة من حزمة حالة التنقّل التي يتم إرسالها مع CarNavigationStatusManager. يتم تخزين اسم الحزمة ضمن المفتاح active_app_package_name في الحِزمة التي يتلقّاها NavigationRenderer#onNavigationStateChanged(Bundle):
// In your NavigationRenderer implementation @Override public void onNavigationStateChanged(Bundle bundle) { if (bundle.containsKey("active_app_package_name")) { String activeAppPackage = bundle.getString("active_app_package_name"); // Use the package name to identify the navigating app (e.g., com.waze) } }
الملحق: استخدام نموذج التطبيق
يوفّر "مشروع Android المفتوح المصدر" (AOSP) تطبيقًا نموذجيًا ينفّذ واجهة برمجة التطبيقات Navigation State API.
لتشغيل هذا التطبيق النموذجي، اتّبِع الخطوات التالية:
- إنشاء Android Auto وتثبيته على وحدة رأس متوافقة اتّبِع تعليمات إنشاء وتثبيت إصدار Android المخصّص لجهازك. للحصول على التعليمات، يُرجى الاطّلاع على استخدام لوحات المراجع.
- وصِّل شاشة عرض ثانوية فعلية بوحدة التحكم الرئيسية (إذا كان ذلك متاحًا) أو فعِّل وحدة التحكم الرئيسية الثانوية الافتراضية:
- اختَر وضع المطوّرين في تطبيق "الإعدادات".
- انتقِل إلى الإعدادات > النظام > الإعدادات المتقدّمة > خيارات المطوّرين > محاكاة الشاشات الثانوية.
- أعِد تشغيل وحدة التحكم الرئيسية
- لتشغيل تطبيق KitchenSink، اتّبِع الخطوات التالية:
- افتح الدرج.
- انتقِل إلى مجموعة المؤسسات.
- انقر على بدء البيانات الوصفية.
يطلب KitchenSink التركيز على NAVIGATION، ما يوجّه الخدمة DirectRenderingCluster
إلى عرض واجهة مستخدم وهمية على لوحة العدادات.