ใช้ Instrument Cluster API (Android API) เพื่อแสดงแอปการนำทาง
รวมถึง Google Maps บนจอแสดงผลรองในรถยนต์ เช่น ด้านหลัง
พวงมาลัยบนแผงหน้าปัด หน้านี้จะอธิบายวิธีสร้างบริการเพื่อควบคุมจอแสดงผลรองและผสานรวมบริการกับ
CarService เพื่อให้แอปนำทางแสดง
ส่วนติดต่อผู้ใช้ได้
คำศัพท์
คำศัพท์ต่อไปนี้ใช้ในหน้านี้
CarManager ที่ช่วยให้แอปภายนอกเปิดกิจกรรมใน
แผงหน้าปัดและรับการเรียกกลับเมื่อแผงหน้าปัดพร้อมแสดง
กิจกรรมandroid:singleUser ในเวลาใดก็ตาม ระบบ Android จะเรียกใช้บริการได้สูงสุด 1 อินสแตนซ์สิ่งที่ต้องมีก่อน
โปรดตรวจสอบว่าคุณมีองค์ประกอบต่อไปนี้ก่อนดำเนินการต่อ
- สภาพแวดล้อมในการพัฒนาซอฟต์แวร์ Android หากต้องการตั้งค่าสภาพแวดล้อมในการพัฒนา Android โปรดดูข้อกำหนดในการสร้าง
- ดาวน์โหลดซอร์สโค้ด Android ดาวน์โหลดซอร์สโค้ด Android เวอร์ชันล่าสุดจาก Branch pi-car-release (หรือหลังจากนั้น) ที่ https://android.googlesource.com
- เครื่องเล่นวิทยุ (HU) อุปกรณ์ Android ที่ใช้ Android 9 (ขึ้นไป) ได้ อุปกรณ์นี้ต้องมีจอแสดงผลของตัวเองและสามารถ แฟลชจอแสดงผลด้วยบิลด์ใหม่ของ Android
- แผงหน้าปัดคือรายการใดรายการหนึ่งต่อไปนี้
- จอแสดงผลรองจริงที่ต่อกับ HU หากฮาร์ดแวร์และเคอร์เนลของอุปกรณ์รองรับการจัดการจอแสดงผลหลายจอ
- หน่วยอิสระ หน่วยประมวลผลใดก็ตามที่เชื่อมต่อกับ HU ผ่านการเชื่อมต่อเครือข่าย ซึ่งสามารถรับและแสดงสตรีมวิดีโอ บนจอแสดงผลของตัวเอง
- จอแสดงผลจำลอง ในระหว่างการพัฒนา คุณสามารถใช้สภาพแวดล้อมจำลองต่อไปนี้
- จอแสดงผลที่สองจำลอง หากต้องการเปิดใช้จอแสดงผลรองจำลองใน Android AOSP ทุกรุ่น ให้ไปที่การตั้งค่าตัวเลือกสำหรับนักพัฒนาแอป ในแอปการตั้งค่าระบบ แล้วเลือกจำลองจอแสดงผลรอง การกำหนดค่านี้เทียบเท่ากับการต่อจอแสดงผลรองจริง โดยมีข้อจำกัดคือจอแสดงผลนี้จะซ้อนทับบนจอแสดงผลหลัก
- แผงหน้าปัดที่จำลอง โปรแกรมจำลอง Android ที่รวมอยู่ใน AAOS มีตัวเลือกในการแสดงแผงหน้าปัดพร้อม ClusterRenderingService
สถาปัตยกรรมการผสานรวม
คอมโพเนนต์การผสานรวม
การผสานรวม API กลุ่มเครื่องมือประกอบด้วยคอมโพเนนต์ 3 อย่างต่อไปนี้
CarService- แอปนำทาง
- บริการแผงหน้าปัด OEM

