از API خوشه ابزار (یک API اندروید) برای نمایش برنامههای ناوبری، از جمله نقشههای گوگل، روی یک نمایشگر ثانویه در خودرو، مانند پشت فرمان روی پنل ابزار، استفاده کنید. این صفحه نحوه ایجاد یک سرویس برای کنترل آن نمایشگر ثانویه و ادغام سرویس با CarService را شرح میدهد تا برنامههای ناوبری بتوانند یک رابط کاربری نمایش دهند.
اصطلاحات
اصطلاحات زیر در این صفحه استفاده شده است.
CarManager که به برنامههای خارجی امکان میدهد فعالیتی را روی Instrument Cluster راهاندازی کنند و هنگامی که Instrument Cluster آماده نمایش فعالیتها است، فراخوانیهای مجدد دریافت کنند.android:singleUser . در هر زمان معین، حداکثر یک نمونه از سرویس روی سیستم اندروید اجرا میشود.پیشنیازها
قبل از ادامه، حتماً این عناصر را داشته باشید:
- محیط توسعه اندروید. برای تنظیم محیط توسعه اندروید، به الزامات ساخت مراجعه کنید.
- کد منبع اندروید را دانلود کنید. آخرین نسخه کد منبع اندروید را از شاخه pi-car-release (یا نسخههای بعدی) در https://android.googlesource.com دریافت کنید.
- دستگاه پخش خودرو (HU). یک دستگاه اندروید که قابلیت اجرای اندروید ۹ (یا بالاتر) را داشته باشد. این دستگاه باید صفحه نمایش مخصوص به خود را داشته باشد و بتواند صفحه نمایش را با نسخههای جدید اندروید فلش کند.
- خوشه ابزار دقیق یکی از موارد زیر است:
- نمایشگر ثانویه فیزیکی متصل به واحد پردازش مرکزی. اگر سختافزار و هسته دستگاه از مدیریت چندین نمایشگر پشتیبانی کنند.
- واحد مستقل. هر واحد محاسباتی که از طریق اتصال شبکه به واحد محاسباتی متصل شده و قادر به دریافت و نمایش جریان ویدئو بر روی صفحه نمایش خود است.
- نمایش شبیهسازیشده. در طول توسعه، میتوانید از یکی از این محیطهای شبیهسازیشده استفاده کنید:
- نمایشگرهای ثانویه شبیهسازیشده. برای فعال کردن نمایشگر ثانویه شبیهسازیشده در هر توزیع اندروید AOSP، به تنظیمات گزینههای توسعهدهندگان در برنامه سیستم تنظیمات بروید و سپس شبیهسازی نمایشگرهای ثانویه را انتخاب کنید. این پیکربندی معادل اتصال یک نمایشگر ثانویه فیزیکی است، با این محدودیت که این نمایشگر روی نمایشگر اصلی قرار میگیرد.
- خوشه ابزار شبیهسازیشده. شبیهساز اندروید موجود در AAOS گزینهای برای نمایش خوشه ابزار با ClusterRenderingService ارائه میدهد.
معماری یکپارچهسازی
اجزای یکپارچهسازی
هرگونه ادغام API خوشه ابزار شامل این سه جزء است:
-
CarService - اپلیکیشنهای ناوبری
- خدمات خوشه ابزار OEM

