คลังแอป Android for Cars ช่วยให้คุณสามารถนำการนำทาง จุดที่น่าสนใจ (POI) และอินเทอร์เน็ตของสรรพสิ่ง (IOT) ของคุณ ลงในรถยนต์ โดยมอบชุดเทมเพลตที่ออกแบบมาเพื่อตอบสนองสิ่งรบกวนผู้ขับขี่ และดูแลรายละเอียดต่างๆ เช่น ปัจจัยต่างๆ ของหน้าจอรถ และวิธีการป้อนข้อมูล
คู่มือนี้จะให้ภาพรวมเกี่ยวกับฟีเจอร์และแนวคิดหลักของไลบรารีและ จะแนะนำขั้นตอนการตั้งค่าแอปพื้นฐาน
ก่อนเริ่มต้น
- ทบทวนการออกแบบสำหรับการขับรถ
หน้าที่ครอบคลุมไลบรารีแอปรถยนต์
- แอปการนำทาง และแอปอื่นๆ เกี่ยวกับการขับขี่ ภาพรวมหมวดหมู่
- ภาพรวมสร้างแอปด้วยเทมเพลต
- องค์ประกอบที่ใช้สร้างสรรค์ ซึ่งครอบคลุมเทมเพลตและคอมโพเนนต์ของเทมเพลต
- ขั้นตอนตัวอย่าง เพื่อแสดงให้เห็นถึงรูปแบบ UX ทั่วไป
- ข้อกำหนดของแอปที่เป็นเทมเพลต
- อ่านคำและแนวคิดสำคัญในเรื่องต่อไปนี้
- ทำความคุ้นเคยกับระบบ Android Auto UI และ Android Automotive OS การออกแบบ
- อ่านบันทึกประจำรุ่น
- ดูตัวอย่าง
คำสำคัญและแนวคิด
- โมเดลและเทมเพลต
- อินเทอร์เฟซผู้ใช้จะแสดงเป็นกราฟของออบเจ็กต์โมเดลที่สามารถ จัดเรียงไว้ด้วยกันในรูปแบบต่างๆ ตามที่ได้รับอนุญาตโดยเทมเพลต เป็น เทมเพลตเป็นชุดย่อยของโมเดลซึ่งทำหน้าที่เป็นรูทของเทมเพลตเหล่านั้น กราฟ โมเดลประกอบด้วยข้อมูลที่แสดงต่อผู้ใช้ใน ข้อความและรูปภาพ รวมถึงแอตทริบิวต์เพื่อกำหนดค่าแง่มุมต่างๆ ลักษณะที่ปรากฏของข้อมูลดังกล่าว เช่น สีข้อความหรือรูปภาพ ขนาดต่างๆ โฮสต์จะแปลงโมเดลเป็นมุมมองที่ออกแบบมาเพื่อเป็นไปตาม มาตรฐานสิ่งรบกวนผู้ขับขี่และดูแลรายละเอียดต่างๆ เช่น ความหลากหลาย ของปัจจัยหน้าจอรถและวิธีป้อนข้อมูล
- เป็นเจ้าภาพ
- โฮสต์คือคอมโพเนนต์แบ็กเอนด์ที่ใช้ฟังก์ชันการทำงานที่มีให้บริการ API ของไลบรารีเพื่อให้แอปของคุณทำงานในรถได้ ซึ่งโฮสต์ก็มีตั้งแต่การค้นพบแอปและการจัดการ วงจรในการแปลงโมเดลเป็นข้อมูลพร็อพเพอร์ตี้และแจ้งเตือนแอปของคุณ การโต้ตอบของผู้ใช้ ในอุปกรณ์เคลื่อนที่ Android จะใช้โฮสต์นี้ อัตโนมัติ ใน Android Automotive OS โฮสต์นี้จะติดตั้งเป็นแอประบบ
- ข้อจำกัดของเทมเพลต
- เทมเพลตที่แตกต่างกันจะบังคับใช้ข้อจำกัดในเนื้อหาของโมเดล สำหรับ เช่น เทมเพลตรายการมีการจำกัดจำนวนรายการที่สามารถ ที่แสดงให้ผู้ใช้เห็น เทมเพลตยังมีข้อจำกัดในด้านวิธีดำเนินการ เพื่อสร้างโฟลว์ของงาน เช่น แอปสามารถพุช เทมเพลตลงในกองหน้าจอได้ถึง 5 เทมเพลต โปรดดู ดูรายละเอียดเพิ่มเติมได้ที่ข้อจำกัดของเทมเพลต
Screen
Screen
คือชั้นเรียนที่ ที่แอปพลิเคชันนำมาใช้เพื่อจัดการอินเทอร์เฟซผู้ใช้ ผู้ใช้Screen
มี วงจร และให้กลไกสำหรับแอปในการ ส่งเทมเพลตเพื่อแสดงเมื่อหน้าจอปรากฏ สามารถพุชอินสแตนซ์Screen
รายการได้ด้วย และเปลี่ยนจากScreen
สแต็ก ซึ่ง เป็นไปตามข้อกำหนดของ ข้อจำกัดสำหรับขั้นตอนของเทมเพลตCarAppService
CarAppService
เป็น AbstractService
ที่แอปของคุณ ติดตั้งใช้งานและส่งออกเพื่อให้โฮสต์ค้นพบและจัดการCarAppService
ของแอปคุณ ซึ่งมีหน้าที่ตรวจสอบว่าการเชื่อมต่อโฮสต์เชื่อถือได้โดยใช้createHostValidator
และมอบSession
ในภายหลัง อินสแตนซ์สำหรับการเชื่อมต่อแต่ละรายการโดยใช้onCreateSession
Session
Session
เป็นคลาสนามธรรมที่ แอปของคุณต้องใช้และกลับมาใช้CarAppService.onCreateSession
ซึ่งทำหน้าที่เป็นจุดแรกเข้าในการแสดงข้อมูลบนหน้าจอของรถยนต์ ทั้งนี้ มีวงจรที่ให้ข้อมูล สถานะปัจจุบันของแอปบนหน้าจอของรถยนต์ เช่น เมื่อแอป มองเห็นได้หรือซ่อนอยู่เมื่อเริ่มการทำงานของ
Session
เช่น เมื่อแอปเปิดขึ้นเป็นครั้งแรก โฮสต์จะขอScreen
เพื่อแสดงโดยใช้onCreateScreen
ติดตั้งไลบรารีแอปรถยนต์
ดูไลบรารี Jetpack หน้าเผยแพร่สำหรับ วิธีการเพิ่มไลบรารีลงในแอปของคุณ
กำหนดค่าไฟล์ Manifest ของแอป
ก่อนจะสร้างแอปสำหรับรถยนต์ ให้กำหนดค่าแอป ไฟล์ Manifest ดังนี้
ประกาศ CarAppService ของคุณ
โฮสต์เชื่อมต่อกับแอปของคุณผ่าน
CarAppService
คุณ
ประกาศบริการนี้ในไฟล์ Manifest เพื่อให้โฮสต์ค้นพบและเชื่อมต่อ
กับแอปของคุณ
คุณต้องประกาศหมวดหมู่ของแอปใน
<category>
ขององค์ประกอบของแอป
Intent ดูรายการ
หมวดหมู่แอปที่รองรับสำหรับค่าที่อนุญาต
องค์ประกอบนี้
ข้อมูลโค้ดต่อไปนี้แสดงวิธีประกาศบริการแอปรถยนต์สำหรับ แอปพลิเคชันความสนใจในไฟล์ Manifest ของคุณ
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService"/>
<category android:name="androidx.car.app.category.POI"/>
</intent-filter>
</service>
...
<application>
หมวดหมู่แอปที่รองรับ
ประกาศหมวดหมู่ของแอปโดยเพิ่มหมวดหมู่ต่อไปนี้อย่างน้อย 1 หมวดหมู่
ในตัวกรอง Intent เมื่อคุณประกาศ CarAppService
ตามที่ได้อธิบายไว้
ในส่วนก่อนหน้านี้
androidx.car.app.category.NAVIGATION
: แอปที่ให้บริการแบบเลี้ยวต่อเลี้ยว เส้นทางการนำทาง ลองดูสร้างแอปการนำทางสำหรับรถยนต์ เพื่อดูเอกสารเพิ่มเติมในหมวดหมู่นี้androidx.car.app.category.POI
: แอปที่มีฟังก์ชันการทำงานเกี่ยวข้องกับ เพื่อหาจุดที่น่าสนใจ เช่น จุดจอดรถ สถานีชาร์จ และ ปั๊มน้ำมัน เช็คเอาต์ สร้างแอปจุดสนใจสำหรับรถยนต์เพื่อ เอกสารเพิ่มเติมในหมวดหมู่นี้androidx.car.app.category.IOT
: แอปที่ช่วยให้ผู้ใช้สามารถใช้ การดำเนินการบนอุปกรณ์ที่เชื่อมต่อจากภายในรถ เช็คเอาต์ สร้างแอปอินเทอร์เน็ตของสรรพสิ่งสำหรับรถยนต์เพื่อ เอกสารเพิ่มเติมในหมวดหมู่นี้
ดูคุณภาพแอป Android สำหรับรถยนต์สำหรับ คำอธิบายโดยละเอียดของแต่ละหมวดหมู่และเกณฑ์เพื่อให้แอปเป็นของแอปนั้น
ระบุชื่อและไอคอนแอป
คุณต้องระบุชื่อและไอคอนแอปที่โฮสต์ใช้เพื่อแสดง ใน UI ของระบบ
คุณระบุชื่อและไอคอนแอปที่จะใช้แสดงแอปได้โดยใช้
label
และ
แอตทริบิวต์ icon
ของ
CarAppService
:
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
หากไม่มีการประกาศป้ายกำกับหรือไอคอนใน
<service>
เอลิเมนต์, โฮสต์
กลับไปเป็นค่าที่ระบุสำหรับ
องค์ประกอบ <application>
ตั้งค่าธีมที่กำหนดเอง
หากต้องการตั้งค่าธีมที่กำหนดเองสำหรับแอปสำหรับรถยนต์ ให้เพิ่ม
<meta-data>
ใน
ไฟล์ Manifest ดังนี้
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
จากนั้นประกาศทรัพยากรสไตล์เป็น ตั้งค่าแอตทริบิวต์ต่อไปนี้สำหรับธีมแอปรถยนต์ที่กำหนดเอง
<resources> <style name="MyCarAppTheme"> <item name="carColorPrimary">@layout/my_primary_car_color</item> <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item> <item name="carColorSecondary">@layout/my_secondary_car_color</item> <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
ระดับ API ของแอปรถยนต์
ไลบรารีแอปรถยนต์จะกำหนดระดับ API ของตนเองเพื่อให้คุณรู้ว่า
ฟีเจอร์คลังใช้ได้กับโฮสต์เทมเพลตในยานพาหนะ
หากต้องการเรียกข้อมูลระดับ API ของแอปรถยนต์สูงสุดที่โฮสต์รองรับ ให้ใช้
getCarAppApiLevel()
ประกาศระดับ API ของแอปรถยนต์ขั้นต่ำที่แอปของคุณรองรับใน
AndroidManifest.xml
ไฟล์:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
โปรดดูเอกสารประกอบสำหรับ
RequiresCarApi
สำหรับรายละเอียดเกี่ยวกับวิธีการรักษาความเข้ากันได้แบบย้อนหลังและประกาศ
ระดับ API ขั้นต่ำที่จำเป็นในการใช้ฟีเจอร์ ดูคำจำกัดความของ API
ก่อนที่จะใช้ฟีเจอร์บางอย่างของไลบรารีแอปรถยนต์ ให้ตรวจสอบ
เอกสารอ้างอิงสำหรับ
CarAppApiLevels
สร้าง CarAppService และเซสชันของคุณ
แอปของคุณจำเป็นต้องขยาย
CarAppService
และการนำไปใช้
onCreateSession
ซึ่งแสดงผล Session
อินสแตนซ์ที่สอดคล้องกับการเชื่อมต่อปัจจุบันกับโฮสต์:
Kotlin
class HelloWorldService : CarAppService() { ... override fun onCreateSession(): Session { return HelloWorldSession() } ... }
Java
public final class HelloWorldService extends CarAppService { ... @Override @NonNull public Session onCreateSession() { return new HelloWorldSession(); } ... }
อินสแตนซ์ Session
มีหน้าที่
จะส่งคืนอินสแตนซ์ Screen
เพื่อใช้พร็อพเพอร์ตี้
ครั้งแรกที่เปิดแอป ให้ทำดังนี้
Kotlin
class HelloWorldSession : Session() { ... override fun onCreateScreen(intent: Intent): Screen { return HelloWorldScreen(carContext) } ... }
Java
public final class HelloWorldSession extends Session { ... @Override @NonNull public Screen onCreateScreen(@NonNull Intent intent) { return new HelloWorldScreen(getCarContext()); } ... }
เพื่อรับมือกับสถานการณ์ที่แอปสำหรับรถยนต์ต้องเริ่มต้นจากหน้าจอที่ไม่ใช่
หน้าแรกหรือหน้าจอ Landing Page ของแอป เช่น การจัดการ Deep Link คุณสามารถ
การซ้อนหน้าจอย้อนหลังโดยใช้
ScreenManager.push
ก่อนกลับจาก
onCreateScreen
การกำหนดล่วงหน้าช่วยให้ผู้ใช้สามารถย้อนกลับไปยังหน้าจอก่อนหน้าตั้งแต่หน้าจอแรก
ที่แอปของคุณแสดงอยู่
สร้างหน้าจอเริ่มต้น
คุณสามารถสร้างหน้าจอที่แอปของคุณแสดงได้ด้วยการกำหนดคลาสที่ขยาย
Screen
คลาสและการนำไปใช้งาน
onGetTemplate
ซึ่งจะแสดงผล
อินสแตนซ์ Template
รายการที่แสดง
สถานะ UI ที่จะแสดงในหน้าจอของรถ
ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีประกาศ
Screen
ที่ใช้องค์ประกอบ
PaneTemplate
เทมเพลตสำหรับ
แสดงข้อความ "สวัสดีทุกคน" ง่ายๆ สตริง:
Kotlin
class HelloWorldScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val row = Row.Builder().setTitle("Hello world!").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
Java
public class HelloWorldScreen extends Screen { @NonNull @Override public Template onGetTemplate() { Row row = new Row.Builder().setTitle("Hello world!").build(); Pane pane = new Pane.Builder().addRow(row).build(); return new PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build(); } }
คลาส CarContext
ชั้นเรียน CarContext
คือ
คลาสย่อย ContextWrapper
เข้าถึงได้จาก Session
และ
Screen
อินสแตนซ์ ให้สิทธิ์เข้าถึง
การบริการรถยนต์ เช่น
ScreenManager
สำหรับการจัดการ
การกองซ้อนหน้าจอ เวลา
AppManager
สำหรับผู้ใช้ทั่วไปเกี่ยวกับแอป
ฟังก์ชันการทำงาน เช่น การเข้าถึงออบเจ็กต์ Surface
สำหรับการวาดแผนที่
และ NavigationManager
ใช้โดยแอปนำทางแบบเลี้ยวต่อเลี้ยวเพื่อสื่อสารการนำทาง
ข้อมูลเมตาและอื่นๆ
เกี่ยวกับการนำทาง
กิจกรรมกับ
ผู้จัด
โปรดดูที่การเข้าถึงการนำทาง เทมเพลตสำหรับ รายการฟังก์ชันการทำงานทั้งหมดของคลังที่พร้อมใช้งานสำหรับแอปนำทาง
CarContext
ยังมีข้อเสนออื่นๆ
ฟังก์ชันอย่างเช่น ให้คุณโหลดทรัพยากรที่ถอนออกได้โดยใช้การกำหนดค่า
จากหน้าจอของรถ การเริ่มแอปในรถโดยใช้ Intent
และส่งสัญญาณว่าแอปควรแสดงแผนที่ในธีมมืดหรือไม่
ใช้การนำทางในหน้าจอ
แอปมักแสดงหน้าจอที่แตกต่างกัน แต่ละหน้าจออาจใช้ เทมเพลตต่างๆ ที่ผู้ใช้เลือกดูได้ขณะมีการโต้ตอบด้วย อินเทอร์เฟซที่แสดงบนหน้าจอ
ชั้นเรียน ScreenManager
จะมี
การกองซ้อนหน้าจอที่คุณสามารถใช้เพื่อดันหน้าจอที่สามารถแสดงโดยอัตโนมัติ
เมื่อผู้ใช้เลือกปุ่มย้อนกลับในหน้าจอของรถหรือใช้ฮาร์ดแวร์กลับ
ในรถบางรุ่น
ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีเพิ่มการดำเนินการย้อนกลับไปยังเทมเพลตข้อความเป็น รวมถึงการทำงานที่พุชหน้าจอใหม่เมื่อผู้ใช้เลือก
Kotlin
val template = MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( Action.Builder() .setTitle("Next screen") .setOnClickListener { screenManager.push(NextScreen(carContext)) } .build()) .build()
Java
MessageTemplate template = new MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( new Action.Builder() .setTitle("Next screen") .setOnClickListener( () -> getScreenManager().push(new NextScreen(getCarContext()))) .build()) .build();
ออบเจ็กต์ Action.BACK
คือ
Action
มาตรฐานที่กำหนดให้โดยอัตโนมัติ
เรียกใช้ ScreenManager.pop
คุณสามารถลบล้างลักษณะการทำงานนี้ได้โดยใช้
OnBackPressedDispatcher
อินสแตนซ์ที่ใช้ได้จาก
CarContext
กองหน้าจออาจมีหน้าจอเพื่อให้มั่นใจว่าแอปปลอดภัยเมื่อใช้ขณะขับรถ สูงสุด ความลึก 5 หน้าจอ ดูข้อจำกัดของเทมเพลต เพื่อดูรายละเอียดเพิ่มเติม
รีเฟรชเนื้อหาของเทมเพลต
แอปของคุณสามารถขอเนื้อหาของ
Screen
เป็นโมฆะด้วยการเรียกใช้
Screen.invalidate
ผู้จัดการประชุมเรียกกลับไปยังแอปพลิเคชันของคุณ
Screen.onGetTemplate
เพื่อเรียกเทมเพลตที่มีเนื้อหาใหม่
เมื่อรีเฟรช Screen
การทำความเข้าใจเนื้อหาที่เจาะจงในเทมเพลตที่ได้รับการอัปเดต
ดังนั้นโฮสต์จะไม่นับเทมเพลตใหม่ในโควต้าเทมเพลต
ดูรายละเอียดเพิ่มเติมได้ที่ส่วนข้อจำกัดของเทมเพลต
เราขอแนะนำให้คุณกำหนดโครงสร้างหน้าจอ
เพื่อให้เป็นแบบ 1 ต่อ 1
การแมประหว่าง Screen
และประเภทของ
เทมเพลตที่แสดงผลผ่านการใช้ onGetTemplate
วาดแผนที่
แอปการนำทางและจุดสนใจ (POI) ที่ใช้เทมเพลตต่อไปนี้สามารถ
วาดแผนที่โดยการเข้าถึง Surface
:
เทมเพลต | สิทธิ์เทมเพลต | คำแนะนำเกี่ยวกับหมวดหมู่ |
---|---|---|
NavigationTemplate |
androidx.car.app.NAVIGATION_TEMPLATES |
การนำทาง |
MapWithContentTemplate |
androidx.car.app.NAVIGATION_TEMPLATES หรือ androidx.car.app.MAP_TEMPLATES |
การนำทาง, จุดที่น่าสนใจ |
MapTemplate (เลิกใช้งานแล้ว) |
androidx.car.app.NAVIGATION_TEMPLATES |
การนำทาง |
PlaceListNavigationTemplate (เลิกใช้งานแล้ว) |
androidx.car.app.NAVIGATION_TEMPLATES |
การนำทาง |
RoutePreviewNavigationTemplate (เลิกใช้งานแล้ว) |
androidx.car.app.NAVIGATION_TEMPLATES |
การนำทาง |
ประกาศสิทธิ์ใช้งานแพลตฟอร์ม
นอกเหนือจากสิทธิ์ที่จำเป็นสำหรับเทมเพลตที่แอปของคุณใช้อยู่
แอปของคุณต้องประกาศสิทธิ์ androidx.car.app.ACCESS_SURFACE
ใน
AndroidManifest.xml
เพื่อเข้าถึงแพลตฟอร์ม:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
...
</manifest>
เข้าถึงพื้นผิว
หากต้องการเข้าถึง Surface
ที่โฮสต์มีให้ คุณต้องใช้
SurfaceCallback
และระบุ
การนำไปใช้งานกับ AppManager
บริการรถยนต์ ระบบส่งต่อSurface
ปัจจุบันไปยัง
SurfaceCallback
ในพารามิเตอร์ SurfaceContainer
ของ
Callback onSurfaceAvailable()
และ onSurfaceDestroyed()
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
ทำความเข้าใจพื้นที่ที่มองเห็นของพื้นผิว
โฮสต์สามารถวาดองค์ประกอบของอินเทอร์เฟซผู้ใช้สำหรับเทมเพลตนอกเหนือจาก
แผนที่ โฮสต์สื่อสารเกี่ยวกับพื้นที่ของแพลตฟอร์มที่รับประกันว่า
ไม่มีสิ่งกีดขวางและมองเห็นได้ทั้งหมดแก่ผู้ใช้ด้วยการเรียก
SurfaceCallback.onVisibleAreaChanged
นอกจากนี้ ในการลดจำนวนการเปลี่ยนแปลง โฮสต์จะเรียก
SurfaceCallback.onStableAreaChanged
ด้วยสี่เหลี่ยมผืนผ้าเล็กที่สุด ซึ่งจะแสดงเสมอโดยอิงจาก
เทมเพลตปัจจุบัน
ตัวอย่างเช่น เมื่อแอปนำทางใช้
NavigationTemplate
ที่มีแถบการทำงานด้านบน แถบการดำเนินการสามารถซ่อนได้
เองเมื่อผู้ใช้ไม่ได้โต้ตอบกับหน้าจอสักระยะหนึ่งเพื่อเพิ่ม
สำหรับแผนที่ ในกรณีนี้ มีการติดต่อกลับไปยัง onStableAreaChanged
และ
onVisibleAreaChanged
ที่มีสี่เหลี่ยมผืนผ้าเดียวกัน เมื่อแถบการทำงานซ่อนอยู่
มีเพียง onVisibleAreaChanged
เท่านั้นที่จะถูกเรียกด้วยพื้นที่ที่ใหญ่กว่า หากผู้ใช้
โต้ตอบกับหน้าจอ จากนั้นจึงเรียกใช้เฉพาะ onVisibleAreaChanged
ด้วย
สี่เหลี่ยมผืนผ้าแรก
รองรับธีมมืด
แอปต้องวาดแผนที่ของตนซ้ำบนอินสแตนซ์ Surface
ด้วยโหมดมืดที่เหมาะสม
สีเมื่อโฮสต์ระบุว่าเงื่อนไขควร ตามที่อธิบายไว้ใน
คุณภาพแอป Android สำหรับรถยนต์
หากต้องการตัดสินใจว่าจะวาดแผนที่แบบมืดหรือไม่ คุณสามารถใช้
CarContext.isDarkMode
เมื่อใดก็ตามที่สถานะธีมมืดเปลี่ยนแปลง คุณจะได้รับสายเรียกเข้า
Session.onCarConfigurationChanged
ให้ผู้ใช้สามารถโต้ตอบกับแผนที่ของคุณ
เมื่อใช้เทมเพลตต่อไปนี้ คุณจะสามารถเพิ่มการสนับสนุนเพื่อให้ผู้ใช้โต้ตอบ กับแผนที่ที่คุณวาด เช่น ทำให้พวกเขาเห็นส่วนต่างๆ ของแผนที่ รวมถึงการซูมเข้าและเลื่อน
เทมเพลต | รองรับการโต้ตอบตั้งแต่ระดับ API ของแอปรถยนต์ |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (เลิกใช้งานแล้ว) |
4 |
RoutePreviewNavigationTemplate (เลิกใช้งานแล้ว) |
4 |
MapTemplate (เลิกใช้งานแล้ว) |
5 (การแนะนำเทมเพลต) |
MapWithContentTemplate |
7 (แนะนำเทมเพลต) |
ใช้ Callback ของการโต้ตอบ
อินเทอร์เฟซ SurfaceCallback
มีวิธี Callback หลายวิธีที่คุณสามารถใช้เพื่อเพิ่มการโต้ตอบให้กับแผนที่ที่สร้างขึ้น
กับเทมเพลตในส่วนก่อนหน้านี้
การโต้ตอบ | SurfaceCallback วิธี |
รองรับตั้งแต่ระดับ API ของแอปรถยนต์ |
---|---|---|
แตะ | onClick |
5 |
บีบและกางนิ้วเพื่อซูม | onScale |
2 |
ลากด้วยการแตะเพียงครั้งเดียว | onScroll |
2 |
การสะบัดด้วยการแตะเพียงครั้งเดียว | onFling |
2 |
แตะสองครั้ง | onScale (ด้วยค่าตัวคูณมาตราส่วนที่กำหนดโดยโฮสต์เทมเพลต) |
2 |
การกระตุ้นเตือนแบบหมุนในโหมดเลื่อน | onScroll (โดยมีปัจจัยระยะทางที่กำหนดโดยโฮสต์ของเทมเพลต) |
2 |
เพิ่มแถบการดำเนินการบนแผนที่
เทมเพลตเหล่านี้มีแถบการทำงานของแผนที่สำหรับการดำเนินการที่เกี่ยวข้องกับแผนที่ได้ เช่น การย่อและขยาย ตั้งจุดศูนย์กลาง แสดงเข็มทิศ และการทำงานอื่นๆ ที่คุณ เลือกที่จะแสดง แถบการทำงานบนแผนที่มีปุ่มเฉพาะไอคอนได้สูงสุด 4 ปุ่ม ซึ่งสามารถรีเฟรชได้โดยไม่ส่งผลกระทบต่อจำนวนงาน ระบบจะซ่อนระหว่างสภาวะไม่มีการใช้งาน และปรากฏขึ้นอีกครั้งในสถานะทำงานอยู่
หากต้องการรับการเรียกกลับของการโต้ตอบบนแผนที่ ให้ทำดังนี้
ต้องเพิ่มปุ่ม Action.PAN
ในแถบการทำงานของแผนที่ เมื่อผู้ใช้
ให้กดปุ่มเลื่อน โฮสต์จะเข้าสู่โหมดเลื่อนตามที่อธิบายไว้ใน
หากแอปละเว้น Action.PAN
ในแถบการดำเนินการบนแผนที่ ไม่ได้รับข้อมูลจากผู้ใช้
SurfaceCallback
วิธี และโฮสต์จะออกจากเมธอดที่เปิดใช้งานก่อนหน้านี้
โหมดเลื่อน
บนหน้าจอสัมผัส ปุ่มเลื่อนจะไม่แสดง
ทำความเข้าใจโหมดเลื่อน
ในโหมดเลื่อน โฮสต์เทมเพลตจะแปลข้อมูลที่ผู้ใช้ป้อนจากการป้อนข้อมูลที่ไม่ใช่แบบสัมผัส
เช่น ตัวควบคุมแบบหมุน และทัชแพด
SurfaceCallback
วิธี ตอบสนองต่อการดำเนินการของผู้ใช้เพื่อเข้าหรือออกจากโหมดเลื่อน
พร้อมด้วย
setPanModeListener
ใน NavigationTemplate.Builder
โฮสต์สามารถซ่อน UI อื่นได้
ในเทมเพลตขณะที่ผู้ใช้อยู่ในโหมดเลื่อน
โต้ตอบกับผู้ใช้
แอปของคุณสามารถโต้ตอบกับผู้ใช้โดยใช้รูปแบบที่คล้ายกับแอปบนอุปกรณ์เคลื่อนที่
จัดการข้อมูลจากผู้ใช้
แอปของคุณสามารถตอบสนองต่อข้อมูลจากผู้ใช้ได้โดยส่ง Listener ที่เหมาะสมไปยัง
รุ่นที่รองรับ ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีสร้าง
โมเดล Action
ที่ตั้งค่า
OnClickListener
ที่
ย้อนกลับไปยังเมธอดที่กำหนดโดยโค้ดของแอป ซึ่งได้แก่
Kotlin
val action = Action.Builder() .setTitle("Navigate") .setOnClickListener(::onClickNavigate) .build()
Java
Action action = new Action.Builder() .setTitle("Navigate") .setOnClickListener(this::onClickNavigate) .build();
จากนั้นเมธอด onClickNavigate
สามารถเริ่มต้น
แอปนำทางเริ่มต้นสำหรับรถยนต์
โดยใช้เมธอด
CarContext.startCarApp
วิธีการ:
Kotlin
private fun onClickNavigate() { val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)) carContext.startCarApp(intent) }
Java
private void onClickNavigate() { Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)); getCarContext().startCarApp(intent); }
สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีเริ่มต้นใช้งานแอป รวมถึงรูปแบบของ
ACTION_NAVIGATE
โปรดดูเริ่มต้นแอปสำหรับรถยนต์ด้วย Intent
การดำเนินการบางอย่าง เช่น การดำเนินการที่กำหนดให้ผู้ใช้ต้องดำเนินการต่อ
การโต้ตอบบนอุปกรณ์เคลื่อนที่ สามารถทำได้เมื่อจอดรถเท่านั้น
คุณสามารถใช้
ParkedOnlyOnClickListener
เพื่อนำการดำเนินการเหล่านั้นไปใช้ หากรถไม่ได้จอดอยู่ ผู้จัดจะแสดง
เพื่อบอกให้ผู้ใช้ทราบว่าจะไม่ได้รับอนุญาตในกรณีนี้ หากรถยนต์
พักไว้ โค้ดจะทำงานตามปกติ ข้อมูลโค้ดต่อไปนี้จะแสดงวิธีการ
ใช้ ParkedOnlyOnClickListener
เพื่อเปิดหน้าจอการตั้งค่าในอุปกรณ์เคลื่อนที่
Kotlin
val row = Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone)) .build()
Java
Row row = new Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone)) .build();
แสดงการแจ้งเตือน
การแจ้งเตือนที่ส่งไปยังอุปกรณ์เคลื่อนที่จะแสดงในหน้าจอของรถเฉพาะในกรณีต่อไปนี้
ส่วนขยายเหล่านั้นจะได้รับการขยายด้วย
CarAppExtender
แอตทริบิวต์การแจ้งเตือนบางอย่าง เช่น ชื่อเนื้อหา ข้อความ ไอคอน และการดำเนินการ
สามารถตั้งค่าใน CarAppExtender
โดยลบล้างแอตทริบิวต์ของการแจ้งเตือน
เมื่อปรากฏบนหน้าจอของรถ
ข้อมูลโค้ดต่อไปนี้แสดงวิธีส่งการแจ้งเตือนไปยังหน้าจอของรถยนต์ แสดงชื่อต่างจากที่แสดงในโทรศัพท์มือถือ:
Kotlin
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build()
Java
Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( new CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build();
การแจ้งเตือนอาจส่งผลต่อส่วนต่างๆ ต่อไปนี้ของอินเทอร์เฟซผู้ใช้
- การแจ้งเตือนล่วงหน้า (HUN) อาจแสดงต่อผู้ใช้
- คุณสามารถเพิ่มข้อความลงในศูนย์การแจ้งเตือนได้ (ไม่บังคับ) พร้อมป้าย มองเห็นได้บนรถไฟ
- สำหรับแอปนำทาง การแจ้งเตือนอาจแสดงในวิดเจ็ตรถไฟเป็น อธิบายไว้ใน การแจ้งเตือนแบบเลี้ยวต่อเลี้ยว
คุณเลือกวิธีกำหนดค่าการแจ้งเตือนของแอปเพื่อให้ส่งผลต่อแต่ละรายการได้
องค์ประกอบอินเทอร์เฟซผู้ใช้ดังกล่าวโดยใช้ลำดับความสำคัญของการแจ้งเตือน ดังที่อธิบายไว้
ในช่วง
CarAppExtender
เอกสารประกอบ
ถ้า
NotificationCompat.Builder.setOnlyAlertOnce
จะถูกเรียกด้วยค่า true
การแจ้งเตือนที่มีลำดับความสำคัญสูงจะแสดงเป็น
HUN เพียงครั้งเดียว
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีออกแบบการแจ้งเตือนของแอปสำหรับรถยนต์ได้ที่ คู่มือการออกแบบสำหรับขับรถของ Google เกี่ยวกับ การแจ้งเตือน
แสดงข้อความโทสต์
แอปของคุณสามารถแสดงข้อความโทสต์โดยใช้
CarToast
ดังที่แสดงในข้อมูลโค้ดนี้
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
ขอสิทธิ์
หากแอปต้องการเข้าถึงข้อมูลหรือการดำเนินการที่ถูกจำกัด เช่น
ตำแหน่ง—กฎมาตรฐานของ Android
สิทธิ์
นำไปใช้ หากต้องการขอสิทธิ์ คุณสามารถใช้
CarContext.requestPermissions()
ประโยชน์ของการใช้
CarContext.requestPermissions()
ซึ่งต่างจากการใช้
Android API มาตรฐานคือ
ที่คุณไม่จำเป็นต้องเปิด Activity
ของคุณเอง
สร้างกล่องโต้ตอบสิทธิ์ นอกจากนี้ คุณยังสามารถใช้โค้ดเดียวกันทั้ง
Android Auto และ Android Automotive OS แทนที่จะต้องสร้าง
ขั้นตอนที่อิงตามแพลตฟอร์ม
จัดรูปแบบกล่องโต้ตอบสิทธิ์ใน Android Auto
ใน Android Auto กล่องโต้ตอบสิทธิ์สำหรับผู้ใช้จะปรากฏในโทรศัพท์
โดยค่าเริ่มต้น จะไม่มีพื้นหลังอยู่ด้านหลังกล่องโต้ตอบ วิธีตั้งค่าที่กำหนดเอง
ให้ประกาศธีมแอปรถยนต์ใน
AndroidManifest.xml
และตั้งค่าแอตทริบิวต์ carPermissionActivityLayout
สำหรับธีมแอปรถยนต์
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
จากนั้นตั้งค่าแอตทริบิวต์ carPermissionActivityLayout
สำหรับธีมแอปรถยนต์ ดังนี้
<resources> <style name="MyCarAppTheme"> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
เริ่มแอปสำหรับรถยนต์ด้วย Intent
คุณสามารถเรียกใช้
CarContext.startCarApp
ในการดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
- เปิดแป้นโทรศัพท์เพื่อโทรออก
- เริ่มการนำทางแบบเลี้ยวต่อเลี้ยวไปยังสถานที่ด้วย แอปนำทางเริ่มต้นสำหรับรถยนต์
- เริ่มแอปของคุณเองด้วยความตั้งใจ
ตัวอย่างต่อไปนี้จะแสดงวิธีสร้างการแจ้งเตือนด้วยการดำเนินการที่
เปิดแอปของคุณพร้อมหน้าจอที่แสดงรายละเอียดการจองที่จอดรถ
คุณขยายอินสแตนซ์การแจ้งเตือนด้วย Intent เนื้อหาที่มี
PendingIntent
การรวมข้อความที่ไม่เหมาะสม
ความตั้งใจในการทำงานของแอป
Kotlin
val notification = notificationBuilder ... .extend( CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(ComponentName(context, MyNotificationReceiver::class.java)), 0)) .build())
Java
Notification notification = notificationBuilder ... .extend( new CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), new Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(new ComponentName(context, MyNotificationReceiver.class)), 0)) .build());
แอปของคุณต้องประกาศ
BroadcastReceiver
ที่
ถูกเรียกใช้ให้ประมวลผล Intent เมื่อผู้ใช้เลือกการดำเนินการใน
อินเทอร์เฟซและการเรียกใช้การแจ้งเตือน
CarContext.startCarApp
โดย Intent จะรวม URI ข้อมูล ดังนี้
Kotlin
class MyNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val intentAction = intent.action if (ACTION_VIEW_PARKING_RESERVATION == intentAction) { CarContext.startCarApp( intent, Intent(Intent.ACTION_VIEW) .setComponent(ComponentName(context, MyCarAppService::class.java)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))) } } }
Java
public class MyNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) { CarContext.startCarApp( intent, new Intent(Intent.ACTION_VIEW) .setComponent(new ComponentName(context, MyCarAppService.class)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))); } } }
สุดท้าย
Session.onNewIntent
ในแอปของคุณจะจัดการกับ Intent นี้ได้โดยการพุชหน้าจอการจองที่จอดรถ
ในกองซ้อนหากยังไม่ได้อยู่ที่ด้านบน
Kotlin
override fun onNewIntent(intent: Intent) { val screenManager = carContext.getCarService(ScreenManager::class.java) val uri = intent.data if (uri != null && MY_URI_SCHEME == uri.scheme && MY_URI_HOST == uri.schemeSpecificPart && ACTION_VIEW_PARKING_RESERVATION == uri.fragment ) { val top = screenManager.top if (top !is ParkingReservationScreen) { screenManager.push(ParkingReservationScreen(carContext)) } } }
Java
@Override public void onNewIntent(@NonNull Intent intent) { ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class); Uri uri = intent.getData(); if (uri != null && MY_URI_SCHEME.equals(uri.getScheme()) && MY_URI_HOST.equals(uri.getSchemeSpecificPart()) && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment()) ) { Screen top = screenManager.getTop(); if (!(top instanceof ParkingReservationScreen)) { screenManager.push(new ParkingReservationScreen(getCarContext())); } } }
ดูข้อมูลเพิ่มเติมในส่วนแสดงการแจ้งเตือน เกี่ยวกับวิธีจัดการการแจ้งเตือนสำหรับแอปสำหรับรถยนต์
ข้อจำกัดของเทมเพลต
โฮสต์จำกัดจำนวนเทมเพลตที่จะแสดงสำหรับงานที่กำหนดไม่เกินจำนวนสูงสุด จาก 5 รายการ โดยเทมเพลตสุดท้ายต้องเป็นประเภทใดประเภทหนึ่งต่อไปนี้
โปรดทราบว่าจำนวนสูงสุดนี้จะมีผลกับจำนวนเทมเพลต ไม่ใช่จำนวนของเทมเพลต
Screen
อินสแตนซ์ในสแต็ก สำหรับ
เช่น หากแอปส่งเทมเพลต 2 รายการขณะอยู่ในหน้าจอ A จากนั้นพุชหน้าจอ
ข จะสามารถส่งเทมเพลตได้อีก 3 รายการ หรือถ้าหน้าจอแต่ละหน้ามีโครงสร้าง
ส่งเทมเพลตเดียว แอปจะสามารถพุชอินสแตนซ์หน้าจอ 5 รายการไปยัง
กอง ScreenManager
ข้อจำกัดเหล่านี้มีกรณีพิเศษ ได้แก่ การรีเฟรชเทมเพลต การย้อนกลับ และ การรีเซ็ต
การรีเฟรชเทมเพลต
การอัปเดตเนื้อหาบางอย่างจะไม่นับรวมในขีดจำกัดของเทมเพลต โดยทั่วไปแล้ว
หากแอปพุชเทมเพลตใหม่ที่เป็นประเภทเดียวกันและมี
เนื้อหาหลักเดียวกับเทมเพลตก่อนหน้า เทมเพลตใหม่จะ
นับรวมในโควต้า ตัวอย่างเช่น การอัปเดตสถานะการสลับแถวใน
ไม่นับ ListTemplate
เทียบกับโควต้า ดูข้อมูลเพิ่มเติมในเอกสารประกอบของเทมเพลตแต่ละรายการ
เกี่ยวกับประเภทการอัปเดตเนื้อหาที่ถือว่าเป็นการรีเฟรช
การทำงานส่วนหลัง
หากต้องการเปิดใช้ขั้นตอนย่อยภายในงาน โฮสต์จะตรวจพบเมื่อแอปแสดงขั้นตอน
Screen
จากกลุ่ม ScreenManager
และการอัปเดต
โควต้าที่เหลือขึ้นอยู่กับจำนวนเทมเพลตที่แอปใช้
ย้อนกลับ
เช่น หากแอปส่งเทมเพลต 2 รายการขณะอยู่ในหน้าจอ A ก็จะพุช หน้าจอ B และส่งเทมเพลตอีก 2 รายการ แอปมีโควต้าเหลือเพียง 1 รายการ ถ้า แล้วแอปก็จะแสดงกลับไปที่หน้าจอ A โฮสต์จะรีเซ็ตโควต้าเป็น 3 เนื่องจาก แอปได้ย้อนกลับไป 2 เทมเพลต
โปรดทราบว่าเมื่อกลับมาที่หน้าจอ แอปต้องส่งเทมเพลตที่ ของประเภทเดียวกับที่ส่งครั้งสุดท้ายมาจากหน้าจอนั้น การส่งอื่นๆ ประเภทเทมเพลตทำให้เกิดข้อผิดพลาด อย่างไรก็ตาม ตราบใดที่ประเภทดังกล่าวยังคง ขณะดำเนินการย้อนกลับ แอปสามารถแก้ไขเนื้อหาของ เทมเพลตโดยไม่กระทบโควต้า
รีเซ็ตการดำเนินการ
บางเทมเพลตจะมีความหมายพิเศษซึ่งแสดงถึงจุดสิ้นสุดของงาน สำหรับ
ตัวอย่างเช่น
NavigationTemplate
เป็นมุมมองที่คาดว่าจะอยู่บนหน้าจอและได้รับการรีเฟรชด้วย
คำแนะนำแบบเลี้ยวต่อเลี้ยวเพื่อดูการใช้งานของผู้ใช้ เมื่อมาถึงจุดใดจุดหนึ่งเหล่านี้
โฮสต์ โฮสต์จะรีเซ็ตโควต้าเทมเพลต โดยจะถือว่าเทมเพลตนั้น
ให้เป็นขั้นตอนแรกของงานใหม่ การดำเนินการนี้จะช่วยให้แอปเริ่มงานใหม่ได้
ดูเอกสารประกอบของเทมเพลตแต่ละรายการเพื่อดูว่าเทมเพลตใดเรียกใช้การรีเซ็ต
ในโฮสต์
หากโฮสต์ได้รับ Intent ในการเริ่มแอปจากการดำเนินการแจ้งเตือน หรือ จาก Launcher ระบบจะรีเซ็ตโควต้าด้วย กลไกนี้ช่วยให้แอป เริ่มขั้นตอนงานใหม่จากการแจ้งเตือน ซึ่งจะเป็น "จริง" แม้ว่าแอป อยู่แล้วและอยู่เบื้องหน้า
ดูรายละเอียดเพิ่มเติมในส่วนแสดงการแจ้งเตือน เกี่ยวกับวิธีแสดงการแจ้งเตือนของแอปในหน้าจอของรถยนต์ โปรดดู เริ่มต้นแอปรถยนต์ด้วย Intent เพื่อดูข้อมูลเกี่ยวกับวิธี เพื่อเริ่มแอปจากการดำเนินการแจ้งเตือน
API การเชื่อมต่อ
คุณระบุได้ว่าแอปกําลังทํางานใน Android Auto หรือ Android
Automotive OS โดยใช้
CarConnection
API ไปยัง
เรียกดูข้อมูลการเชื่อมต่อขณะรันไทม์
ตัวอย่างเช่น ใน Session
ของแอปรถยนต์ ให้เริ่มต้น CarConnection
และ
สมัครรับข้อมูลอัปเดตของ LiveData
:
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
ในผู้สังเกตการณ์ คุณสามารถตอบสนองต่อการเปลี่ยนแปลงสถานะการเชื่อมต่อได้ ดังนี้
Kotlin
fun onConnectionStateUpdated(connectionState: Int) { val message = when(connectionState) { CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit" CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS" CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto" else -> "Unknown car connection type" } CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show() }
Java
private void onConnectionStateUpdated(int connectionState) { String message; switch(connectionState) { case CarConnection.CONNECTION_TYPE_NOT_CONNECTED: message = "Not connected to a head unit"; break; case CarConnection.CONNECTION_TYPE_NATIVE: message = "Connected to Android Automotive OS"; break; case CarConnection.CONNECTION_TYPE_PROJECTION: message = "Connected to Android Auto"; break; default: message = "Unknown car connection type"; break; } CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show(); }
ข้อจำกัด API
รถแต่ละคันอาจอนุญาตให้
Item
อินสแตนซ์ที่จะแสดง
ผู้ใช้ได้ทีละคน ใช้เมนู
ConstraintManager
เพื่อตรวจสอบขีดจำกัดเนื้อหาขณะรันไทม์ และกำหนดจำนวนรายการที่เหมาะสม
ในเทมเพลต
เริ่มต้นด้วยการรับ ConstraintManager
จาก CarContext
:
Kotlin
val manager = carContext.getCarService(ConstraintManager::class.java)
Java
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);
จากนั้นค้นหาออบเจ็กต์ ConstraintManager
ที่เรียกดูสำหรับข้อมูลที่เกี่ยวข้อง
ขีดจำกัดเนื้อหา เช่น หากต้องการทราบจำนวนรายการที่แสดงใน
ตารางกริด, โทร
getContentLimit
กับ
CONTENT_LIMIT_TYPE_GRID
:
Kotlin
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
Java
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
เพิ่มขั้นตอนการลงชื่อเข้าใช้
หากแอปนำเสนอประสบการณ์การลงชื่อเข้าใช้แก่ผู้ใช้ คุณสามารถใช้เทมเพลตอย่างเช่น
SignInTemplate
และ LongMessageTemplate
ด้วย Car App API ระดับ 2 ขึ้นไปเพื่อจัดการการลงชื่อเข้าใช้แอปของคุณใน
เครื่องเล่นวิทยุของรถ
หากต้องการสร้าง SignInTemplate
ให้กำหนด SignInMethod
รถยนต์
ปัจจุบันคลังแอปรองรับวิธีการลงชื่อเข้าใช้ต่อไปนี้
InputSignInMethod
ในการลงชื่อเข้าใช้ด้วยชื่อผู้ใช้/รหัสผ่านPinSignInMethod
สำหรับการลงชื่อเข้าใช้ด้วย PIN ซึ่งผู้ใช้ลิงก์บัญชีของตนจากโทรศัพท์ โดยใช้ PIN ที่แสดงบนเครื่องเล่นวิทยุProviderSignInMethod
สำหรับการลงชื่อเข้าใช้ของผู้ให้บริการ เช่น Google Sign-In และ One TapQRCodeSignInMethod
สำหรับการลงชื่อเข้าใช้ด้วยคิวอาร์โค้ด ซึ่งผู้ใช้จะสแกนคิวอาร์โค้ดเพื่อลงชื่อเข้าใช้ โทรศัพท์ของตน ซึ่งใช้ได้กับ Car API ระดับ 4 ขึ้นไป
เช่น หากต้องการใช้เทมเพลตที่รวบรวมรหัสผ่านของผู้ใช้ ให้เริ่มจาก
กำลังสร้าง InputCallback
เพื่อประมวลผลและตรวจสอบข้อมูลจากผู้ใช้
Kotlin
val callback = object : InputCallback { override fun onInputSubmitted(text: String) { // You will receive this callback when the user presses Enter on the keyboard. } override fun onInputTextChanged(text: String) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } }
Java
InputCallback callback = new InputCallback() { @Override public void onInputSubmitted(@NonNull String text) { // You will receive this callback when the user presses Enter on the keyboard. } @Override public void onInputTextChanged(@NonNull String text) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } };
Builder
ของ InputSignInMethod
ต้องมี InputCallback
Kotlin
val passwordInput = InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build()
Java
InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build();
ขั้นตอนสุดท้าย ให้ใช้ InputSignInMethod
ใหม่เพื่อสร้าง SignInTemplate
Kotlin
SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build()
Java
new SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build();
ใช้ Account Manager
แอป Android Automotive OS ที่มีการตรวจสอบสิทธิ์ต้องใช้ AccountManager เนื่องจากเหตุผลต่อไปนี้
- UX ที่ดีขึ้นและการจัดการบัญชีที่ง่ายยิ่งขึ้น: ผู้ใช้สามารถจัดการทั้งหมดได้อย่างง่ายดาย บัญชีของตนจากเมนูบัญชีในการตั้งค่าระบบ รวมถึงการลงชื่อเข้าใช้ และออกจากระบบ
- "ผู้มาเยือน" : เนื่องจากรถยนต์เป็นอุปกรณ์ที่แชร์กัน OEM จึงสามารถเปิดใช้ ประสบการณ์ของแขกในยานพาหนะที่ไม่สามารถเพิ่มบัญชีได้
เพิ่มตัวแปรสตริงข้อความ
หน้าจอของรถยนต์ขนาดต่างๆ อาจแสดงจำนวนข้อความแตกต่างกัน พร้อม API ของแอปรถยนต์
ระดับ 2 ขึ้นไป คุณสามารถระบุรูปแบบที่หลากหลายของสตริงข้อความให้ดีที่สุด
ให้พอดีกับหน้าจอ หากต้องการดูว่ามีการใช้ข้อความรูปแบบต่างๆ ที่ใดบ้าง ให้มองหาเทมเพลตและ
คอมโพเนนต์ที่ใช้ CarText
คุณสามารถเพิ่มรูปแบบสตริงข้อความลงใน CarText
ได้ด้วยเมธอด
CarText.Builder.addVariant()
วิธีการ:
Kotlin
val itemTitle = CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build()
Java
CarText itemTitle = new CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build();
จากนั้นคุณสามารถใช้ CarText
นี้ เช่น เป็นข้อความหลักของ
GridItem
Kotlin
GridItem.Builder() .addTitle(itemTitle) ... .build()
Java
new GridItem.Builder() .addTitle(itemTitle) ... build();
เพิ่มสตริงตามลำดับจากมากที่สุดไปน้อยที่สุด เช่น จากยาวสุดไป สั้นที่สุด โฮสต์จะเลือกสตริงความยาวที่เหมาะสม โดยขึ้นอยู่กับ บนหน้าจอของรถยนต์
เพิ่ม CarIcons ในบรรทัดสำหรับแถว
เพิ่มไอคอนในบรรทัดพร้อมข้อความเพื่อเพิ่มความน่าสนใจให้แอปได้โดยใช้
CarIconSpan
ดูเอกสารสำหรับ
CarIconSpan.create
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการสร้างระยะเวลาเหล่านี้ โปรดดู
สเปนต่อเนื่อง
การจัดรูปแบบข้อความด้วย Spans เพื่อดูภาพรวมวิธีการทำงานของการจัดรูปแบบข้อความด้วยระยะเวลา
Kotlin
val rating = SpannableString("Rating: 4.5 stars") rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) val row = Row.Builder() ... .addText(rating) .build()
Java
SpannableString rating = new SpannableString("Rating: 4.5 stars"); rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars new CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ); Row row = new Row.Builder() ... .addText(rating) .build();
API ฮาร์ดแวร์รถยนต์
ตั้งแต่ API แอปรถระดับที่ 3 ไลบรารีแอปรถยนต์มี API ที่คุณ สามารถใช้เพื่อเข้าถึงคุณสมบัติและเซ็นเซอร์ของยานพาหนะ
ข้อกำหนด
หากต้องการใช้ API กับ Android Auto ให้เริ่มด้วยการเพิ่มทรัพยากร Dependency
androidx.car.app:app-projected
ไปยังไฟล์ build.gradle
สำหรับ Android ของคุณ
โมดูลอัตโนมัติ สำหรับ Android Automotive OS ให้เพิ่มทรัพยากร Dependency
androidx.car.app:app-automotive
ไปยังไฟล์ build.gradle
สำหรับ Android ของคุณ
โมดูล Automotive OS
นอกจากนี้ ในไฟล์ AndroidManifest.xml
คุณจะต้อง
ประกาศสิทธิ์ที่เกี่ยวข้องที่จำเป็นต่อการ
ขอข้อมูลรถที่คุณต้องการใช้ โปรดทราบว่าสิทธิ์เหล่านี้ต้อง
ให้สิทธิ์แก่คุณ คุณสามารถใช้
รหัสเดียวกันทั้งใน Android Auto และ Android Automotive OS
แทนที่จะต้องสร้างขั้นตอน
ที่ขึ้นอยู่กับแพลตฟอร์ม แต่สิทธิ์ที่จำเป็น
แตกต่างกัน
ข้อมูลรถยนต์
ตารางนี้อธิบายพร็อพเพอร์ตี้ที่แสดงโดย
CarInfo
API และ
สิทธิ์ที่คุณต้องขอเพื่อใช้
วิธีการ | คุณสมบัติ | สิทธิ์ของ Android Auto | สิทธิ์ของ Android Automotive OS | รองรับตั้งแต่ระดับ API ของแอปรถยนต์ |
---|---|---|---|---|
fetchModel |
ยี่ห้อ รุ่น ปี | android.car.permission.CAR_INFO |
3 | |
fetchEnergyProfile |
ประเภทหัวชาร์จ EV, ประเภทเชื้อเพลิง | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
3 |
fetchExteriorDimensions
ข้อมูลนี้มีเฉพาะในยานยนต์ Android Automotive OS บางรุ่นเท่านั้น ที่ใช้ API ระดับ 30 ขึ้นไป |
ขนาดภายนอก | ไม่มี | android.car.permission.CAR_INFO |
7 |
addTollListener
removeTollListener |
สถานะบัตรค่าผ่านทาง ประเภทบัตรค่าผ่านทาง | 3 | ||
addEnergyLevelListener
removeEnergyLevelListener |
ระดับแบตเตอรี่ ระดับเชื้อเพลิง ระดับเชื้อเพลิงต่ำ ระยะทางที่เหลืออยู่ | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_ENERGY ,android.car.permission.CAR_ENERGY_PORTS ,android.car.permission.READ_CAR_DISPLAY_UNITS
|
3 |
addSpeedListener
removeSpeedListener |
ความเร็วดิบ, ความเร็วในการแสดงผล (แสดงในจอแสดงผลคลัสเตอร์ของรถยนต์) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED ,android.car.permission.READ_CAR_DISPLAY_UNITS |
3 |
addMileageListener
removeMileageListener |
ระยะทางเครื่องวัดระยะทาง | com.google.android.gms.permission.CAR_MILEAGE |
ข้อมูลนี้ไม่พร้อมให้บริการใน Android Automotive OS สำหรับแอปที่ติดตั้งจาก Play Store | 3 |
ตัวอย่างเช่น หากต้องการรับช่วงที่เหลือ ให้สร้างอินสแตนซ์
CarInfo
รายการ จากนั้น
สร้างและลงทะเบียน OnCarDataAvailableListener
:
Kotlin
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo val listener = OnCarDataAvailableListener<EnergyLevel> { data -> if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) { val rangeRemaining = data.rangeRemainingMeters.value } else { // Handle error } } carInfo.addEnergyLevelListener(carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener)
Java
CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo(); OnCarDataAvailableListener<EnergyLevel> listener = (data) -> { if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) { float rangeRemaining = data.getRangeRemainingMeters().getValue(); } else { // Handle error } }; carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener);
อย่าคิดเอาเองว่าข้อมูลจากรถจะพร้อมใช้งานตลอดเวลา
หากพบข้อผิดพลาด ให้ตรวจสอบ
สถานะ ของ
ค่าที่คุณขอเพื่อให้เข้าใจได้ดียิ่งขึ้นว่าเหตุใดข้อมูลที่คุณขอจึงอาจ
จะไม่มีการดึงข้อมูล โปรดดู
เอกสารอ้างอิงสำหรับ
คำจำกัดความของชั้นเรียน CarInfo
ฉบับเต็ม
เซ็นเซอร์ตรวจจับรถ
ชั้นเรียน CarSensors
จะช่วยให้คุณเข้าถึงตัวตรวจวัดความเร่ง เครื่องวัดการหมุน เข็มทิศ ของรถ และ
ข้อมูลสถานที่ ความพร้อมใช้งานของค่าเหล่านี้อาจขึ้นอยู่กับ
OEM รูปแบบของข้อมูลจากตัวตรวจวัดความเร่ง เครื่องวัดการหมุน และเข็มทิศ
เช่นเดียวกับที่คุณจะได้รับจาก
SensorManager
API ตัวอย่างเช่น
ในการตรวจสอบทิศทางของรถ ให้ทำดังนี้
Kotlin
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val listener = OnCarDataAvailableListener<Compass> { data -> if (data.orientations.status == CarValue.STATUS_SUCCESS) { val orientation = data.orientations.value } else { // Data not available, handle error } } carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener)
Java
CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors(); OnCarDataAvailableListener<Compass> listener = (data) -> { if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) { List<Float> orientations = data.getOrientations().getValue(); } else { // Data not available, handle error } }; carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener);
หากต้องการเข้าถึงข้อมูลตำแหน่งจากรถ คุณต้องประกาศและขอ
สิทธิ์android.permission.ACCESS_FINE_LOCATION
การทดสอบ
ในการจำลองข้อมูลเซ็นเซอร์เมื่อทดสอบใน Android Auto โปรดดู เซ็นเซอร์และเซ็นเซอร์ การกำหนดค่า คู่มือหน่วยโฆษณาเครื่องเสียงบนเดสก์ท็อป เพื่อจำลองข้อมูลเซ็นเซอร์เมื่อทดสอบบน Android Automotive OS โปรดดูจำลองฮาร์ดแวร์ สถานะของ Android คู่มือโปรแกรมจำลอง Automotive OS
วงจรการใช้งาน CarAppService, เซสชัน และหน้าจอ
Session
และ
คลาส Screen
ใช้
อินเทอร์เฟซ LifecycleOwner
อาส
ผู้ใช้โต้ตอบกับแอป, ออบเจ็กต์ Session
และ Screen
ของคุณ วงจร
ระบบจะเรียกใช้ Callback ตามที่อธิบายไว้ในแผนภาพต่อไปนี้
วงจรชีวิตของ CarAppService และเซสชัน
![](https://developer.android.com/static/images/training/cars/carappservice-session-lifecycle.png?authuser=9&hl=th)
Session
โปรดดูรายละเอียดทั้งหมดในเอกสารประกอบเกี่ยวกับ
Session.getLifecycle
วงจรชีวิตของหน้าจอ
![](https://developer.android.com/static/images/training/cars/screen-lifecycle.png?authuser=9&hl=th)
Screen
โปรดดูรายละเอียดทั้งหมดในเอกสารประกอบเกี่ยวกับ
Screen.getLifecycle
บันทึกจากไมโครโฟนของรถยนต์
หากใช้
CarAppService
และ
CarAudioRecord
API,
คุณสามารถให้สิทธิ์แอปเข้าถึงไมโครโฟนในรถยนต์ของผู้ใช้ ผู้ใช้ต้องให้
สิทธิ์ของแอปในการเข้าถึงไมโครโฟนรถยนต์ แอปของคุณสามารถบันทึกและ
ประมวลผลข้อมูลของผู้ใช้ภายในแอป
สิทธิ์ในการบันทึก
ก่อนที่จะบันทึกเสียงใดๆ คุณต้องประกาศสิทธิ์ในการบันทึก
AndroidManifest.xml
และขอให้ผู้ใช้ให้สิทธิ์
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
...
</manifest>
คุณต้องขอสิทธิ์ในการบันทึกขณะรันไทม์ ดูคำขอ สิทธิ์เพื่อดูรายละเอียดเกี่ยวกับวิธีส่งคำขอ สิทธิ์ในแอปรถยนต์
บันทึกเสียง
หลังจากผู้ใช้ให้สิทธิ์ในการบันทึกแล้ว คุณจะบันทึกเสียงและประมวลผลได้ การบันทึก
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) carAudioRecord.startRecording() val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording()
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); carAudioRecord.startRecording(); byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE]; while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording();
โฟกัสอัตโนมัติ
เมื่อบันทึกจากไมโครโฟนรถยนต์ ให้ซื้อเสียงก่อน โฟกัสเพื่อ ตรวจดูว่าสื่อที่ดำเนินอยู่หยุดลงแล้ว หากโฟกัสเสียงหายไป หยุดบันทึก
ตัวอย่างวิธีรับโฟกัสเสียงมีดังนี้
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) // Take audio focus so that user's media is not recorded val audioAttributes = AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build() val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener { state: Int -> if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording() } } .build() if (carContext.getSystemService(AudioManager::class.java) .requestAudioFocus(audioFocusRequest) != AudioManager.AUDIOFOCUS_REQUEST_GRANTED ) { // Don't record if the focus isn't granted return } carAudioRecord.startRecording() // Process the audio and abandon the AudioFocusRequest when done
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); // Take audio focus so that user's media is not recorded AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build(); AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener(state -> { if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording(); } }) .build(); if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest) != AUDIOFOCUS_REQUEST_GRANTED) { // Don't record if the focus isn't granted return; } carAudioRecord.startRecording(); // Process the audio and abandon the AudioFocusRequest when done
ไลบรารีการทดสอบ
การทดสอบ Android for Cars
ห้องสมุดจะให้ความช่วยเหลือ
คลาสที่คุณสามารถใช้เพื่อตรวจสอบลักษณะการทำงานของแอปในสภาพแวดล้อมการทดสอบ
ตัวอย่างเช่น พารามิเตอร์
SessionController
จะช่วยให้คุณสามารถจำลองการเชื่อมต่อกับโฮสต์และยืนยันว่า
Screen
และ
สร้าง Template
และ
ส่งคืนแล้ว
โปรดดู ลองฟัง เพื่อดูตัวอย่างการใช้งาน
รายงานปัญหาเกี่ยวกับคลังแอป Android สำหรับรถยนต์
หากคุณพบปัญหากับไลบรารี ให้รายงานปัญหาโดยใช้ เครื่องมือติดตามปัญหาของ Google ตรวจสอบว่าได้กรอกข้อมูลที่ขอทั้งหมดในเทมเพลตของปัญหา
ก่อนยื่นฉบับใหม่ โปรดตรวจสอบว่าฉบับแสดงไว้ในรุ่นของไลบรารีแล้วหรือไม่ หมายเหตุหรือที่รายงานในรายการปัญหา คุณสามารถสมัครรับข้อมูลและโหวตปัญหาได้โดย คลิกดาวที่ปัญหาในเครื่องมือติดตาม สำหรับข้อมูลเพิ่มเติม โปรดดู การสมัครรับปัญหา