บริการด้านรถยนต์
CarServiceทำหน้าที่เป็นตัวกลางระหว่างแอปนำทางกับรถยนต์ เพื่อให้มั่นใจว่าจะมีแอปนำทางที่ใช้งานอยู่เพียงแอปเดียวในแต่ละครั้ง และมีเพียงแอปที่มีสิทธิ์ android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL เท่านั้นที่ส่งข้อมูลไปยังรถยนต์ได้
CarService เริ่มต้นบริการทั้งหมดที่เฉพาะเจาะจงสำหรับรถยนต์และให้สิทธิ์เข้าถึง
บริการเหล่านี้ผ่านชุดเครื่องมือจัดการ หากต้องการโต้ตอบกับบริการ
แอปที่ทำงานในรถยนต์จะเข้าถึงตัวจัดการเหล่านี้ได้
สำหรับการติดตั้งคลัสเตอร์เครื่องมือ OEM ยานยนต์ต้องสร้างการติดตั้งใช้งาน InstrumentClusterRendererService ที่กำหนดเองและอัปเดต ClusterRenderingService
เมื่อแสดงผลแผงหน้าปัด ในระหว่างกระบวนการบูต
CarService จะอ่านคีย์ InstrumentClusterRendererService ของ
ClusterRenderingService
เพื่อค้นหาการติดตั้งใช้งาน InstrumentClusterService ใน AOSP รายการนี้
ชี้ไปยังบริการแสดงผลการติดตั้งใช้งานคลัสเตอร์ตัวอย่างของ Navigation State API
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
ระบบได้เริ่มต้นใช้งานและเชื่อมโยงบริการที่อ้างอิงในรายการนี้กับ
CarService แล้ว เมื่อแอปนำทาง เช่น Google Maps ขอ
CarInstrumentClusterManager CarService จะให้ตัวจัดการที่
อัปเดตสถานะแผงหน้าปัดจาก InstrumentClusterRenderingService ที่เชื่อมโยง
(ในกรณีนี้ ผูกหมายถึง
บริการของ Android)
บริการแผงหน้าปัด
OEM ต้องสร้างแพ็กเกจ Android (APK) ที่มีคลาสย่อยของ ClusterRenderingService
ชั้นเรียนนี้มีวัตถุประสงค์ 2 ประการ ได้แก่
- มีอินเทอร์เฟซสำหรับ Android และอุปกรณ์การแสดงผลแผงหน้าปัด (วัตถุประสงค์ของหน้านี้)
- รับและแสดงผลการอัปเดตสถานะการนำทาง เช่น คำแนะนำการนำทางแบบเลี้ยวต่อเลี้ยว
สำหรับวัตถุประสงค์แรก การติดตั้งใช้งาน InstrumentClusterRendererService ของ OEM
ต้องเริ่มต้นการแสดงผลรองที่ใช้ในการแสดงข้อมูลบนหน้าจอในห้องโดยสารของรถยนต์ และ
สื่อสารข้อมูลนี้ไปยัง CarService โดยการเรียกใช้เมธอด InstrumentClusterRendererService.setClusterActivityOptions() และ InstrumentClusterRendererService.setClusterActivityState()
สำหรับฟังก์ชันที่ 2 บริการแผงหน้าปัดต้องมี
การติดตั้งใช้งาน
ClusterRenderingService
อินเทอร์เฟซที่รับเหตุการณ์การอัปเดตสถานะการนำทาง ซึ่งเข้ารหัสเป็น
eventType และข้อมูลเหตุการณ์ที่เข้ารหัสใน Bundle
ลำดับการผสานรวม
แผนภาพต่อไปนี้แสดงการใช้สถานะการนำทาง ที่แสดงผลการอัปเดต
ในภาพนี้ สีต่างๆ หมายถึงสิ่งต่อไปนี้
- เหลือง
CarServiceและCarNavigationStatusManagerจัดทำโดยแพลตฟอร์ม Android ดูข้อมูลเพิ่มเติมได้ที่ Car และ CAR_NAVIGATION_SERVICE - เขียวแกมน้ำเงิน
InstrumentClusterRendererServiceที่ OEM ใช้งาน - สีม่วง แอปนำทางที่ Google และนักพัฒนาแอปบุคคลที่สาม นำมาใช้
- เขียว
CarAppFocusManagerดูข้อมูลเพิ่มเติมได้ที่ การใช้ CarAppFocusManager API ด้านล่างและ CarAppFocusManager
โฟลว์ข้อมูลสถานะการนำทางเป็นไปตามลำดับต่อไปนี้
CarServiceจะเริ่มต้นInstrumentClusterRenderingService- ในระหว่างการเริ่มต้น
InstrumentClusterRenderingServiceจะอัปเดตCarServiceด้วยข้อมูลต่อไปนี้- แสดงพร็อพเพอร์ตี้ของแผงหน้าปัด เช่น ขอบเขตที่ไม่บดบัง (ดูรายละเอียดเพิ่มเติมเกี่ยวกับขอบเขตที่ไม่บดบังในภายหลัง)
- ตัวเลือกกิจกรรมที่จำเป็นในการเปิดใช้กิจกรรมภายในจอแสดงผลแผงหน้าปัด ดูข้อมูลเพิ่มเติมได้ที่ ActivityOptions
- แอปการนำทาง (เช่น Google Maps สำหรับ Android Automotive หรือแอปแผนที่ใดก็ได้
ที่มีสิทธิ์ที่จำเป็น) ดังนี้
- รับ
CarAppFocusManagerโดยใช้คลาส Car จาก car-lib - ก่อนที่การนำทางแบบเลี้ยวต่อเลี้ยวจะเริ่มขึ้น ให้เรียกใช้
CarAppFocusManager.requestFocus()เพื่อส่งCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONเป็นพารามิเตอร์appType
- รับ
CarAppFocusManagerจะสื่อสารคำขอนี้กับCarServiceหากได้รับอนุญาตCarServiceจะตรวจสอบแพ็กเกจแอปนำทางและค้นหากิจกรรมที่ทำเครื่องหมายด้วยหมวดหมู่android.car.cluster.NAVIGATION- หากพบ แอปนำทางจะใช้
ActivityOptionsที่รายงานโดยInstrumentClusterRenderingServiceเพื่อเปิดใช้กิจกรรม และรวม พร็อพเพอร์ตี้การแสดงผลของแผงหน้าปัดเป็นส่วนเสริมใน Intent
ผสานรวม API
การใช้งาน InstrumentClusterRenderingService ต้องมีลักษณะดังนี้
- ได้รับการกำหนดให้เป็นบริการแบบ Singleton โดยการเพิ่มค่าต่อไปนี้ลงใน
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คลาสนี้ ควบคุมการแสดงผลของแผงหน้าปัดและสามารถแสดงผลข้อมูล API ของสถานะการนำทางได้ (ไม่บังคับ) - ในระหว่าง
onCreate()ให้ใช้บริการนี้เพื่อเริ่มต้นการสื่อสารกับ ฮาร์ดแวร์การแสดงผล โดยมีตัวเลือกดังนี้- กำหนดจอแสดงผลรองที่จะใช้สำหรับแผงหน้าปัด
- สร้างจอแสดงผลเสมือนเพื่อให้แอปแผงหน้าปัดแสดงผลและส่ง รูปภาพที่แสดงผลไปยังหน่วยภายนอก (โดยใช้รูปแบบการสตรีมวิดีโอ เช่น H.264)
- เมื่อจอแสดงผลที่ระบุไว้ข้างต้นพร้อมใช้งาน บริการนี้ต้องเรียกใช้
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()เพื่อกำหนดActivityOptionsที่แน่นอนซึ่งต้องใช้เพื่อแสดงกิจกรรมใน แผงหน้าปัด ใช้พารามิเตอร์ต่อไปนี้category.ClusterRenderingServiceActivityOptions.ActivityOptionsอินสแตนซ์ที่ใช้เปิดกิจกรรมในแผงหน้าปัดได้ ตัวอย่างเช่น จากการติดตั้งใช้งานแผงหน้าปัดตัวอย่างใน AOSPgetService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- เมื่อแผงหน้าปัดพร้อมแสดงกิจกรรมแล้ว บริการนี้จะต้องเรียกใช้
InstrumentClusterRenderingService#setClusterActivityState()ใช้พารามิเตอร์ต่อไปนี้categoryClusterRenderingServicestateบันเดิลที่สร้างด้วย ClusterRenderingService โปรดระบุข้อมูลต่อไปนี้visibleระบุแผงหน้าปัดให้มองเห็นและพร้อม แสดงเนื้อหาunobscuredBoundsสี่เหลี่ยมผืนผ้าที่กำหนดพื้นที่ภายใน จอแสดงผลแผงหน้าปัดซึ่งแสดงเนื้อหาได้อย่างปลอดภัย เช่น พื้นที่ ที่ครอบคลุมโดยแป้นหมุนและเกจ
- แทนที่เมธอด
Service#dump()และรายงานข้อมูลสถานะที่เป็นประโยชน์สำหรับการ แก้ไขข้อบกพร่อง (ดูข้อมูลเพิ่มเติมได้ที่ dumpsys )
ตัวอย่างการใช้งาน InstrumentClusterRenderingService
ตัวอย่างต่อไปนี้แสดงInstrumentClusterRenderingService
การติดตั้งใช้งาน ซึ่งสร้าง VirtualDisplay เพื่อนำเสนอเนื้อหาคลัสเตอร์เครื่องมือ
บนจอแสดงผลจริงที่อยู่ระยะไกล
หรือโค้ดนี้อาจส่ง 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); } }
ใช้ CarAppFocusManager API
CarAppFocusManager API มีเมธอดชื่อ getAppTypeOwner() ซึ่งช่วยให้ บริการคลัสเตอร์ที่ OEM เขียนทราบว่าแอปนำทางใดมีโฟกัสการไปยังส่วนต่างๆ ในเวลาใดก็ตาม OEM สามารถใช้วิธี CarAppFocusManager#addFocusListener() ที่มีอยู่ แล้วใช้ getAppTypeOwner() เพื่อดูว่าแอปใดมีโฟกัส ข้อมูลนี้ช่วยให้ OEM ทำสิ่งต่อไปนี้ได้
- เปลี่ยนกิจกรรมที่แสดงในคลัสเตอร์เป็นกิจกรรมคลัสเตอร์ที่แอปนำทางระบุ โดยคงโฟกัสไว้
- ตรวจหาได้ว่าแอปนำทางที่โฟกัสมีกิจกรรมคลัสเตอร์หรือไม่ หากแอปนำทางที่โฟกัส ไม่มีกิจกรรมคลัสเตอร์ (หรือหากปิดใช้กิจกรรมดังกล่าว) 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(..)เพื่อดึงข้อมูลชื่อแพ็กเกจ
ของเจ้าของปัจจุบันของแอปประเภทหนึ่งๆ ที่กำลังโฟกัส วิธีนี้อาจแสดงชื่อแพ็กเกจมากกว่า 1 รายการหากเจ้าของปัจจุบันใช้ฟีเจอร์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)
เนื่องจากโฮสต์จะถือโฟกัสของระบบในนามของแอปไคลเอ็นต์
หากต้องการระบุแอปไคลเอ็นต์ที่ใช้ในการไปยังส่วนต่างๆ OEM สามารถ
ดึงชื่อแพ็กเกจจากชุดสถานะการนำทางที่ส่งพร้อมกับ
CarNavigationStatusManager ระบบจะจัดเก็บชื่อแพ็กเกจไว้ภายใต้คีย์ active_app_package_name ใน App Bundle ที่ได้รับจาก
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 ใน HU ที่รองรับ ใช้ วิธีการสร้างและแฟลช Android ที่เฉพาะเจาะจงสำหรับอุปกรณ์ของคุณ ดูวิธีการได้ที่ การใช้บอร์ดอ้างอิง
- เชื่อมต่อจอแสดงผลรองจริงกับ HU (หากรองรับ) หรือเปิด HU รองเสมือน
:
- เลือกโหมดนักพัฒนาแอปในแอปการตั้งค่า
- ไปที่การตั้งค่า > ระบบ > ขั้นสูง > ตัวเลือกสำหรับนักพัฒนาแอป > จำลองจอแสดงผลรอง
- รีบูต HU
- วิธีเปิดแอป KitchenSink
- เปิดลิ้นชัก
- ไปที่ Inst. Cluster
- คลิกเริ่มข้อมูลเมตา
KitchenSink จะขอโฟกัสการนำทาง ซึ่งจะสั่งให้DirectRenderingCluster
บริการแสดงอินเทอร์เฟซผู้ใช้จำลองบนแผงหน้าปัด