خدمات خودرو
CarService بین برنامههای ناوبری و خودرو واسطهگری میکند و تضمین میکند که در هر زمان فقط یک برنامه ناوبری فعال باشد و فقط برنامههایی که مجوز android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL دارند میتوانند دادهها را به خودرو ارسال کنند.
CarService تمام سرویسهای مخصوص خودرو را راهاندازی میکند و از طریق مجموعهای از مدیران (Managers) به این سرویسها دسترسی میدهد. برای تعامل با سرویسها، برنامههای در حال اجرا در خودرو میتوانند به این مدیران دسترسی داشته باشند.
برای پیادهسازی خوشه ابزار، تولیدکنندگان اصلی تجهیزات (OEM) خودرو باید یک پیادهسازی سفارشی از InstrumentClusterRendererService ایجاد کرده و ClusterRenderingService را بهروزرسانی کنند.
هنگام رندر کردن یک Instrument Cluster، در طول فرآیند بوت، CarService کلید InstrumentClusterRendererService مربوط به ClusterRenderingService را میخواند تا یک پیادهسازی از InstrumentClusterService را پیدا کند. در AOSP، این ورودی به سرویس رندر پیادهسازی خوشهای نمونه Navigation State API اشاره میکند:
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
سرویسی که در این مطلب به آن اشاره شده است، مقداردهی اولیه شده و به CarService متصل شده است. وقتی برنامههای ناوبری، مانند Google Maps، درخواست CarInstrumentClusterManager میکنند، CarService یک مدیر ارائه میدهد که وضعیت Instrument Cluster را از InstrumentClusterRenderingService متصل بهروزرسانی میکند. (در این مورد، bound به Android Services اشاره دارد.)
سرویس خوشه ابزار دقیق
تولیدکنندگان اصلی تجهیزات (OEM) باید یک بسته اندروید (APK) ایجاد کنند که شامل یک زیرکلاس از ClusterRenderingService باشد.
این کلاس دو هدف را دنبال میکند:
- یک رابط کاربری اندروید و دستگاه رندر Instrument Cluster (هدف این صفحه) را فراهم میکند.
- بهروزرسانیهای وضعیت ناوبری، مانند راهنمای ناوبری گام به گام، را دریافت و ارائه میکند.
برای هدف اول، پیادهسازیهای OEM از InstrumentClusterRendererService باید نمایشگر ثانویه مورد استفاده برای رندر اطلاعات روی صفحات نمایش در کابین خودرو را مقداردهی اولیه کرده و این اطلاعات را با فراخوانی متدهای InstrumentClusterRendererService.setClusterActivityOptions() و InstrumentClusterRendererService.setClusterActivityState() به CarService ارسال کنند.
برای عملکرد دوم، سرویس Instrument Cluster باید پیادهسازی از ClusterRenderingService را ارائه دهد. رابطی که رویدادهای بهروزرسانی وضعیت ناوبری را دریافت میکند، که به صورت eventType کدگذاری شدهاند و دادههای رویداد در یک بسته کدگذاری شدهاند.
توالی ادغام
نمودار زیر پیادهسازی یک وضعیت ناوبری را نشان میدهد که بهروزرسانیها را رندر میکند:
در این تصویر، رنگها نشاندهندهی موارد زیر هستند:
- زرد.
CarServiceوCarNavigationStatusManagerتوسط پلتفرم اندروید ارائه میشوند. برای کسب اطلاعات بیشتر، به Car و CAR_NAVIGATION_SERVICE مراجعه کنید. - فیروزهای.
InstrumentClusterRendererServiceتوسط تولیدکننده اصلی تجهیزات (OEM) پیادهسازی شده است. - بنفش. اپلیکیشن ناوبری که توسط گوگل و توسعهدهندگان شخص ثالث پیادهسازی شده است.
- سبز.
CarAppFocusManager. برای کسب اطلاعات بیشتر، به بخش «استفاده از API CarAppFocusManager» در زیر و CarAppFocusManager مراجعه کنید.
جریان اطلاعات وضعیت ناوبری از این ترتیب پیروی میکند:
-
CarServiceInstrumentClusterRenderingServiceرا مقداردهی اولیه میکند. - در طول مقداردهی اولیه،
InstrumentClusterRenderingServiceCarServiceبا موارد زیر بهروزرسانی میکند:- خوشه ابزار، ویژگیهایی مانند مرزهای غیرمبهم را نمایش میدهد (جزئیات بیشتر در مورد مرزهای غیرمبهم را بعداً ببینید).
- گزینههای فعالیت مورد نیاز برای اجرای فعالیتها در داخل نمایشگر Instrument Cluster. برای کسب اطلاعات بیشتر، به ActivityOptions مراجعه کنید.
- یک برنامه ناوبری (مانند نقشههای گوگل برای اندروید اتوموبیل یا هر برنامه نقشهای با مجوزهای لازم):
- با استفاده از کلاس Car از car-lib، یک
CarAppFocusManagerدریافت میکند. - قبل از شروع مسیریابی گام به گام، تابع
CarAppFocusManager.requestFocus()را فراخوانی میکند تاCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONرا به عنوان پارامترappTypeارسال کند.
- با استفاده از کلاس Car از car-lib، یک
-
CarAppFocusManagerاین درخواست را بهCarServiceارسال میکند. در صورت پذیرش،CarServiceبسته برنامه ناوبری را بررسی کرده و فعالیتی را که با دستهandroid.car.cluster.NAVIGATIONمشخص شده است، پیدا میکند. - در صورت یافتن، برنامهی ناوبری از
ActivityOptionsگزارششده توسطInstrumentClusterRenderingServiceبرای راهاندازی فعالیت استفاده میکند و ویژگیهای نمایش Instrument Cluster را به عنوان موارد اضافی در intent لحاظ میکند.
ادغام API
پیادهسازی InstrumentClusterRenderingService باید:
- با اضافه کردن مقدار زیر به AndroidManifest.xml، به عنوان یک سرویس singleton تعیین شود. این کار برای اطمینان از اجرای یک کپی واحد از سرویس Instrument Cluster، حتی در حین مقداردهی اولیه و تغییر کاربر، ضروری است:
android:singleUser="true" - مجوز سیستم
BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICEرا نگه دارید. این تضمین میکند که فقط سرویس رندر Instrument Cluster که به عنوان بخشی از تصویر سیستم اندروید موجود است، همیشه توسطCarServiceمحدود میشود:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
پیادهسازی InstrumentClusterRenderingService
برای ساخت سرویس:
- یک کلاس بنویسید که از ClusterRenderingService ارثبری کند و سپس ورودی مربوطه را به فایل
AndroidManifest.xmlخود اضافه کنید. این کلاس نمایش Instrument Cluster را کنترل میکند و میتواند ( به صورت اختیاری ) دادههای API مربوط به Navigation State را رندر کند. - در طول
onCreate()، از این سرویس برای مقداردهی اولیه ارتباط با سختافزار رندر استفاده کنید. گزینهها عبارتند از:- نمایشگر ثانویه مورد استفاده برای مجموعه ابزار دقیق را تعیین کنید.
- یک نمایشگر مجازی ایجاد کنید تا برنامه Instrument Cluster تصویر رندر شده را رندر کرده و به یک واحد خارجی (با استفاده از یک فرمت پخش ویدئو، مانند H.264) منتقل کند.
- وقتی نمایش نشان داده شده در بالا آماده شد، این سرویس باید
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()را فراخوانی کند تاActivityOptionsدقیقی را که باید برای نمایش یک Activity در Instrument Cluster استفاده شود، تعریف کند. از این پارامترها استفاده کنید:-
category.سرویس رندر خوشه ای . -
ActivityOptions.یک نمونهActivityOptionsکه میتواند برای راهاندازی یک Activity در Instrument Cluster استفاده شود. برای مثال، از پیادهسازی نمونه Instrument Cluster در AOSP:getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
-
- وقتی Instrument Cluster آماده نمایش فعالیتها باشد، این سرویس باید
InstrumentClusterRenderingService#setClusterActivityState()را فراخوانی کند. از این پارامترها استفاده کنید:-
categoryClusterRenderingService . - بستهی
stateبا ClusterRenderingService تولید شده است. حتماً این دادهها را ارائه دهید:-
visibleخوشه ابزار را به عنوان قابل مشاهده و آماده نمایش محتوا مشخص میکند. -
unobscuredBoundsمستطیلی که ناحیهای را در نمایشگر Instrument Cluster تعریف میکند که نمایش محتوا در آن ایمن است. به عنوان مثال، نواحی تحت پوشش صفحهها و گیجها.
-
-
- متد
Service#dump()را بازنویسی کنید و اطلاعات وضعیت مفید برای اشکالزدایی را گزارش دهید (برای اطلاعات بیشتر به dumpsys مراجعه کنید).
نمونه پیادهسازی InstrumentClusterRenderingService
مثال زیر پیادهسازی InstrumentClusterRenderingService را شرح میدهد که یک VirtualDisplay ایجاد میکند تا محتوای Instrument Cluster را روی یک نمایشگر فیزیکی از راه دور ارائه دهد.
از طرف دیگر، این کد میتواند displayId یک نمایشگر ثانویه فیزیکی متصل به HU را، در صورت وجود، ارسال کند.
/** * 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); } }
استفاده از API مربوط به CarAppFocusManager
رابط برنامهنویسی کاربردی CarAppFocusManager متدی به نام getAppTypeOwner() ارائه میدهد که به سرویس خوشهای نوشته شده توسط تولیدکنندگان اصلی تجهیزات (OEM) اجازه میدهد تا بداند کدام برنامه ناوبری در هر زمان مشخص دارای فوکوس ناوبری است. تولیدکنندگان اصلی تجهیزات میتوانند از متد موجود CarAppFocusManager#addFocusListener() استفاده کنند و سپس getAppTypeOwner() برای فهمیدن اینکه کدام برنامه دارای فوکوس است، استفاده کنند. با این اطلاعات، تولیدکنندگان اصلی تجهیزات میتوانند:
- فعالیت نشان داده شده در خوشه را به فعالیت خوشه ارائه شده توسط برنامه ناوبری که فوکوس را نگه داشته است، تغییر دهید.
- میتواند تشخیص دهد که آیا برنامه ناوبری متمرکز، فعالیت خوشهای دارد یا خیر. اگر برنامه ناوبری متمرکز، فعالیت خوشهای نداشته باشد (یا اگر چنین فعالیتی غیرفعال باشد)، تولیدکنندگان اصلی تجهیزات (OEM) میتوانند این سیگنال را به 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 } ...
شناسایی برنامههای الگو
برای برنامههای ناوبری مبتنی بر قالب که از کتابخانه Car App استفاده میکنند، CarAppFocusManager#getAppTypeOwner() نام بسته میزبان (برای مثال، com.google.android.apps.automotive.templates.host ) را برمیگرداند، زیرا میزبان به نمایندگی از برنامه کلاینت، تمرکز سیستم را در اختیار دارد.
برای شناسایی برنامه کلاینت ناوبری، تولیدکنندگان اصلی تجهیزات (OEM) میتوانند نام بسته را از بسته وضعیت ناوبری ارسال شده با 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 یک برنامه نمونه ارائه میدهد که API وضعیت ناوبری (Navigation State API) را پیادهسازی میکند.
برای اجرای این برنامه نمونه:
- اندروید اتو را روی یک HU پشتیبانیشده بسازید و فلش کنید. از دستورالعملهای ساخت و فلش کردن اندروید مخصوص دستگاه خود استفاده کنید. برای دستورالعملها، به بخش «استفاده از بردهای مرجع» مراجعه کنید.
- یک نمایشگر ثانویه فیزیکی را به HU وصل کنید (در صورت پشتیبانی) یا HU ثانویه مجازی را روشن کنید:
- در برنامه تنظیمات، حالت توسعهدهنده (Developer Mode) را انتخاب کنید.
- به تنظیمات > سیستم > پیشرفته > گزینههای توسعهدهنده > شبیهسازی نمایشگرهای ثانویه بروید.
- HU را دوباره راه اندازی کنید
- برای اجرای برنامه KitchenSink:
- کشو را باز کنید.
- به خوشه موسسه بروید.
- روی شروع فراداده کلیک کنید.
KitchenSink درخواست فوکوس NAVIGATION را میدهد که به سرویس DirectRenderingCluster دستور میدهد تا یک رابط کاربری شبیهسازی شده را در Instrument Cluster نمایش دهد.