ใช้ Instrument Cluster API (Android API) เพื่อแสดงแอปการนำทาง รวมถึง Google Maps บนจอแสดงผลรองในรถ เช่น ด้านหลังพวงมาลัยบนแผงหน้าปัด หน้านี้จะอธิบายวิธีสร้างบริการเพื่อควบคุมจอแสดงผลรองและผสานรวมบริการกับ CarService
เพื่อให้แอปการนำทางแสดงอินเทอร์เฟซผู้ใช้ได้
คำศัพท์
หน้านี้ใช้คำศัพท์ต่อไปนี้
CarManager
ที่ช่วยให้แอปภายนอกเปิดใช้งานกิจกรรมในแผงหน้าปัดและรับการเรียกกลับเมื่อแผงหน้าปัดพร้อมแสดงกิจกรรมandroid:singleUser
บริการจะทำงานในระบบ Android ได้สูงสุด 1 อินสแตนซ์ในแต่ละครั้งสิ่งที่ต้องมีก่อน
โปรดตรวจสอบว่าคุณมีองค์ประกอบต่อไปนี้ก่อนที่จะดําเนินการต่อ
- สภาพแวดล้อมการพัฒนา Android หากต้องการตั้งค่าสภาพแวดล้อมการพัฒนาซอฟต์แวร์ Android โปรดดูข้อกำหนดการสร้าง
- ดาวน์โหลดซอร์สโค้ด Android ดาวน์โหลดซอร์สโค้ด Android เวอร์ชันล่าสุดจากสาขา pi-car-release (หรือเวอร์ชันที่ใหม่กว่า) ที่ https://android.googlesource.com
- หน่วยหลัก (HU) อุปกรณ์ Android ที่ใช้งาน Android 9 (หรือเวอร์ชันที่ใหม่กว่า) ได้ อุปกรณ์นี้ต้องมีจอแสดงผลของตัวเองและสามารถแฟลชจอแสดงผลด้วยบิลด์ Android ใหม่
- หน้าปัดคือสิ่งใดสิ่งหนึ่งต่อไปนี้
- จอแสดงผลรองจริงที่แนบอยู่กับ HU หากฮาร์ดแวร์และเคอร์เนลของอุปกรณ์รองรับการจัดการจอแสดงผลหลายจอ
- หน่วยอิสระ หน่วยประมวลผลใดก็ตามที่เชื่อมต่อกับ HU ผ่านการเชื่อมต่อเครือข่าย ซึ่งสามารถรับและแสดงสตรีมวิดีโอบนจอแสดงผลของตัวเอง
- จอแสดงผลจำลอง ในระหว่างการพัฒนา คุณสามารถใช้สภาพแวดล้อมจำลองอย่างใดอย่างหนึ่งต่อไปนี้
- จอแสดงผลรองจำลอง หากต้องการเปิดใช้จอแสดงผลรองจำลองในระบบปฏิบัติการ AOSP ของ Android ให้ไปที่การตั้งค่าตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ในแอประบบการตั้งค่า แล้วเลือกจำลองจอแสดงผลรอง การกำหนดค่านี้จะเทียบเท่ากับการต่อจอแสดงผลรองจริง โดยมีข้อจำกัดคือจอแสดงผลนี้จะวางซ้อนทับจอแสดงผลหลัก
- หน้าปัดแบบจำลอง โปรแกรมจำลอง Android ที่รวมอยู่ใน AAOS มีตัวเลือกในการแสดงแผงหน้าปัดด้วย ClusterRenderingService
สถาปัตยกรรมการผสานรวม
คอมโพเนนต์การผสานรวม
การผสานรวม Instrument Cluster 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
ที่เชื่อมโยง
(ในกรณีนี้ bound หมายถึง Android Services)
บริการแผงหน้าปัด
OEM จะต้องสร้างแพ็กเกจ Android (APK) ที่มีคลาสย่อยของ ClusterRenderingService
ชั้นเรียนนี้มีวัตถุประสงค์ 2 อย่าง ได้แก่
- ให้อินเทอร์เฟซ Android และอุปกรณ์แสดงผลหน้าปัด (วัตถุประสงค์ของหน้านี้)
- รับและแสดงผลข้อมูลอัปเดตสถานะการนำทาง เช่น การแนะนำการนำทางแบบเลี้ยวต่อเลี้ยว
สำหรับวัตถุประสงค์แรก การใช้งาน InstrumentClusterRendererService
ของ OEM ต้องเริ่มต้นการแสดงผลรองที่ใช้แสดงผลข้อมูลบนหน้าจอในห้องโดยสารของรถยนต์ และสื่อสารข้อมูลนี้ไปยัง CarService
โดยการเรียกใช้เมธอด InstrumentClusterRendererService.setClusterActivityOptions()
และ InstrumentClusterRendererService.setClusterActivityState()
สำหรับฟังก์ชันที่ 2 บริการหน้าปัดต้องระบุการใช้งานอินเทอร์เฟซ ClusterRenderingService ที่ได้รับเหตุการณ์การอัปเดตสถานะการนำทาง ซึ่งเข้ารหัสเป็น eventType
และข้อมูลเหตุการณ์ที่เข้ารหัสในแพ็กเกจ
ลําดับการผสานรวม
แผนภาพต่อไปนี้แสดงการใช้งานสถานะการนำทางที่แสดงผลข้อมูลอัปเดต
ในภาพนี้ สีต่างๆ หมายถึงสิ่งต่อไปนี้
- สีเหลือง
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
คลาสนี้ควบคุมจอแสดงผลของแผงหน้าปัด และสามารถแสดงผลข้อมูล Navigation State API (ไม่บังคับ) - ในระหว่าง
onCreate()
ให้ใช้บริการนี้เพื่อเริ่มต้นการสื่อสารกับฮาร์ดแวร์การแสดงผล โดยมีตัวเลือกดังนี้- กำหนดจอแสดงผลรองที่จะใช้สำหรับหน้าปัด
- สร้างจอแสดงผลเสมือนเพื่อให้แอปหน้าปัดแสดงผลและส่งรูปภาพที่แสดงผลไปยังอุปกรณ์ภายนอก (โดยใช้รูปแบบสตรีมมิงวิดีโอ เช่น H.264)
- เมื่อจอแสดงผลที่ระบุไว้ข้างต้นพร้อมใช้งาน บริการนี้ต้องเรียกใช้
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()
เพื่อกำหนดActivityOptions
ที่แน่นอนซึ่งต้องใช้เพื่อแสดงกิจกรรมบนหน้าปัด ใช้พารามิเตอร์ต่อไปนี้category.
ClusterRenderingServiceActivityOptions.
อินสแตนซ์ActivityOptions
ที่ใช้เพื่อเปิดใช้งานกิจกรรมในแผงหน้าปัดได้ ตัวอย่างเช่น จากตัวอย่างการติดตั้งใช้งานหน้าปัดใน AOSPgetService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- เมื่อหน้าปัดพร้อมแสดงกิจกรรม บริการนี้จะต้องเรียกใช้
InstrumentClusterRenderingService#setClusterActivityState()
ใช้พารามิเตอร์ต่อไปนี้category
ClusterRenderingServicestate
Bundle ที่สร้างขึ้นด้วย 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 } ...
ภาคผนวก: ใช้แอปตัวอย่าง
AOSP มีตัวอย่างแอปที่ใช้ Navigation State API
วิธีเรียกใช้แอปตัวอย่างนี้
- สร้างและแฟลช Android Auto ใน HU ที่รองรับ ใช้วิธีการสร้างและแฟลช Android สำหรับอุปกรณ์ของคุณโดยเฉพาะ ดูวิธีการได้ที่หัวข้อการใช้บอร์ดอ้างอิง
- เชื่อมต่อจอแสดงผลรองจริงกับ HU (หากรองรับ) หรือเปิด HU รองเสมือน ดังนี้
- เลือกโหมดนักพัฒนาแอปในแอปการตั้งค่า
- ไปที่การตั้งค่า > ระบบ > ขั้นสูง > ตัวเลือกสำหรับนักพัฒนาแอป > simulasikan layar sekunder
- รีบูต HU
- วิธีเปิดแอป KitchenSink
- เปิดลิ้นชัก
- ไปที่ Inst. Cluster
- คลิกเริ่มข้อมูลเมตา
KitchenSink ขอโฟกัสการนําทาง ซึ่งจะสั่งให้DirectRenderingCluster
บริการแสดงอินเทอร์เฟซผู้ใช้จำลองบนหน้าปัด