يمكنك استخدام Instrument Cluster API (إحدى واجهات برمجة التطبيقات في Android) لعرض تطبيقات التنقّل، بما في ذلك "خرائط Google"، على شاشة ثانوية في السيارة، مثل الشاشة الموجودة خلف عجلة القيادة على لوحة العدادات. توضّح هذه الصفحة كيفية إنشاء خدمة للتحكّم في هذه الشاشة الثانوية ودمج الخدمة مع CarService لكي تتمكّن تطبيقات التنقّل من عرض واجهة مستخدم.
المصطلحات
تُستخدَم المصطلحات التالية في هذه الصفحة.
CarManager التي تتيح للتطبيقات الخارجية تشغيل نشاط على مجموعة العدادات وتلقّي معاودة الاتصال عندما تكون مجموعة العدادات جاهزة لعرض الأنشطة.android:singleUser. في أي وقت، يتم تشغيل حالة واحدة على الأكثر من الخدمة على نظام Android.المتطلبات الأساسية
قبل المتابعة، تأكَّد من توفّر العناصر التالية:
- بيئة تطوير Android : لإعداد بيئة تطوير Android ، يُرجى الاطّلاع على متطلبات الإصدار.
- تنزيل رمز المصدر لنظام Android : يمكنك الحصول على أحدث إصدار من رمز المصدر لنظام Android من فرع pi-car-release (أو إصدار أحدث) على https://android.googlesource.com.
- الوحدة الرئيسية (HU) : يجب أن يكون لديك جهاز Android قادر على تشغيل Android 9 (أو إصدار أحدث). يجب أن يتضمّن هذا الجهاز شاشة خاصة به وأن يكون قادرًا على عرض الإصدارات الجديدة من Android على الشاشة.
- مجموعة العدادات هي إحدى الحالات التالية:
- شاشة ثانوية فعلية متصلة بالوحدة الرئيسية : إذا كان جهازك ونواة النظام يتيحان إدارة شاشات متعددة.
- وحدة مستقلة : أي وحدة حوسبة متصلة بالوحدة الرئيسية من خلال اتصال شبكة، وقادرة على تلقّي وعرض بث فيديو على شاشتها الخاصة.
- شاشة محاكاة : أثناء التطوير، يمكنك استخدام إحدى
بيئات المحاكاة التالية:
- شاشات ثانوية محاكاة : لتفعيل شاشة ثانوية محاكاة على أي توزيعة AOSP Android، انتقِل إلى إعدادات خيارات المطوّرين في تطبيق الإعدادات على النظام، ثم اختَر محاكاة الشاشات الثانوية. يعادل هذا الإعداد توصيل شاشة ثانوية فعلية، مع العلم أنّ هذه الشاشة تكون فوق الشاشة الأساسية.
- مجموعة عدادات محاكاة : يوفّر محاكي 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 و CAR_NAVIGATION_SERVICE. - السماوي :
InstrumentClusterRendererServiceنفّذه المصنّع الأصلي للجهاز. - الأرجواني : تطبيق التنقّل الذي نفّذته Google والمطوّرون الخارجيون.
- الأخضر :
CarAppFocusManager. لمزيد من المعلومات، يُرجى الاطّلاع على استخدام CarAppFocusManager API أدناه و CarAppFocusManager.
يتّبع تدفق معلومات "حالة التنقّل" التسلسل التالي:
- تهيئ
CarServiceعنصرInstrumentClusterRenderingService. - أثناء التهيئة، يحدّث
InstrumentClusterRenderingServiceCarServiceبما يلي:- خصائص شاشة مجموعة العدادات، مثل الحدود غير المحجوبة (يمكنك الاطّلاع على مزيد من التفاصيل حول الحدود غير المحجوبة لاحقًا).
- خيارات النشاط اللازمة لتشغيل الأنشطة داخل شاشة مجموعة العدادات. لمزيد من المعلومات، يُرجى الاطّلاع على 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لتشغيل النشاط، ويتضمّن خصائص شاشة مجموعة العدادات كبيانات إضافية في الـ intent.
دمج واجهة برمجة التطبيقات
يجب أن تتّسم عملية تنفيذ InstrumentClusterRenderingService بما يلي:
- يجب تحديدها كخدمة "سينغلتون" من خلال إضافة القيمة التالية إلى
AndroidManifest.xml. هذا ضروري لضمان تشغيل نسخة واحدة من خدمة مجموعة العدادات، حتى أثناء التهيئة وتبديل المستخدم:
android:singleUser="true" - يجب أن يكون لديك إذن النظام
BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. يضمن ذلك أنّCarServiceلا تربط إلا خدمة عرض مجموعة العدادات المضمّنة كجزء من صورة نظام Android:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
تنفيذ InstrumentClusterRenderingService
لإنشاء الخدمة، اتّبِع الخطوات التالية:
- اكتب فئة تستند إلى
ClusterRenderingService
، ثم أضِف إدخالاً مطابقًا إلى ملف
AndroidManifest.xmlتتحكّم هذه الفئة في شاشة مجموعة العدادات ويمكنها (اختياريًا) عرض بيانات Navigation State API. - أثناء
onCreate()، استخدِم هذه الخدمة لتهيئة التواصل مع جهاز العرض. تشمل الخيارات ما يلي:- تحديد الشاشة الثانوية التي سيتم استخدامها لمجموعة العدادات.
- إنشاء شاشة افتراضية لكي يعرض تطبيق مجموعة العدادات الصورة المعروضة وينقلها إلى وحدة خارجية (باستخدام تنسيق بث فيديو، مثل H.264).
- عندما تكون الشاشة الموضّحة أعلاه جاهزة، يجب أن تستدعي هذه الخدمة
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()لتحديدActivityOptionsالدقيقة التي يجب استخدامها لعرض النشاط على مجموعة العدادات. استخدِم هذه المَعلمات:category.ClusterRenderingService.ActivityOptions.هي حالةActivityOptionsيمكن استخدامها لتشغيل نشاط في مجموعة العدادات. على سبيل المثال، من نموذج تنفيذ مجموعة العدادات على AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- عندما تكون مجموعة العدادات جاهزة لعرض الأنشطة، يجب أن تستدعي هذه الخدمة
InstrumentClusterRenderingService#setClusterActivityState(). استخدِم هذه المَعلمات:categoryClusterRenderingServicestateحزمة تم إنشاؤها باستخدام ClusterRenderingService. احرص على توفير هذه البيانات:visibleتحدّد هذه المَعلمة مجموعة العدادات على أنّها مرئية وجاهزة لـ عرض المحتوى.unobscuredBoundsهو مستطيل يحدّد المنطقة داخل شاشة مجموعة العدادات التي يكون من الآمن عرض المحتوى فيها. على سبيل المثال، المناطق التي تغطيها المؤشرات والمقاييس.
- يمكنك إلغاء طريقة
Service#dump()وعرض معلومات الحالة المفيدة لتحديد الأخطاء وحلّها (يُرجى الاطّلاع على dumpsys لمزيد من المعلومات).
نموذج تنفيذ InstrumentClusterRenderingService
يقدّم المثال التالي عملية تنفيذ InstrumentClusterRenderingService، التي تنشئ VirtualDisplay لعرض محتوى مجموعة العدادات على شاشة فعلية بعيدة.
بدلاً من ذلك، يمكن لهذا الرمز تمرير 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 API طريقة باسم getAppTypeOwner()، ما يسمح
لخدمة مجموعة العدادات التي يكتبها المصنّعون الأصليون للأجهزة بمعرفة تطبيق التنقّل الذي لديه تركيز التنقّل في أي وقت. يمكن للمصنّعين الأصليين للأجهزة استخدام الطريقة الحالية CarAppFocusManager#addFocusListener()، و
ثم استخدام getAppTypeOwner() لمعرفة التطبيق الذي لديه التركيز. باستخدام هذه المعلومات،
يمكن للمصنّعين الأصليين للأجهزة إجراء ما يلي:
- تبديل النشاط المعروض في مجموعة العدادات إلى نشاط مجموعة العدادات الذي يوفّره تطبيق التنقّل الذي لديه التركيز.
- يمكنهم رصد ما إذا كان تطبيق التنقّل الذي لديه التركيز يتضمّن نشاط مجموعة عدادات أم لا. إذا لم يكن لتطبيق التنقّل الذي لديه التركيز نشاط مجموعة عدادات (أو إذا كان هذا النشاط غير مفعَّل)، يمكن للمصنّعين الأصليين للأجهزة إرسال هذه الإشارة إلى وحدة DIM في السيارة ليتم تخطّي جانب التنقّل في مجموعة العدادات بالكامل.
يمكنك استخدام 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) } }
الملحق: استخدام نموذج التطبيق
يوفّر AOSP نموذج تطبيق ينفّذ Navigation State API.
لتشغيل نموذج التطبيق هذا، اتّبِع الخطوات التالية:
- أنشئ Android Auto وثبّت ذاكرة ROM على وحدة رئيسية متوافقة. استخدِم تعليمات إنشاء Android وعرضه الخاصة بجهازك. للحصول على تعليمات، يُرجى الاطّلاع على استخدام لوحات مرجعية.
- وصِّل شاشة ثانوية فعلية بالوحدة الرئيسية (إذا كانت متوافقة) أو فعِّل الوحدة الرئيسية الثانوية الافتراضية:
- اختَر وضع المطوّرين في تطبيق "الإعدادات".
- انتقِل إلى الإعدادات > النظام > الإعدادات المتقدّمة > خيارات المطوّرين > محاكاة الشاشات الثانوية.
- أعِد تشغيل الوحدة الرئيسية.
- لتشغيل تطبيق KitchenSink، اتّبِع الخطوات التالية:
- افتح الدرج.
- انتقِل إلى مجموعة العدادات.
- انقر على بدء البيانات الوصفية.
يطلب KitchenSink تركيز NAVIGATION، ما يوجّه خدمة DirectRenderingCluster لعرض واجهة مستخدم محاكاة على مجموعة العدادات.