Android Auto และ Android Automotive OS ช่วยให้คุณนำเนื้อหาแอปสื่อไปให้ผู้ใช้ในรถยนต์ได้
การสร้างแอปสื่อสำหรับรถยนต์ทำได้ 2 วิธี
คู่มือนี้จะอธิบายวิธีใช้
MediaBrowserService
และMediaSession
เพื่อสร้างแอปที่ Android Auto และ Android Automotive OS สามารถเชื่อมต่อได้ เพื่อแสดงผลมุมมองการเรียกดูและการเล่นสื่อที่ได้รับการเพิ่มประสิทธิภาพสำหรับการใช้งานในรถยนต์นอกจากนี้ คุณยังสร้างแอปสื่อโดยใช้เทมเพลตคลังแอปในรถยนต์เพื่อ การจัดรูปแบบที่ปรับแต่งได้ ความสามารถในการเรียกดู และการดำเนินการที่กำหนดเองเพิ่มเติมได้ด้วย ดูรายละเอียดการติดตั้งได้ที่ สร้างแอปสื่อที่ใช้เทมเพลต ปัจจุบันแอปสื่อที่ใช้เทมเพลต รองรับเฉพาะใน Android Auto
คู่มือนี้อธิบายคอมโพเนนต์ที่จำเป็นของ MediaBrowserService
และ
MediaSession
ที่แอปของคุณต้องใช้เพื่อให้ทำงานบน Android Auto หรือ Android
Automotive OS ได้ หลังจากสร้างโครงสร้างพื้นฐานของสื่อหลักเสร็จแล้ว คุณจะเพิ่มการรองรับ Android Auto และเพิ่มการรองรับ
Android Automotive OS ลงในแอปสื่อได้
คู่มือนี้ถือว่าคุณมีแอปสื่อที่เล่นเสียงในโทรศัพท์อยู่แล้ว และแอปสื่อของคุณเป็นไปตามสถาปัตยกรรมแอปสื่อของ Android
ก่อนเริ่มต้น
- อ่านเอกสารประกอบเกี่ยวกับ Android Media API
- ดูคำแนะนำด้านการออกแบบได้ที่สร้างแอปสื่อ
- โปรดอ่านข้อกำหนดและแนวคิดที่สำคัญซึ่งระบุไว้ในส่วนนี้
คำและแนวคิดสำคัญ
- บริการเบราว์เซอร์สื่อ
- บริการ Android ที่แอปสื่อของคุณใช้ซึ่งเป็นไปตาม
MediaBrowserServiceCompat
API แอปของคุณใช้บริการนี้เพื่อแสดงเนื้อหา - เบราว์เซอร์สื่อ
- API ที่แอปสื่อใช้เพื่อค้นหาบริการเบราว์เซอร์สื่อและแสดง เนื้อหาของตน Android Auto และ Android Automotive OS ใช้ MediaBrowser เพื่อ ค้นหาบริการ MediaBrowser ของแอป
- รายการสื่อ
เบราว์เซอร์สื่อจะจัดระเบียบเนื้อหาในโครงสร้างแบบต้นไม้ของออบเจ็กต์
MediaItem
รายการสื่ออาจมีแฟล็กต่อไปนี้อย่างใดอย่างหนึ่งหรือทั้ง 2 อย่างFLAG_PLAYABLE
: บ่งบอกว่ารายการดังกล่าวเป็นรายการสุดท้ายในโครงสร้างเนื้อหา รายการแสดงถึงสตรีมเสียงเดียว เช่น เพลงในอัลบั้ม บทในหนังสือเสียง หรือตอนของพอดแคสต์FLAG_BROWSABLE
: แสดงว่ารายการเป็นโหนดในแผนผังเนื้อหาและมีรายการย่อย เช่น รายการแสดงถึงอัลบั้ม และรายการย่อยคือเพลงในอัลบั้ม
รายการสื่อที่ทั้งเรียกดูและเล่นได้จะทำงานเหมือนเพลย์ลิสต์ คุณสามารถ เลือกรายการนั้นเพื่อเล่นรายการย่อยทั้งหมด หรือจะเรียกดูรายการย่อยของรายการนั้นก็ได้
- เพิ่มประสิทธิภาพสำหรับยานพาหนะ
กิจกรรมสำหรับแอป Android Automotive OS ที่เป็นไปตาม หลักเกณฑ์การออกแบบ Android Automotive OS Android Automotive OS ไม่ได้วาดอินเทอร์เฟซสำหรับกิจกรรมเหล่านี้ ดังนั้นคุณ ต้องตรวจสอบว่าแอปของคุณเป็นไปตามหลักเกณฑ์การออกแบบ โดยปกติแล้ว การปรับปรุงนี้จะ รวมถึงเป้าหมายการแตะและขนาดแบบอักษรที่ใหญ่ขึ้น การรองรับโหมดกลางวันและกลางคืน และ อัตราส่วนคอนทราสต์ที่สูงขึ้น
ระบบจะอนุญาตให้แสดงอินเทอร์เฟซผู้ใช้ที่ปรับให้เหมาะกับยานพาหนะได้เฉพาะเมื่อข้อจำกัดด้านประสบการณ์การใช้งานรถยนต์ (CUXR) ไม่มีผลบังคับใช้ เนื่องจากอินเทอร์เฟซเหล่านี้อาจต้องใช้ความสนใจหรือการโต้ตอบจากผู้ใช้เป็นเวลานาน CUXR จะไม่มีผลเมื่อรถหยุดหรือจอด แต่จะมีผลเสมอเมื่อรถเคลื่อนที่
คุณไม่จำเป็นต้องออกแบบกิจกรรมสำหรับ Android Auto เนื่องจาก Android Auto จะวาดอินเทอร์เฟซที่ปรับให้เหมาะกับยานพาหนะของตัวเองโดยใช้ข้อมูลจาก บริการเบราว์เซอร์สื่อ
กำหนดค่าไฟล์ Manifest ของแอป
คุณต้องกำหนดค่าไฟล์ Manifest ของแอปก่อนจึงจะสร้างบริการเบราว์เซอร์สื่อได้
ประกาศบริการเบราว์เซอร์สื่อ
ทั้ง Android Auto และ Android Automotive OS จะเชื่อมต่อกับแอปของคุณผ่าน บริการเบราว์เซอร์สื่อเพื่อเรียกดูรายการสื่อ ประกาศบริการ Media Browser ในไฟล์ Manifest เพื่อให้ Android Auto และ Android Automotive OS ค้นพบบริการและเชื่อมต่อกับแอปของคุณ
ข้อมูลโค้ดต่อไปนี้แสดงวิธีประกาศบริการเบราว์เซอร์สื่อใน ไฟล์ Manifest ใส่โค้ดนี้ในไฟล์ Manifest สำหรับโมดูล Android Automotive OS และในไฟล์ Manifest สำหรับแอปโทรศัพท์
<application>
...
<service android:name=".MyMediaBrowserService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
...
</application>
ระบุไอคอนแอป
คุณต้องระบุไอคอนแอปที่ Android Auto และ Android Automotive OS ใช้เพื่อแสดงแอปใน UI ของระบบได้ คุณต้องระบุไอคอน 2 ประเภท ได้แก่
- ไอคอน Launcher
- ไอคอนการระบุแหล่งที่มา
ไอคอน Launcher
ไอคอน Launcher แสดงแอปของคุณใน UI ของระบบ เช่น ใน Launcher และในถาดไอคอน คุณระบุได้ว่าต้องการใช้ไอคอนจาก แอปบนอุปกรณ์เคลื่อนที่เพื่อแสดงแอปสื่อในรถยนต์โดยใช้การประกาศในไฟล์ Manifest ต่อไปนี้
<application
...
android:icon="@mipmap/ic_launcher"
...
/>
หากต้องการใช้ไอคอนอื่นที่ไม่ใช่ของแอปบนอุปกรณ์เคลื่อนที่ ให้ตั้งค่าพร็อพเพอร์ตี้ android:icon
ในองค์ประกอบ <service>
ของบริการเบราว์เซอร์สื่อในไฟล์ Manifest ดังนี้
<application>
...
<service
...
android:icon="@mipmap/auto_launcher"
...
/>
</application>
ไอคอนการระบุแหล่งที่มา

รูปที่ 1 ไอคอนการระบุแหล่งที่มาในการ์ดสื่อ
ระบบจะใช้ไอคอนการระบุแหล่งที่มาในที่ที่เนื้อหาสื่อมีความสำคัญมากกว่า เช่น ในการ์ดสื่อ ลองใช้ไอคอนขนาดเล็กที่ใช้สำหรับการแจ้งเตือนซ้ำ ไอคอนนี้ต้องเป็นสีเดียว คุณระบุไอคอนที่ใช้เพื่อแสดง แอปได้โดยใช้การประกาศในไฟล์ Manifest ต่อไปนี้
<application>
...
<meta-data
android:name="androidx.car.app.TintableAttributionIcon"
android:resource="@drawable/ic_status_icon" />
...
</application>
สร้างบริการเบราว์เซอร์สื่อ
คุณสร้างบริการเบราว์เซอร์สื่อได้โดยการขยายคลาส MediaBrowserServiceCompat
จากนั้นทั้ง Android Auto และ Android Automotive OS จะใช้บริการของคุณเพื่อทำสิ่งต่อไปนี้ได้
- เรียกดูลำดับชั้นของเนื้อหาแอปเพื่อแสดงเมนูต่อผู้ใช้
- รับโทเค็นสำหรับออบเจ็กต์
MediaSessionCompat
ของแอปเพื่อควบคุมการเล่นเสียง
นอกจากนี้ คุณยังใช้บริการ MediaBrowser เพื่อให้ไคลเอ็นต์อื่นๆ เข้าถึงเนื้อหาสื่อจากแอปได้ด้วย ไคลเอ็นต์สื่อเหล่านี้อาจเป็นแอปอื่นๆ ในโทรศัพท์ของผู้ใช้ หรืออาจเป็นไคลเอ็นต์ระยะไกลอื่นๆ
เวิร์กโฟลว์บริการเบราว์เซอร์สื่อ
ส่วนนี้อธิบายวิธีที่ Android Automotive OS และ Android Auto โต้ตอบกับบริการเบราว์เซอร์สื่อในเวิร์กโฟลว์ของผู้ใช้ทั่วไป
- ผู้ใช้เปิดแอปของคุณใน Android Automotive OS หรือ Android Auto
- Android Automotive OS หรือ Android Auto จะติดต่อบริการเบราว์เซอร์สื่อของแอปโดยใช้เมธอด
onCreate()
ในการติดตั้งใช้งานเมธอดonCreate()
คุณต้องสร้างและลงทะเบียนออบเจ็กต์MediaSessionCompat
และออบเจ็กต์การเรียกกลับ - Android Automotive OS หรือ Android Auto จะเรียกใช้เมธอด
onGetRoot()
ของบริการเพื่อรับรายการสื่อรูทในลำดับชั้นของเนื้อหา ระบบจะไม่แสดงรายการสื่อรูท แต่จะใช้เพื่อดึงเนื้อหาเพิ่มเติมจากแอปแทน - Android Automotive OS หรือ Android Auto จะเรียกใช้เมธอด
onLoadChildren()
ของบริการเพื่อรับรายการสื่อย่อยของรายการสื่อรูท Android Automotive OS และ Android Auto จะแสดงรายการสื่อเหล่านี้เป็นรายการเนื้อหาระดับบนสุด ดูจัดโครงสร้างเมนูรูทในหน้านี้เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ระบบคาดหวังในระดับนี้ - หากผู้ใช้เลือกรายการสื่อที่เรียกดูได้ ระบบจะเรียกใช้
onLoadChildren()
เมธอดของบริการอีกครั้งเพื่อดึงข้อมูลรายการเมนูย่อยของรายการที่เลือก - หากผู้ใช้เลือกรายการสื่อที่เล่นได้ Android Automotive OS หรือ Android Auto จะเรียกใช้เมธอดการเรียกกลับของเซสชันสื่อที่เหมาะสมเพื่อดำเนินการดังกล่าว
- หากแอปของคุณรองรับ ผู้ใช้จะค้นหาเนื้อหาของคุณได้ด้วย ในกรณีนี้ Android Automotive OS หรือ Android Auto จะเรียกใช้เมธอด
onSearch()
ของบริการ
สร้างลำดับชั้นของเนื้อหา
Android Auto และ Android Automotive OS จะเรียกใช้บริการ MediaBrowser ของแอปเพื่อ
ดูว่ามีเนื้อหาใดบ้าง คุณต้องใช้ 2 วิธีในบริการเบราว์เซอร์สื่อเพื่อรองรับฟีเจอร์นี้ ได้แก่ onGetRoot()
และ
onLoadChildren()
ใช้งาน onGetRoot
เมธอด onGetRoot()
ของบริการจะแสดงข้อมูลเกี่ยวกับโหนดรูทของลำดับชั้นเนื้อหา
Android Auto และ Android Automotive OS ใช้โหนดรูทนี้เพื่อขอเนื้อหาที่เหลือ
โดยใช้วิธี
onLoadChildren()
ข้อมูลโค้ดต่อไปนี้แสดงการใช้งานเมธอด
onGetRoot()
อย่างง่าย
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): BrowserRoot? = // Verify that the specified package is allowed to access your // content. You'll need to write your own logic to do this. if (!isValid(clientPackageName, clientUid)) { // If the request comes from an untrusted package, return null. // No further calls will be made to other media browsing methods. null } else MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)
Java
@Override public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { // Verify that the specified package is allowed to access your // content. You'll need to write your own logic to do this. if (!isValid(clientPackageName, clientUid)) { // If the request comes from an untrusted package, return null. // No further calls will be made to other media browsing methods. return null; } return new MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null); }
ดูตัวอย่างโดยละเอียดเพิ่มเติมของวิธีการนี้ได้ที่เมธอด onGetRoot()
ในแอปตัวอย่าง Universal Android Music Player ใน GitHub
เพิ่มการตรวจสอบแพ็กเกจสำหรับ onGetRoot()
เมื่อมีการโทรไปยังเมธอด onGetRoot()
ของบริการ แพ็กเกจที่เรียกจะส่งข้อมูลระบุตัวตนไปยังบริการของคุณ บริการของคุณสามารถใช้ข้อมูลนี้เพื่อพิจารณาว่าแพ็กเกจดังกล่าวเข้าถึงเนื้อหาของคุณได้หรือไม่ เช่น คุณสามารถจำกัดสิทธิ์เข้าถึงเนื้อหาของแอปให้เฉพาะรายการแพ็กเกจที่ได้รับอนุมัติได้โดยการเปรียบเทียบ clientPackageName
กับรายการที่อนุญาตและยืนยันใบรับรองที่ใช้ลงนามใน APK ของแพ็กเกจ หากยืนยันแพ็กเกจไม่ได้ ให้กลับไปที่ null
เพื่อปฏิเสธการเข้าถึงเนื้อหา
หากต้องการให้แอประบบ เช่น Android Auto และ Android Automotive OS
เข้าถึงเนื้อหาของคุณได้ บริการของคุณต้องแสดงผล BrowserRoot
ที่ไม่ใช่ Null
BrowserRoot
เสมอเมื่อแอประบบเหล่านี้เรียกใช้เมธอด onGetRoot()
ลายเซ็นของแอปของระบบ Android Automotive OS อาจแตกต่างกันไปตามยี่ห้อและรุ่นของรถยนต์ ดังนั้นคุณต้องอนุญาตการเชื่อมต่อจากแอปของระบบทั้งหมดเพื่อรองรับ Android Automotive OS อย่างมีประสิทธิภาพ
ข้อมูลโค้ดต่อไปนี้แสดงวิธีที่บริการของคุณสามารถตรวจสอบได้ว่าแพ็กเกจที่เรียกใช้เป็นแอปของระบบหรือไม่
fun isKnownCaller(
callingPackage: String,
callingUid: Int
): Boolean {
...
val isCallerKnown = when {
// If the system is making the call, allow it.
callingUid == Process.SYSTEM_UID -> true
// If the app was signed by the same certificate as the platform
// itself, also allow it.
callerSignature == platformSignature -> true
// ... more cases
}
return isCallerKnown
}
ข้อมูลโค้ดนี้เป็นข้อความที่คัดลอกมาจากคลาส PackageValidator
ในแอปตัวอย่าง Universal Android Music Player บน GitHub ดูคลาสดังกล่าว
เพื่อดูตัวอย่างโดยละเอียดเพิ่มเติมเกี่ยวกับวิธีใช้การตรวจสอบแพ็กเกจสำหรับonGetRoot()
ของบริการ
นอกเหนือจากการอนุญาตแอปของระบบแล้ว คุณต้องอนุญาตให้ Google Assistant
เชื่อมต่อกับ MediaBrowserService
ด้วย โปรดทราบว่า Google Assistant มีชื่อแพ็กเกจแยกกัน
สำหรับโทรศัพท์ ซึ่งรวมถึง Android Auto และสำหรับ Android Automotive OS
ใช้ onLoadChildren()
หลังจากได้รับออบเจ็กต์โหนดรูทแล้ว Android Auto และ Android Automotive OS
จะสร้างเมนูระดับบนสุดโดยเรียกใช้ onLoadChildren()
ในออบเจ็กต์โหนดรูทเพื่อรับออบเจ็กต์ย่อย แอปไคลเอ็นต์สร้างเมนูย่อยโดย
เรียกใช้เมธอดเดียวกันนี้โดยใช้ออบเจ็กต์โหนดลูก
แต่ละโหนดในลำดับชั้นเนื้อหาจะแสดงด้วยออบเจ็กต์ MediaBrowserCompat.MediaItem
โดยรายการสื่อแต่ละรายการจะมีสตริงรหัสที่ไม่ซ้ำกัน แอปไคลเอ็นต์
จะถือว่าสตริงรหัสเหล่านี้เป็นโทเค็นแบบไม่ชัดเจน เมื่อแอปไคลเอ็นต์ต้องการเรียกดู
เมนูย่อยหรือเล่นรายการสื่อ แอปจะส่งโทเค็น แอปของคุณมีหน้าที่
เชื่อมโยงโทเค็นกับรายการสื่อที่เหมาะสม
ข้อมูลโค้ดต่อไปนี้แสดงการใช้งานonLoadChildren()
เมธอดอย่างง่าย
Kotlin
override fun onLoadChildren( parentMediaId: String, result: Result<List<MediaBrowserCompat.MediaItem>> ) { // Assume for example that the music catalog is already loaded/cached. val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf() // Check whether this is the root menu: if (MY_MEDIA_ROOT_ID == parentMediaId) { // Build the MediaItem objects for the top level // and put them in the mediaItems list. } else { // Examine the passed parentMediaId to see which submenu we're at // and put the children of that menu in the mediaItems list. } result.sendResult(mediaItems) }
Java
@Override public void onLoadChildren(final String parentMediaId, final Result<List<MediaBrowserCompat.MediaItem>> result) { // Assume for example that the music catalog is already loaded/cached. List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>(); // Check whether this is the root menu: if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) { // Build the MediaItem objects for the top level // and put them in the mediaItems list. } else { // Examine the passed parentMediaId to see which submenu we're at // and put the children of that menu in the mediaItems list. } result.sendResult(mediaItems); }
ดูตัวอย่างที่สมบูรณ์ของเมธอดนี้ได้ในเมธอด
onLoadChildren()
ในแอปตัวอย่าง Universal Android Music Player บน GitHub
สร้างโครงสร้างเมนูหลัก

รูปที่ 2 เนื้อหาระดับบนสุดจะแสดงเป็นแท็บการนำทาง
Android Auto และ Android Automotive OS มีข้อจำกัดเฉพาะเกี่ยวกับ
โครงสร้างของเมนูหลัก โดยจะสื่อสารกับ MediaBrowserService
ผ่านคำแนะนำรูท ซึ่งอ่านได้ผ่านอาร์กิวเมนต์ Bundle
ที่ส่งไปยัง
onGetRoot()
การทำตามคำแนะนำเหล่านี้จะช่วยให้ระบบแสดงเนื้อหาระดับบนสุดได้อย่างเหมาะสมที่สุด
ในรูปแบบแท็บการนำทาง หากคุณไม่ปฏิบัติตามคำแนะนำเหล่านี้ ระบบอาจไม่แสดงเนื้อหาหลักบางส่วนหรือทำให้ค้นพบได้ยากขึ้น ระบบจะส่งคำใบ้ 2 รายการ ดังนี้
- ขีดจำกัดจำนวนบัญชีลูกที่ระดับบนสุด: ในกรณีส่วนใหญ่ คุณจะเห็นว่าจำนวนนี้คือ 4 ซึ่งหมายความว่า แสดงแท็บได้ไม่เกิน 4 แท็บ
- แฟล็กที่รองรับในองค์ประกอบย่อยระดับรูท
คุณคาดหวังให้ค่านี้เป็น
MediaItem#FLAG_BROWSABLE
ซึ่งหมายความว่าระบบจะแสดงเฉพาะรายการที่เรียกดูได้เป็นแท็บเท่านั้น ไม่ใช่รายการที่เล่นได้
ใช้โค้ดต่อไปนี้เพื่ออ่านคำแนะนำรูทที่เกี่ยวข้อง
Kotlin
import androidx.media.utils.MediaConstants // Later, in your MediaBrowserServiceCompat. override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle ): BrowserRoot { val maximumRootChildLimit = rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT, /* defaultValue= */ 4) val supportedRootChildFlags = rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS, /* defaultValue= */ MediaItem.FLAG_BROWSABLE) // Rest of method... }
Java
import androidx.media.utils.MediaConstants; // Later, in your MediaBrowserServiceCompat. @Override public BrowserRoot onGetRoot( String clientPackageName, int clientUid, Bundle rootHints) { int maximumRootChildLimit = rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT, /* defaultValue= */ 4); int supportedRootChildFlags = rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS, /* defaultValue= */ MediaItem.FLAG_BROWSABLE); // Rest of method... }
คุณสามารถเลือกแยกตรรกะสำหรับโครงสร้างของลำดับชั้นเนื้อหา
ตามค่าของคำแนะนำเหล่านี้ได้ โดยเฉพาะอย่างยิ่งหากลำดับชั้นแตกต่างกันในMediaBrowser
การผสานรวมภายนอก Android Auto และ Android Automotive OS
เช่น หากปกติคุณแสดงไอเทมที่เล่นได้ระดับรูท คุณอาจต้องการซ้อนไอเทมดังกล่าว
ไว้ใต้ไอเทมที่เรียกดูได้ระดับรูทแทน เนื่องจากค่าของแฟล็กที่รองรับ
คำแนะนำ
นอกเหนือจากคำแนะนำระดับรูทแล้ว ยังมีหลักเกณฑ์เพิ่มเติมอีก 2 ข้อที่ควรปฏิบัติตาม เพื่อให้มั่นใจว่าแท็บจะแสดงผลได้อย่างเหมาะสมที่สุด
- ระบุไอคอนโมโนโครม (สีเดียว) โดยควรเป็นสีขาวสำหรับรายการแท็บแต่ละรายการ
- ระบุป้ายกำกับที่สั้นแต่มีความหมายสำหรับรายการแท็บแต่ละรายการ การใช้ป้ายกำกับแบบสั้น จะช่วยลดโอกาสที่สตริงจะถูกตัดทอน
ภาพปกสื่อที่แสดง
ต้องส่งอาร์ตเวิร์กสำหรับรายการสื่อเป็น URI ในเครื่องโดยใช้
ContentResolver.SCHEME_CONTENT
หรือ ContentResolver.SCHEME_ANDROID_RESOURCE
URI ในเครื่องนี้ต้องแปลงเป็นบิตแมปหรือเวกเตอร์ Drawable ในทรัพยากรของแอปพลิเคชัน สำหรับออบเจ็กต์ MediaDescriptionCompat
ที่แสดงถึงรายการใน
ลำดับชั้นของเนื้อหา ให้ส่ง URI ผ่าน setIconUri()
สำหรับออบเจ็กต์ MediaMetadataCompat
ที่แสดงถึงรายการที่กำลังเล่น ให้ส่ง URI ผ่าน putString()
โดยใช้คีย์ต่อไปนี้
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI
MediaMetadataCompat.METADATA_KEY_ART_URI
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI
ขั้นตอนต่อไปนี้อธิบายวิธีดาวน์โหลดอาร์ตเวิร์กจาก URI ของเว็บและแสดงผ่าน URI ในเครื่อง
ดูตัวอย่างที่สมบูรณ์ยิ่งขึ้นได้ในการติดตั้งใช้งาน
openFile()
และเมธอดโดยรอบในแอปตัวอย่าง Universal Android Music
Player
สร้าง
content://
URI ที่สอดคล้องกับ URI ของเว็บ บริการเบราว์เซอร์สื่อ และเซสชันสื่อจะส่ง URI ของเนื้อหานี้ไปยัง Android Auto และ Android Automotive OSKotlin
fun Uri.asAlbumArtContentURI(): Uri { return Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CONTENT_PROVIDER_AUTHORITY) .appendPath(this.getPath()) // Make sure you trust the URI .build() }
Java
public static Uri asAlbumArtContentURI(Uri webUri) { return new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CONTENT_PROVIDER_AUTHORITY) .appendPath(webUri.getPath()) // Make sure you trust the URI! .build(); }
ในการติดตั้งใช้งาน
ContentProvider.openFile()
ให้ตรวจสอบว่ามีไฟล์ สำหรับ URI ที่เกี่ยวข้องหรือไม่ หากไม่มี ให้ดาวน์โหลดและแคชไฟล์รูปภาพ ข้อมูลโค้ดต่อไปนี้ใช้ GlideKotlin
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? { val context = this.context ?: return null val file = File(context.cacheDir, uri.path) if (!file.exists()) { val remoteUri = Uri.Builder() .scheme("https") .authority("my-image-site") .appendPath(uri.path) .build() val cacheFile = Glide.with(context) .asFile() .load(remoteUri) .submit() .get(DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS) cacheFile.renameTo(file) file = cacheFile } return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY) }
Java
@Nullable @Override public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { Context context = this.getContext(); File file = new File(context.getCacheDir(), uri.getPath()); if (!file.exists()) { Uri remoteUri = new Uri.Builder() .scheme("https") .authority("my-image-site") .appendPath(uri.getPath()) .build(); File cacheFile = Glide.with(context) .asFile() .load(remoteUri) .submit() .get(DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS); cacheFile.renameTo(file); file = cacheFile; } return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); }
ดูรายละเอียดเพิ่มเติมเกี่ยวกับผู้ให้บริการเนื้อหาได้ที่การสร้างผู้ให้บริการเนื้อหา
ใช้รูปแบบเนื้อหา
หลังจากสร้างลำดับชั้นของเนื้อหาโดยใช้รายการที่เรียกดูหรือเล่นได้แล้ว คุณ สามารถใช้รูปแบบเนื้อหาที่กำหนดวิธีแสดงรายการเหล่านั้นในรถยนต์ได้
คุณใช้รูปแบบเนื้อหาต่อไปนี้ได้
- รายการข้อมูล
-
รูปแบบเนื้อหานี้จะให้ความสำคัญกับชื่อและข้อมูลเมตามากกว่ารูปภาพ
- รายการตารางกริด
-
รูปแบบเนื้อหานี้ให้ความสำคัญกับรูปภาพมากกว่าชื่อและข้อมูลเมตา
ตั้งค่ารูปแบบเนื้อหาเริ่มต้น
คุณตั้งค่าเริ่มต้นส่วนกลางสำหรับวิธีแสดงรายการสื่อได้โดยใส่ค่าคงที่บางอย่างในBrowserRoot
กลุ่มพิเศษของเมธอด
onGetRoot()
ของบริการ Android Auto และ Android Automotive OS จะอ่านชุดข้อมูลนี้และค้นหาค่าคงที่เหล่านั้นเพื่อกำหนดสไตล์ที่เหมาะสม
คุณใช้รายการต่อไปนี้เป็นคีย์ในแพ็กเกจได้
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: ระบุคำแนะนำในการนำเสนอสำหรับรายการที่เรียกดูได้ทั้งหมดภายในโครงสร้างการเรียกดูDESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: ระบุคำแนะนำในการนำเสนอสำหรับรายการที่เล่นได้ทั้งหมดภายในโครงสร้างการเรียกดู
คีย์สามารถแมปกับค่าคงที่จำนวนเต็มต่อไปนี้เพื่อส่งผลต่อ การนำเสนอรายการเหล่านั้น
DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
: รายการที่เกี่ยวข้องจะแสดงเป็นรายการDESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
รายการที่เกี่ยวข้องจะแสดงเป็นรายการในตารางกริดDESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM
: รายการที่เกี่ยวข้องจะแสดงเป็นรายการ "หมวดหมู่" ซึ่งเหมือนกับรายการธรรมดา เพียงแต่มีการใช้ระยะขอบรอบๆ ไอคอนของรายการ เนื่องจากไอคอนจะดูดีกว่าเมื่อมีขนาดเล็ก ไอคอน ต้องเป็น Vector Drawable ที่ปรับสีได้ คาดว่าคำใบ้นี้จะแสดงเฉพาะ สำหรับรายการที่เรียกดูได้เท่านั้นDESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
: รายการที่เกี่ยวข้องจะแสดงเป็นรายการตารางกริด "หมวดหมู่" ซึ่งเหมือนกับรายการกริดทั่วไป เพียงแต่มีการใช้ระยะขอบรอบๆ ไอคอนของรายการ เนื่องจากไอคอนจะดูดีกว่าเมื่อมีขนาดเล็ก ไอคอน ต้องเป็น Vector Drawable ที่ปรับสีได้ คาดว่าคำใบ้นี้จะแสดงเฉพาะ สำหรับรายการที่เรียกดูได้เท่านั้น
ข้อมูลโค้ดต่อไปนี้แสดงวิธีตั้งค่ารูปแบบเนื้อหาเริ่มต้นสำหรับ รายการที่เรียกดูได้เป็นตารางกริด และรายการที่เล่นได้เป็นรายการ
Kotlin
import androidx.media.utils.MediaConstants @Nullable override fun onGetRoot( @NonNull clientPackageName: String, clientUid: Int, @Nullable rootHints: Bundle ): BrowserRoot { val extras = Bundle() extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM) return BrowserRoot(ROOT_ID, extras) }
Java
import androidx.media.utils.MediaConstants; @Nullable @Override public BrowserRoot onGetRoot( @NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { Bundle extras = new Bundle(); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM); return new BrowserRoot(ROOT_ID, extras); }
ตั้งค่ารูปแบบเนื้อหาต่อรายการ
Content Style API ช่วยให้คุณลบล้างรูปแบบเนื้อหาเริ่มต้นสำหรับรายการสื่อที่เรียกดูได้ ของรายการย่อย รวมถึงรายการสื่อเอง
หากต้องการลบล้างค่าเริ่มต้นสำหรับรายการย่อยของรายการสื่อที่เรียกดูได้ ให้สร้าง
แพ็กเกจเนื้อหาพิเศษใน MediaDescription
ของรายการสื่อ แล้วเพิ่มคำแนะนำเดียวกันกับที่
กล่าวถึงก่อนหน้านี้ DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
จะมีผลกับรายการย่อยที่เล่นได้ของรายการนั้น ส่วน
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
จะมีผลกับรายการย่อยที่เรียกดูได้ของรายการนั้น
หากต้องการลบล้างค่าเริ่มต้นสำหรับรายการสื่อรายการนั้น ไม่ใช่รายการย่อย ให้สร้างแพ็กเกจเนื้อหาพิเศษใน MediaDescription
ของรายการสื่อ
และเพิ่มคำแนะนำที่มีคีย์
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
ใช้ค่าเดียวกันกับที่อธิบายไว้ก่อนหน้านี้เพื่อระบุการนำเสนอของสินค้า
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง MediaItem
ที่เรียกดูได้ซึ่ง
ลบล้างรูปแบบเนื้อหาเริ่มต้นสำหรับทั้งตัวมันเองและองค์ประกอบย่อย โดยจะจัดรูปแบบ
ตัวเองเป็นรายการหมวดหมู่ รายการย่อยที่เรียกดูได้เป็นรายการ และรายการย่อยที่
เล่นได้เป็นรายการตารางกริด
Kotlin
import androidx.media.utils.MediaConstants private fun createBrowsableMediaItem( mediaId: String, folderName: String, iconUri: Uri ): MediaBrowser.MediaItem { val mediaDescriptionBuilder = MediaDescription.Builder() mediaDescriptionBuilder.setMediaId(mediaId) mediaDescriptionBuilder.setTitle(folderName) mediaDescriptionBuilder.setIconUri(iconUri) val extras = Bundle() extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM) mediaDescriptionBuilder.setExtras(extras) return MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE) }
Java
import androidx.media.utils.MediaConstants; private MediaBrowser.MediaItem createBrowsableMediaItem( String mediaId, String folderName, Uri iconUri) { MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder(); mediaDescriptionBuilder.setMediaId(mediaId); mediaDescriptionBuilder.setTitle(folderName); mediaDescriptionBuilder.setIconUri(iconUri); Bundle extras = new Bundle(); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM); mediaDescriptionBuilder.setExtras(extras); return new MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE); }
จัดกลุ่มรายการโดยใช้คำแนะนำชื่อ
หากต้องการจัดกลุ่มรายการสื่อที่เกี่ยวข้องไว้ด้วยกัน คุณต้องใช้คำแนะนำต่อรายการ รายการสื่อทุกรายการ
ในกลุ่มต้องประกาศแพ็กเกจพิเศษใน MediaDescription
ที่
มีการแมปกับคีย์
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE
และค่าสตริงที่เหมือนกัน แปลสตริงนี้ซึ่งใช้เป็น
ชื่อของกลุ่ม
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้าง MediaItem
ที่มีส่วนหัวของกลุ่มย่อยเป็น "Songs"
Kotlin
import androidx.media.utils.MediaConstants private fun createMediaItem( mediaId: String, folderName: String, iconUri: Uri ): MediaBrowser.MediaItem { val mediaDescriptionBuilder = MediaDescription.Builder() mediaDescriptionBuilder.setMediaId(mediaId) mediaDescriptionBuilder.setTitle(folderName) mediaDescriptionBuilder.setIconUri(iconUri) val extras = Bundle() extras.putString( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") mediaDescriptionBuilder.setExtras(extras) return MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), /* playable or browsable flag*/) }
Java
import androidx.media.utils.MediaConstants; private MediaBrowser.MediaItem createMediaItem(String mediaId, String folderName, Uri iconUri) { MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder(); mediaDescriptionBuilder.setMediaId(mediaId); mediaDescriptionBuilder.setTitle(folderName); mediaDescriptionBuilder.setIconUri(iconUri); Bundle extras = new Bundle(); extras.putString( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs"); mediaDescriptionBuilder.setExtras(extras); return new MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), /* playable or browsable flag*/); }
แอปของคุณต้องส่งรายการสื่อทั้งหมดที่ต้องการจัดกลุ่มไว้ด้วยกันเป็น บล็อกที่ต่อเนื่องกัน ตัวอย่างเช่น สมมติว่าคุณต้องการแสดงกลุ่มรายการสื่อ 2 กลุ่ม ได้แก่ "เพลง" และ "อัลบั้ม" ตามลำดับ และแอปของคุณส่งรายการสื่อ 5 รายการตามลำดับต่อไปนี้
- รายการสื่อ A ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- รายการสื่อ B ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
- รายการสื่อ C ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- รายการสื่อ D ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- รายการสื่อ E ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
เนื่องจากรายการสื่อสำหรับกลุ่ม "เพลง" และกลุ่ม "อัลบั้ม" ไม่ได้อยู่ในบล็อกที่ต่อเนื่องกัน Android Auto และ Android Automotive OS จึงตีความว่ามี 4 กลุ่มดังนี้
- กลุ่ม 1 ชื่อ "เพลง" ซึ่งมีรายการสื่อ ก
- กลุ่ม 2 ชื่อ "อัลบั้ม" ซึ่งมีรายการสื่อ B
- กลุ่ม 3 ชื่อ "เพลง" ซึ่งมีรายการสื่อ C และ D
- กลุ่ม 4 ชื่อ "อัลบั้ม" ที่มีรายการสื่อ E
หากต้องการแสดงรายการเหล่านี้ใน 2 กลุ่ม แอปของคุณต้องส่งรายการสื่อตามลำดับต่อไปนี้แทน
- รายการสื่อ A ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- รายการสื่อ C ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- รายการสื่อ D ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
- รายการสื่อ B ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
- รายการสื่อ E ที่มี
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
แสดงตัวบ่งชี้ข้อมูลเมตาเพิ่มเติม
คุณสามารถรวมตัวบ่งชี้ข้อมูลเมตาเพิ่มเติมเพื่อให้ข้อมูลโดยย่อ สำหรับเนื้อหาในโครงสร้างของเบราว์เซอร์สื่อและระหว่างการเล่น ในโครงสร้างการเรียกดู Android Auto และ Android Automotive OS จะอ่านข้อมูลเพิ่มเติมที่เชื่อมโยงกับรายการและมองหาค่าคงที่บางอย่างเพื่อพิจารณาว่าจะแสดงตัวบ่งชี้ใด ในระหว่างการเล่นสื่อ Android Auto และ Android Automotive OS จะอ่านข้อมูลเมตาสำหรับเซสชันสื่อและค้นหาค่าคงที่บางอย่างเพื่อกำหนดตัวบ่งชี้ที่จะแสดง

รูปที่ 3 มุมมองการเล่นพร้อมข้อมูลเมตาที่ระบุเพลง และศิลปิน รวมถึงไอคอนที่ระบุเนื้อหาไม่เหมาะสม

รูปที่ 4 มุมมองการเรียกดูที่มีจุดสำหรับเนื้อหาที่ยังไม่ได้เล่นใน รายการแรกและแถบความคืบหน้าสำหรับเนื้อหาที่เล่นบางส่วนใน รายการที่ 2
คุณใช้ค่าคงที่ต่อไปนี้ได้ทั้ง MediaItem
ส่วนขยายคำอธิบายและส่วนขยายMediaMetadata
EXTRA_DOWNLOAD_STATUS
: แสดงสถานะการดาวน์โหลดของรายการ ใช้ค่าคงที่นี้เป็น คีย์ ค่าคงที่แบบยาวต่อไปนี้คือค่าที่เป็นไปได้STATUS_DOWNLOADED
: ดาวน์โหลดรายการเสร็จสมบูรณ์STATUS_DOWNLOADING
: กำลังดาวน์โหลดรายการSTATUS_NOT_DOWNLOADED
: ไม่ได้ดาวน์โหลดรายการ
METADATA_KEY_IS_EXPLICIT
: ระบุว่ารายการมีเนื้อหาโจ่งแจ้งหรือไม่ หากต้องการระบุว่ารายการเป็นเนื้อหา โจ่งแจ้ง ให้ใช้ค่าคงที่นี้เป็นคีย์และค่าMETADATA_VALUE_ATTRIBUTE_PRESENT
เป็นค่า
ค่าคงที่ต่อไปนี้ใช้ได้เท่านั้นในส่วนเสริมของคำอธิบาย MediaItem
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
: ระบุสถานะการสิ้นสุดของเนื้อหารูปแบบยาว เช่น ตอนของพอดแคสต์หรือ หนังสือเสียง ใช้ค่าคงที่นี้เป็นคีย์ โดยค่าที่เป็นไปได้คือค่าคงที่จำนวนเต็มต่อไปนี้DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: ไม่ได้เล่นไอเทมเลยDESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: เล่นรายการไปแล้วบางส่วน และตำแหน่งปัจจุบันอยู่ตรงกลางDESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
รายการเสร็จสมบูรณ์แล้ว
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: ระบุจำนวนความคืบหน้าในการดูคอนเทนต์แบบยาวเป็นค่าทศนิยม ระหว่าง 0.0 ถึง 1.0 (รวม) ข้อมูลเพิ่มเติมนี้จะให้ข้อมูลเพิ่มเติมเกี่ยวกับPARTIALLY_PLAYING
สถานะเพื่อให้ Android Auto หรือ Android Automotive OS แสดงตัวบ่งชี้ความคืบหน้าที่มีความหมายมากขึ้น เช่น แถบความคืบหน้า หากคุณใช้ส่วนเสริมนี้ โปรดดูส่วนเกี่ยวกับ การอัปเดตแถบความคืบหน้าในมุมมองการเรียกดูขณะเล่นเนื้อหา ในคำแนะนำนี้เพื่อดูวิธีอัปเดตตัวบ่งชี้นี้หลังจากแสดงผลครั้งแรก
หากต้องการแสดงตัวบ่งชี้ที่ปรากฏขณะที่ผู้ใช้กำลังเรียกดูทรีการเรียกดูสื่อ
ให้สร้างชุดข้อมูลเพิ่มเติมที่มีค่าคงที่เหล่านี้อย่างน้อย 1 รายการ แล้ว
ส่งชุดข้อมูลดังกล่าวไปยังเมธอด MediaDescription.Builder.setExtras()
ข้อมูลโค้ดต่อไปนี้แสดงวิธีแสดงตัวบ่งชี้สำหรับรายการสื่อที่โจ่งแจ้งหรืออาจไม่เหมาะสมซึ่งดูไปแล้ว 70%
Kotlin
import androidx.media.utils.MediaConstants val extras = Bundle() extras.putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS, MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED) extras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7) val description = MediaDescriptionCompat.Builder() .setMediaId(/*...*/) .setTitle(resources.getString(/*...*/)) .setExtras(extras) .build() return MediaBrowserCompat.MediaItem(description, /* flags */)
Java
import androidx.media.utils.MediaConstants; Bundle extras = new Bundle(); extras.putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS, MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED); extras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7); MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setMediaId(/*...*/) .setTitle(resources.getString(/*...*/)) .setExtras(extras) .build(); return new MediaBrowserCompat.MediaItem(description, /* flags */);
หากต้องการแสดงตัวบ่งชี้สำหรับรายการสื่อที่กำลังเล่นอยู่ คุณสามารถ
ประกาศค่า Long
สำหรับ METADATA_KEY_IS_EXPLICIT
หรือ EXTRA_DOWNLOAD_STATUS
ใน MediaMetadataCompat
ของ mediaSession
คุณไม่สามารถแสดงเครื่องหมาย
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
หรือ
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
ในมุมมองการเล่น
ข้อมูลโค้ดต่อไปนี้แสดงวิธีระบุว่าเพลงที่กำลังเล่นใน มุมมองการเล่นเป็นเพลงที่โจ่งแจ้งและดาวน์โหลดแล้ว
Kotlin
import androidx.media.utils.MediaConstants mediaSession.setMetadata( MediaMetadataCompat.Builder() .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name") .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name") .putString( MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUri.toString()) .putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) .putLong( MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS, MediaDescriptionCompat.STATUS_DOWNLOADED) .build())
Java
import androidx.media.utils.MediaConstants; mediaSession.setMetadata( new MediaMetadataCompat.Builder() .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name") .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name") .putString( MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUri.toString()) .putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) .putLong( MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS, MediaDescriptionCompat.STATUS_DOWNLOADED) .build());
อัปเดตแถบความคืบหน้าในมุมมองการเรียกดูขณะเล่นเนื้อหา
ดังที่ได้กล่าวไว้ก่อนหน้านี้ คุณสามารถใช้
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
เพิ่มเติมเพื่อแสดงแถบความคืบหน้าสำหรับเนื้อหาที่เล่นบางส่วนใน
มุมมองการเรียกดู อย่างไรก็ตาม หากผู้ใช้เล่นเนื้อหาที่เล่นค้างไว้ต่อจาก Android Auto หรือ Android Automotive OS ตัวบ่งชี้ดังกล่าวจะ
ไม่ถูกต้องเมื่อเวลาผ่านไป
สำหรับ Android Auto และ Android Automotive OS
เพื่อให้แถบความคืบหน้าเป็นข้อมูลล่าสุดอยู่เสมอ คุณสามารถระบุข้อมูลเพิ่มเติมใน
MediaMetadataCompat
และ PlaybackStateCompat
เพื่อลิงก์เนื้อหาที่กำลังเล่นกับ
รายการสื่อในมุมมองการเรียกดู รายการสื่อต้องมีคุณสมบัติตรงตามข้อกำหนดต่อไปนี้เพื่อให้มีแถบความคืบหน้าที่อัปเดตโดยอัตโนมัติ
- เมื่อสร้างแล้ว
MediaItem
ต้องส่งDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
ในส่วนข้อมูลเพิ่มเติมโดยมีค่าระหว่าง 0.0 ถึง 1.0 (รวม) MediaMetadataCompat
ต้องส่งMETADATA_KEY_MEDIA_ID
พร้อมค่าสตริงที่เท่ากับ รหัสสื่อ ที่ส่งไปยังMediaItem
PlaybackStateCompat
ต้องมีส่วนเสริมที่มีคีย์PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
ที่แมปกับค่าสตริงที่เท่ากับ รหัสสื่อ ที่ส่งไปยังMediaItem
ข้อมูลโค้ดต่อไปนี้แสดงวิธีระบุว่ารายการที่กำลังเล่นอยู่ ลิงก์กับรายการในมุมมองการเรียกดู
Kotlin
import androidx.media.utils.MediaConstants // When the MediaItem is constructed to show in the browse view. // Suppose the item was 25% complete when the user launched the browse view. val mediaItemExtras = Bundle() mediaItemExtras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25) val description = MediaDescriptionCompat.Builder() .setMediaId("my-media-id") .setExtras(mediaItemExtras) // ...and any other setters. .build() return MediaBrowserCompat.MediaItem(description, /* flags */) // Elsewhere, when the user has selected MediaItem for playback. mediaSession.setMetadata( MediaMetadataCompat.Builder() .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id") // ...and any other setters. .build()) val playbackStateExtras = Bundle() playbackStateExtras.putString( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id") mediaSession.setPlaybackState( PlaybackStateCompat.Builder() .setExtras(playbackStateExtras) // ...and any other setters. .build())
Java
import androidx.media.utils.MediaConstants; // When the MediaItem is constructed to show in the browse view. // Suppose the item was 25% complete when the user launched the browse view. Bundle mediaItemExtras = new Bundle(); mediaItemExtras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25); MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setMediaId("my-media-id") .setExtras(mediaItemExtras) // ...and any other setters. .build(); return MediaBrowserCompat.MediaItem(description, /* flags */); // Elsewhere, when the user has selected MediaItem for playback. mediaSession.setMetadata( new MediaMetadataCompat.Builder() .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id") // ...and any other setters. .build()); Bundle playbackStateExtras = new Bundle(); playbackStateExtras.putString( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id"); mediaSession.setPlaybackState( new PlaybackStateCompat.Builder() .setExtras(playbackStateExtras) // ...and any other setters. .build());
แสดงผลการค้นหาที่เรียกดูได้

รูปที่ 5 มุมมองการเล่นที่มีตัวเลือก "ผลการค้นหา" สำหรับ ดูรายการสื่อที่เกี่ยวข้องกับการค้นหาด้วยเสียงของผู้ใช้
แอปของคุณสามารถแสดงผลการค้นหาตามบริบทซึ่งจะแสดงต่อผู้ใช้เมื่อเริ่มคำค้นหา Android Auto และระบบปฏิบัติการ Android Automotive จะแสดงผลลัพธ์เหล่านี้ผ่านอินเทอร์เฟซคำค้นหาหรือผ่านความสามารถที่อิงตามคำค้นหาที่ทำก่อนหน้านี้ในเซสชัน ดูข้อมูลเพิ่มเติมได้ที่ส่วนรองรับการสั่งงานด้วยเสียงในคู่มือนี้
หากต้องการแสดงผลการค้นหาที่เรียกดูได้ ให้ใส่คีย์ค่าคงที่
BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
ในแพ็กเกจข้อมูลเพิ่มเติมของเมธอด onGetRoot()
ของบริการ โดยแมปกับบูลีน true
ข้อมูลโค้ดต่อไปนี้แสดงวิธีเปิดใช้การรองรับในเมธอด onGetRoot()
Kotlin
import androidx.media.utils.MediaConstants @Nullable fun onGetRoot( @NonNull clientPackageName: String, clientUid: Int, @Nullable rootHints: Bundle ): BrowserRoot { val extras = Bundle() extras.putBoolean( MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true) return BrowserRoot(ROOT_ID, extras) }
Java
import androidx.media.utils.MediaConstants; @Nullable @Override public BrowserRoot onGetRoot( @NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { Bundle extras = new Bundle(); extras.putBoolean( MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true); return new BrowserRoot(ROOT_ID, extras); }
หากต้องการเริ่มแสดงผลการค้นหา ให้ลบล้างเมธอด onSearch()
ในบริการเบราว์เซอร์สื่อ Android Auto และระบบปฏิบัติการ Android Automotive
จะส่งต่อคำค้นหาของผู้ใช้ไปยังเมธอดนี้ทุกครั้งที่ผู้ใช้เรียกใช้อินเทอร์เฟซคำค้นหาหรือความสามารถในการใช้งาน "ผลการค้นหา"
คุณจัดระเบียบผลการค้นหาจากonSearch()
เมธอดของบริการโดยใช้รายการชื่อ
เพื่อให้เรียกดูได้ง่ายขึ้น เช่น หากแอปของคุณเล่นเพลง คุณอาจ
จัดระเบียบผลการค้นหาตามอัลบั้ม ศิลปิน และเพลง
ข้อมูลโค้ดต่อไปนี้แสดงการใช้งานเมธอด onSearch()
อย่างง่าย
Kotlin
fun onSearch(query: String, extras: Bundle) { // Detach from results to unblock the caller (if a search is expensive). result.detach() object:AsyncTask() { internal var searchResponse:ArrayList internal var succeeded = false protected fun doInBackground(vararg params:Void):Void { searchResponse = ArrayList() if (doSearch(query, extras, searchResponse)) { succeeded = true } return null } protected fun onPostExecute(param:Void) { if (succeeded) { // Sending an empty List informs the caller that there were no results. result.sendResult(searchResponse) } else { // This invokes onError() on the search callback. result.sendResult(null) } return null } }.execute() } // Populates resultsToFill with search results. Returns true on success or false on error. private fun doSearch( query: String, extras: Bundle, resultsToFill: ArrayList ): Boolean { // Implement this method. }
Java
@Override public void onSearch(final String query, final Bundle extras, Result<List<MediaItem>> result) { // Detach from results to unblock the caller (if a search is expensive). result.detach(); new AsyncTask<Void, Void, Void>() { List<MediaItem> searchResponse; boolean succeeded = false; @Override protected Void doInBackground(Void... params) { searchResponse = new ArrayList<MediaItem>(); if (doSearch(query, extras, searchResponse)) { succeeded = true; } return null; } @Override protected void onPostExecute(Void param) { if (succeeded) { // Sending an empty List informs the caller that there were no results. result.sendResult(searchResponse); } else { // This invokes onError() on the search callback. result.sendResult(null); } } }.execute() } /** Populates resultsToFill with search results. Returns true on success or false on error. */ private boolean doSearch(String query, Bundle extras, ArrayList<MediaItem> resultsToFill) { // Implement this method. }
การทำงานของการเรียกดูที่กำหนดเอง

รูปที่ 6 การเรียกดูที่กำหนดเองรายการเดียว
การดำเนินการเรียกดูที่กำหนดเองช่วยให้คุณเพิ่มไอคอนและป้ายกำกับที่กำหนดเองลงในออบเจ็กต์ MediaItem
ของแอปในแอปสื่อของรถยนต์ และจัดการการโต้ตอบของผู้ใช้กับการดำเนินการเหล่านี้ได้ ซึ่งจะช่วยให้คุณขยายฟังก์ชันการทำงานของแอปสื่อได้หลายวิธี เช่น การเพิ่มการดำเนินการ "ดาวน์โหลด" "เพิ่มลงในคิว" "เปิดวิทยุ" "รายการโปรด" หรือ "นำออก"

รูปที่ 7 เมนูเพิ่มเติมของการดำเนินการเรียกดูที่กำหนดเอง
หากมีการดำเนินการที่กำหนดเองมากกว่าที่ OEM อนุญาตให้แสดง ระบบจะแสดง เมนูที่ซ่อนอยู่ต่อผู้ใช้
วิธีการทำงาน
การกระทำในการเรียกดูที่กำหนดเองแต่ละรายการจะกำหนดด้วยข้อมูลต่อไปนี้
- รหัสการดำเนินการ (ตัวระบุสตริงที่ไม่ซ้ำกัน)
- ป้ายกำกับการดำเนินการ (ข้อความที่แสดงต่อผู้ใช้)
- URI ของไอคอนการดำเนินการ (Vector Drawable ที่ปรับสมดุลสีเขียว-แดงได้)
คุณกำหนดรายการการเรียกดูที่กำหนดเองทั่วโลกเป็นส่วนหนึ่งของ
BrowseRoot
จากนั้นคุณจะแนบชุดย่อยของการดำเนินการเหล่านี้กับMediaItem.
แต่ละรายการได้
เมื่อผู้ใช้โต้ตอบกับการเรียกดูที่กำหนดเอง แอปของคุณจะได้รับการเรียกกลับ
ใน onCustomAction()
จากนั้นคุณจะจัดการการดำเนินการและอัปเดตรายการการดำเนินการสำหรับ MediaItem
ได้หากจำเป็น ซึ่งจะเป็นประโยชน์สำหรับการดำเนินการแบบเก็บสถานะ
เช่น "รายการโปรด" และ "ดาวน์โหลด" สำหรับคำสั่งที่ไม่ต้องอัปเดต เช่น "เปิด
วิทยุ" คุณไม่จำเป็นต้องอัปเดตรายการคำสั่ง

รูปที่ 8 แถบเครื่องมือการดำเนินการเรียกดูที่กำหนดเอง
นอกจากนี้ คุณยังแนบการดำเนินการเรียกดูที่กำหนดเองกับรูทของโหนดการเรียกดูได้ด้วย การดำเนินการเหล่านี้ จะแสดงในแถบเครื่องมือรองใต้แถบเครื่องมือหลัก
วิธีติดตั้งใช้งานการดำเนินการเรียกดูที่กำหนดเอง
ขั้นตอนในการเพิ่มการเรียกดูที่กำหนดเองไปยังโปรเจ็กต์มีดังนี้
- ลบล้าง 2 วิธีต่อไปนี้ในการติดตั้งใช้งาน
MediaBrowserServiceCompat
- แยกวิเคราะห์ขีดจํากัดการดำเนินการที่รันไทม์
- ใน
onGetRoot()
ให้รับจำนวนการกระทำสูงสุดที่อนุญาตสำหรับแต่ละMediaItem
โดยใช้คีย์BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
ในrootHints
Bundle
ขีดจำกัด 0 แสดงว่าระบบไม่รองรับฟีเจอร์นี้
- ใน
- สร้างรายการการทำงานของการเรียกดูที่กำหนดเองส่วนกลาง
- สำหรับการดำเนินการแต่ละรายการ ให้สร้างออบเจ็กต์
Bundle
ที่มีคีย์ต่อไปนี้ *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
: รหัสการดำเนินการ *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
: ป้ายกำกับการดำเนินการ *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
: URI ของไอคอนการดำเนินการ * เพิ่มออบเจ็กต์Bundle
ของการดำเนินการทั้งหมดลงในรายการ
- สำหรับการดำเนินการแต่ละรายการ ให้สร้างออบเจ็กต์
- เพิ่มรายการส่วนกลางลงใน
BrowseRoot
ดังนี้- ใน
BrowseRoot
extrasBundle
ให้เพิ่มรายการการดำเนินการเป็นParcelable
Arraylist
โดยใช้คีย์BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
- ใน
- เพิ่มการดำเนินการไปยังออบเจ็กต์
MediaItem
โดยทำดังนี้- คุณเพิ่มการดำเนินการไปยังออบเจ็กต์
MediaItem
แต่ละรายการได้โดยใส่รายการรหัสการดำเนินการในส่วนMediaDescriptionCompat
extras โดยใช้คีย์DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST
รายการนี้ต้องเป็นชุดย่อยของรายการการดำเนินการส่วนกลางที่คุณกำหนดไว้ในBrowseRoot
- คุณเพิ่มการดำเนินการไปยังออบเจ็กต์
- จัดการการดำเนินการและแสดงความคืบหน้าหรือผลลัพธ์
- ใน
onCustomAction
ให้จัดการการดำเนินการตามรหัสการดำเนินการและข้อมูลอื่นๆ ที่คุณต้องการ คุณรับรหัสของMediaItem
ที่ทริกเกอร์การดำเนินการจากส่วนเสริมได้โดยใช้คีย์EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
- คุณอัปเดตรายการการดำเนินการสำหรับ
MediaItem
ได้โดยใส่คีย์EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
ในแพ็กเกจความคืบหน้าหรือผลลัพธ์
- ใน
การเปลี่ยนแปลงบางอย่างที่คุณทำได้ใน BrowserServiceCompat
เพื่อเริ่มต้นใช้งาน
การเรียกดูที่กำหนดเองมีดังนี้
ลบล้าง BrowserServiceCompat
คุณต้องลบล้างเมธอดต่อไปนี้ใน MediaBrowserServiceCompat
public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)
public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)
ขีดจำกัดการแยกวิเคราะห์การกระทำ
คุณควรตรวจสอบว่าระบบรองรับการดำเนินการเรียกดูที่กำหนดเองกี่รายการ
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0) }
สร้างการเรียกดูที่กำหนดเอง
โดยแต่ละการกระทำจะต้องรวมอยู่ใน Bundle
แยกกัน
- รหัสการทำงาน
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID, "<ACTION_ID>")
- ป้ายกำกับการดำเนินการ
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL, "<ACTION_LABEL>")
- URI ของไอคอนการดำเนินการ
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, "<ACTION_ICON_URI>")
เพิ่มการดำเนินการเรียกดูที่กำหนดเองไปยัง Parceable
ArrayList
เพิ่มออบเจ็กต์ Custom Browse Action ทั้งหมดลงใน ArrayList
Bundle
private ArrayList<Bundle> createCustomActionsList( CustomBrowseAction browseActions) { ArrayList<Bundle> browseActionsBundle = new ArrayList<>(); for (CustomBrowseAction browseAction : browseActions) { Bundle action = new Bundle(); action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID, browseAction.mId); action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL, getString(browseAction.mLabelResId)); action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, browseAction.mIcon); browseActionsBundle.add(action); } return browseActionsBundle; }
เพิ่มรายการการกระทำในการเรียกดูที่กำหนดเองไปยังรูทการเรียกดู
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { Bundle browserRootExtras = new Bundle(); browserRootExtras.putParcelableArrayList( BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST, createCustomActionsList())); mRoot = new BrowserRoot(ROOT_ID, browserRootExtras); return mRoot; }
เพิ่มการดำเนินการไปยัง MediaItem
MediaDescriptionCompat buildDescription (long id, String title, String subtitle, String description, Uri iconUri, Uri mediaUri, ArrayList<String> browseActionIds) { MediaDescriptionCompat.Builder bob = new MediaDescriptionCompat.Builder(); bob.setMediaId(id); bob.setTitle(title); bob.setSubtitle(subtitle); bob.setDescription(description); bob.setIconUri(iconUri); bob.setMediaUri(mediaUri); Bundle extras = new Bundle(); extras.putStringArrayList( DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST, browseActionIds); bob.setExtras(extras); return bob.build(); } MediaItem mediaItem = new MediaItem(buildDescription(...), flags);
ผลลัพธ์ของบิลด์ onCustomAction
- แยกวิเคราะห์ mediaId จาก
Bundle extras
:@Override public void onCustomAction( @NonNull String action, Bundle extras, @NonNull Result<Bundle> result){ String mediaId = extras.getString(MediaConstans.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID); }
- สำหรับผลลัพธ์แบบอะซิงโครนัส ให้แยกผลลัพธ์
result.detach()
- แพ็กเกจผลลัพธ์ของบิลด์
- ข้อความถึงผู้ใช้
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE, mContext.getString(stringRes))
- อัปเดตรายการ(ใช้เพื่ออัปเดตการดำเนินการในรายการ)
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
- เปิดมุมมองการเล่น
//Shows user the PBV without changing the playback state mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
- อัปเดตโหนดการเรียกดู
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- ข้อความถึงผู้ใช้
- หากมีข้อผิดพลาด โปรดโทรหา
result.sendError(resultBundle).
- หากต้องการอัปเดตความคืบหน้า โปรดโทรหา
result.sendProgressUpdate(resultBundle)
- โปรดโทรหา
result.sendResult(resultBundle)
เพื่อดำเนินการให้เสร็จสิ้น
อัปเดตสถานะการดำเนินการ
การใช้เมธอด result.sendProgressUpdate(resultBundle)
กับคีย์ EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
จะช่วยให้คุณอัปเดต MediaItem
เพื่อแสดงสถานะใหม่ของการดำเนินการได้ ซึ่งจะช่วยให้คุณให้ความคิดเห็นแบบเรียลไทม์แก่ผู้ใช้เกี่ยวกับความคืบหน้าและ
ผลลัพธ์ของการกระทำของผู้ใช้ได้
ตัวอย่าง: การดำเนินการดาวน์โหลด
ตัวอย่างวิธีใช้ฟีเจอร์นี้เพื่อใช้การดำเนินการดาวน์โหลด ที่มี 3 สถานะ
- ดาวน์โหลด: นี่คือสถานะเริ่มต้นของการดำเนินการ เมื่อผู้ใช้เลือก
การดำเนินการนี้ คุณสามารถสลับกับการดำเนินการ "ดาวน์โหลด" และเรียก
sendProgressUpdate
เพื่ออัปเดต UI - กำลังดาวน์โหลด: สถานะนี้บ่งชี้ว่ากำลังดาวน์โหลด คุณสามารถ ใช้สถานะนี้เพื่อแสดงแถบความคืบหน้าหรือตัวบ่งชี้อื่นแก่ผู้ใช้
- ดาวน์โหลดแล้ว: สถานะนี้บ่งบอกว่าการดาวน์โหลดเสร็จสมบูรณ์แล้ว เมื่อดาวน์โหลดเสร็จแล้ว คุณสามารถสลับ "กำลังดาวน์โหลด" กับ "ดาวน์โหลดแล้ว" และเรียกใช้
sendResult
ด้วยคีย์EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
เพื่อระบุว่าควรรีเฟรชรายการ นอกจากนี้ คุณยังใช้คีย์EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
เพื่อแสดงข้อความว่าดำเนินการสำเร็จแล้วต่อผู้ใช้ได้ด้วย
แนวทางนี้ช่วยให้คุณแสดงความคิดเห็นที่ชัดเจนแก่ผู้ใช้เกี่ยวกับกระบวนการดาวน์โหลด และสถานะปัจจุบัน คุณเพิ่มรายละเอียดได้มากขึ้นด้วยไอคอนเพื่อแสดงสถานะการดาวน์โหลด 25%, 50%, 75%
ตัวอย่าง: การดำเนินการที่ชื่นชอบ
อีกตัวอย่างหนึ่งคือการดำเนินการที่ชื่นชอบซึ่งมี 2 สถานะ ดังนี้
- รายการโปรด: การดำเนินการนี้จะแสดงสำหรับรายการที่ไม่ได้อยู่ใน
รายการโปรดของผู้ใช้ เมื่อผู้ใช้เลือกการดำเนินการนี้ คุณจะสลับการดำเนินการนี้กับ "รายการโปรด" และเรียกใช้
sendResult
ด้วยคีย์EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
เพื่ออัปเดต UI ได้ - รายการโปรด: การดำเนินการนี้จะแสดงสำหรับรายการที่อยู่ในรายการโปรดของผู้ใช้
เมื่อผู้ใช้เลือกการดำเนินการนี้ คุณสามารถสลับการดำเนินการนี้กับ "รายการโปรด" และเรียกใช้
sendResult
ด้วยคีย์EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
เพื่ออัปเดต UI
แนวทางนี้ช่วยให้ผู้ใช้จัดการรายการโปรดได้อย่างชัดเจนและสอดคล้องกัน
ตัวอย่างเหล่านี้แสดงให้เห็นถึงความยืดหยุ่นของ "การดำเนินการเรียกดูที่กำหนดเอง" และวิธีที่คุณสามารถ ใช้เพื่อติดตั้งใช้งานฟังก์ชันการทำงานที่หลากหลายพร้อมความคิดเห็นแบบเรียลไทม์เพื่อ ปรับปรุงประสบการณ์ของผู้ใช้ในแอปสื่อของรถยนต์
ดูตัวอย่างการติดตั้งใช้งานฟีเจอร์นี้ทั้งหมดได้ใน
TestMediaApp
โปรเจ็กต์
เปิดใช้การควบคุมการเล่น
Android Auto และ Android Automotive OS จะส่งคำสั่งควบคุมการเล่นผ่าน MediaSessionCompat
ของบริการ
คุณต้องลงทะเบียนเซสชันและใช้วิธีการเรียกกลับที่เชื่อมโยง
ลงทะเบียนเซสชันสื่อ
ในเมธอด onCreate()
ของบริการเบราว์เซอร์สื่อ ให้สร้าง MediaSessionCompat
จากนั้นลงทะเบียนเซสชันสื่อโดยเรียกใช้ setSessionToken()
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างและลงทะเบียนเซสชันสื่อ
Kotlin
override fun onCreate() { super.onCreate() ... // Start a new MediaSession. val session = MediaSessionCompat(this, "session tag").apply { // Set a callback object that implements MediaSession.Callback // to handle play control requests. setCallback(MyMediaSessionCallback()) } sessionToken = session.sessionToken ... }
Java
public void onCreate() { super.onCreate(); ... // Start a new MediaSession. MediaSessionCompat session = new MediaSessionCompat(this, "session tag"); setSessionToken(session.getSessionToken()); // Set a callback object that implements MediaSession.Callback // to handle play control requests. session.setCallback(new MyMediaSessionCallback()); ... }
เมื่อสร้างออบเจ็กต์เซสชันสื่อ คุณจะตั้งค่าออบเจ็กต์การเรียกกลับที่จะใช้
เพื่อจัดการคำขอควบคุมการเล่น คุณสร้างออบเจ็กต์การเรียกกลับนี้ได้โดย
ระบุการใช้งานของคลาส MediaSessionCompat.Callback
สำหรับแอปของคุณ ส่วนถัดไปจะอธิบายวิธีใช้ออบเจ็กต์นี้
ใช้คำสั่งเล่น
เมื่อผู้ใช้ขอเล่นรายการสื่อจากแอปของคุณ Android Automotive
OS และ Android Auto จะใช้คลาส MediaSessionCompat.Callback
จากออบเจ็กต์ MediaSessionCompat
ของแอปที่ได้จากบริการเบราว์เซอร์สื่อของแอป เมื่อผู้ใช้
ต้องการควบคุมการเล่นเนื้อหา เช่น หยุดเล่นชั่วคราวหรือข้ามไปยังแทร็กถัดไป
Android Auto และ Android Automotive OS จะเรียกใช้เมธอดของออบเจ็กต์การเรียกกลับรายการใดรายการหนึ่ง
หากต้องการจัดการการเล่นเนื้อหา แอปของคุณต้องขยายMediaSessionCompat.Callback
คลาสแบบนามธรรมและใช้เมธอดที่แอปของคุณรองรับ
ใช้เมธอดเรียกกลับทั้งหมดต่อไปนี้ที่เหมาะกับ ประเภทเนื้อหาที่แอปของคุณนำเสนอ
onPrepare()
- เรียกใช้เมื่อมีการเปลี่ยนแหล่งที่มาของสื่อ Android Automotive OS ยังเรียกใช้ เมธอดนี้ทันทีหลังจากบูตด้วย แอปสื่อของคุณต้องใช้วิธีนี้
onPlay()
- เรียกใช้หากผู้ใช้เลือกเล่นโดยไม่เลือกรายการที่เฉพาะเจาะจง แอปของคุณต้องเล่นเนื้อหาเริ่มต้น หรือหากหยุดการเล่นชั่วคราวด้วย
onPause()
แอปของคุณจะเล่นต่อหมายเหตุ: แอปของคุณไม่ควรเริ่มเล่นเพลงโดยอัตโนมัติ เมื่อ Android Automotive OS หรือ Android Auto เชื่อมต่อกับเบราว์เซอร์สื่อ ของคุณ ดูข้อมูลเพิ่มเติมได้ที่ส่วนเกี่ยวกับ การตั้งค่าสถานะการเล่นเริ่มต้น
onPlayFromMediaId()
- เรียกใช้เมื่อผู้ใช้เลือกเล่นรายการที่เฉพาะเจาะจง ระบบจะส่งเมธอด ID ที่บริการเบราว์เซอร์สื่อของคุณกำหนด ให้กับรายการสื่อในลำดับชั้นเนื้อหา
onPlayFromSearch()
- เรียกใช้เมื่อผู้ใช้เลือกเล่นจากคำค้นหา แอปต้อง เลือกตัวเลือกที่เหมาะสมตามสตริงการค้นหาที่ส่งเข้ามา
onPause()
- เรียกใช้เมื่อผู้ใช้เลือกหยุดการเล่นชั่วคราว
onSkipToNext()
- เรียกใช้เมื่อผู้ใช้เลือกข้ามไปยังรายการถัดไป
onSkipToPrevious()
- เรียกใช้เมื่อผู้ใช้เลือกข้ามไปยังรายการก่อนหน้า
onStop()
- เรียกใช้เมื่อผู้ใช้เลือกหยุดเล่น
ลบล้างวิธีการเหล่านี้ในแอปเพื่อระบุฟังก์ชันการทำงานที่ต้องการ คุณไม่จำเป็นต้องใช้วิธีการหากแอปไม่รองรับฟังก์ชันการทำงานของวิธีการนั้น เช่น หากแอปเล่นไลฟ์สด เช่น การถ่ายทอดสดกีฬา คุณไม่จำเป็นต้องใช้วิธีการ onSkipToNext()
คุณใช้การติดตั้งใช้งานเริ่มต้นของ onSkipToNext()
แทนได้
แอปของคุณไม่จำเป็นต้องมีตรรกะพิเศษใดๆ ในการเล่นเนื้อหาผ่านลำโพงของรถยนต์ เมื่อแอปได้รับคำขอให้เล่นเนื้อหา แอปจะเล่นเสียง ในลักษณะเดียวกับการเล่นเนื้อหาผ่าน ลำโพงหรือหูฟังของโทรศัพท์ผู้ใช้ Android Auto และ Android Automotive OS จะส่งเนื้อหาเสียงไปยังระบบของรถยนต์โดยอัตโนมัติเพื่อเล่นผ่าน ลำโพงของรถยนต์
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเล่นเนื้อหาเสียงได้ที่ ภาพรวมของ MediaPlayer ภาพรวมของแอปเสียง และภาพรวมของ ExoPlayer
ตั้งค่าการดำเนินการเล่นมาตรฐาน
Android Auto และ Android Automotive OS จะแสดงตัวควบคุมการเล่นตาม
การดำเนินการที่เปิดใช้ในออบเจ็กต์ PlaybackStateCompat
โดยค่าเริ่มต้น แอปของคุณต้องรองรับการดำเนินการต่อไปนี้
นอกจากนี้ แอปยังรองรับการดำเนินการต่อไปนี้ได้หากเกี่ยวข้องกับเนื้อหาของแอป
นอกจากนี้ คุณยังมีตัวเลือกในการสร้างคิวการเล่นที่แสดงต่อผู้ใช้ได้ แต่ไม่จำเป็นต้องสร้าง โดยเรียกใช้เมธอด setQueue()
และ setQueueTitle()
เปิดใช้การดำเนินการ ACTION_SKIP_TO_QUEUE_ITEM
และกำหนดการเรียกกลับ onSkipToQueueItem()
นอกจากนี้ ให้เพิ่มการรองรับไอคอนกำลังเล่น ซึ่งเป็นตัวบ่งชี้ว่ากำลังเล่นอะไรอยู่
โดยเรียกใช้เมธอด setActiveQueueItemId()
แล้วส่งรหัสของรายการที่กำลังเล่นอยู่ในคิว คุณต้อง
อัปเดต setActiveQueueItemId()
ทุกครั้งที่มีการเปลี่ยนแปลงคิว
Android Auto และ Android Automotive OS จะแสดงปุ่มสำหรับการดำเนินการแต่ละอย่างที่เปิดใช้
รวมถึงคิวการเล่น เมื่อคลิกปุ่ม ระบบจะเรียกใช้การเรียกกลับที่เกี่ยวข้องจาก
MediaSessionCompat.Callback
จองพื้นที่ที่ไม่ได้ใช้
Android Auto และ Android Automotive OS จะสำรองพื้นที่ใน UI สำหรับการดำเนินการ ACTION_SKIP_TO_PREVIOUS
และ ACTION_SKIP_TO_NEXT
หากแอปของคุณไม่รองรับฟังก์ชันใดฟังก์ชันหนึ่งเหล่านี้ Android Auto และ Android Automotive OS จะใช้พื้นที่ดังกล่าวเพื่อแสดงการดำเนินการที่กำหนดเองที่คุณสร้างขึ้น
หากไม่ต้องการกรอกข้อมูลในช่องเหล่านั้นด้วยการดำเนินการที่กำหนดเอง คุณสามารถจองช่องเหล่านั้นเพื่อให้ Android Auto และ Android Automotive OS เว้นช่องว่างไว้เมื่อใดก็ตามที่แอปไม่รองรับฟังก์ชันที่เกี่ยวข้อง โดยให้เรียกใช้เมธอด setExtras()
ด้วยชุดข้อมูลเพิ่มเติมที่มีค่าคงที่ซึ่งสอดคล้องกับฟังก์ชันที่สงวนไว้
SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
สอดคล้องกับ ACTION_SKIP_TO_NEXT
และ
SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
สอดคล้องกับ ACTION_SKIP_TO_PREVIOUS
ใช้ค่าคงที่เหล่านี้เป็นคีย์ใน
Bundle และใช้บูลีน true
เป็นค่า
ตั้งค่า PlaybackState เริ่มต้น
เมื่อ Android Auto และ Android Automotive OS สื่อสารกับบริการเบราว์เซอร์สื่อ เซสชันสื่อจะสื่อสารสถานะการเล่นเนื้อหาโดยใช้ PlaybackStateCompat
แอปของคุณไม่ควรเริ่มเล่นเพลงโดยอัตโนมัติเมื่อ Android Automotive OS
หรือ Android Auto เชื่อมต่อกับบริการ MediaBrowserService แต่ให้ใช้ Android
Auto และระบบปฏิบัติการ Android Automotive เพื่อเล่นต่อหรือเริ่มเล่นโดยอิงตามสถานะของรถยนต์หรือการดำเนินการของผู้ใช้
หากต้องการดำเนินการนี้ ให้ตั้งค่า PlaybackStateCompat
เริ่มต้นของเซสชันสื่อเป็น
STATE_STOPPED
STATE_PAUSED
STATE_NONE
หรือ STATE_ERROR
เซสชันสื่อภายใน Android Auto และ Android Automotive OS จะมีระยะเวลาเท่ากับ
ระยะเวลาการขับรถเท่านั้น ดังนั้นผู้ใช้จึงเริ่มและหยุดเซสชันเหล่านี้บ่อยครั้ง หากต้องการ
มอบประสบการณ์การใช้งานไดรฟ์ที่ราบรื่น ให้ติดตามสถานะเซสชันก่อนหน้าของผู้ใช้
เพื่อให้เมื่อแอปสื่อได้รับคำขอเล่นต่อ ผู้ใช้จะเล่นต่อจากจุดที่ค้างไว้ได้โดยอัตโนมัติ เช่น รายการสื่อที่เล่นล่าสุด PlaybackStateCompat
และคิว
เพิ่มการดำเนินการเล่นที่กำหนดเอง
คุณสามารถเพิ่มการดำเนินการเล่นที่กำหนดเองเพื่อแสดงการดำเนินการเพิ่มเติมที่แอปสื่อรองรับได้
หากมีพื้นที่ว่าง(และไม่ได้สงวนไว้) Android จะเพิ่ม
การดำเนินการที่กำหนดเองลงในตัวควบคุมการขนส่ง ไม่เช่นนั้น การดำเนินการที่กำหนดเองจะ
แสดงในเมนูรายการเพิ่มเติม การดำเนินการแบบกำหนดเองจะแสดงตามลำดับ
ที่เพิ่มลงใน PlaybackStateCompat
ใช้การกระทำที่กำหนดเองเพื่อระบุลักษณะการทำงานที่แตกต่างจากการกระทำมาตรฐาน อย่าใช้เพื่อแทนที่หรือทำซ้ำการดำเนินการมาตรฐาน
คุณเพิ่มการดำเนินการที่กำหนดเองได้โดยใช้เมธอด addCustomAction()
ในคลาส PlaybackStateCompat.Builder
ข้อมูลโค้ดต่อไปนี้แสดงวิธีเพิ่มการดำเนินการ "เริ่มสถานีวิทยุ" ที่กำหนดเอง
Kotlin
val customActionExtras = Bundle() customActionExtras.putInt( androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, androidx.media3.session.CommandButton.ICON_RADIO) stateBuilder.addCustomAction( PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon // or R.drawable.media3_icon_radio ).run { setExtras(customActionExtras) build() } )
Java
Bundle customActionExtras = new Bundle(); customActionExtras.putInt( androidx.media3.session.MediaConstants.EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT, androidx.media3.session.CommandButton.ICON_RADIO); stateBuilder.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon) // or R.drawable.media3_icon_radio .setExtras(customActionExtras) .build());
ดูตัวอย่างโดยละเอียดเพิ่มเติมของวิธีการนี้ได้ที่เมธอด setCustomAction()
ในแอปตัวอย่าง Universal Android Music Player ใน GitHub
หลังจากสร้างการดำเนินการที่กำหนดเองแล้ว เซสชันสื่อจะตอบสนองต่อการดำเนินการได้
โดยการลบล้างเมธอด onCustomAction()
ข้อมูลโค้ดต่อไปนี้แสดงวิธีที่แอปอาจตอบสนองต่อการดำเนินการ "เริ่มสถานีวิทยุ"
Kotlin
override fun onCustomAction(action: String, extras: Bundle?) { when(action) { CUSTOM_ACTION_START_RADIO_FROM_MEDIA -> { ... } } }
Java
@Override public void onCustomAction(@NonNull String action, Bundle extras) { if (CUSTOM_ACTION_START_RADIO_FROM_MEDIA.equals(action)) { ... } }
ดูตัวอย่างโดยละเอียดเพิ่มเติมของวิธีการนี้ได้ที่เมธอด onCustomAction
ในแอปตัวอย่าง Universal Android Music Player ใน GitHub
ไอคอนสำหรับการกระทำแบบกำหนดเอง
การดำเนินการที่กำหนดเองแต่ละรายการที่คุณสร้างต้องมีไอคอน
หากคำอธิบายของไอคอนนั้นตรงกับค่าคงที่ CommandButton.ICON_
อย่างใดอย่างหนึ่ง คุณควรกำหนดค่าจำนวนเต็มนั้นสำหรับคีย์ EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT
ของ
ส่วนเพิ่มเติมของการดำเนินการที่กำหนดเอง ในระบบที่รองรับ การดำเนินการนี้จะลบล้างไอคอน
ทรัพยากรที่ส่งไปยัง CustomAction.Builder
ซึ่งจะช่วยให้คอมโพเนนต์ของระบบแสดงผลการดำเนินการ
และการดำเนินการเล่นอื่นๆ ในรูปแบบที่สอดคล้องกันได้
นอกจากนี้ คุณต้องระบุทรัพยากรไอคอนด้วย แอปในรถยนต์สามารถ ทำงานบนหน้าจอที่มีขนาดและความหนาแน่นแตกต่างกันได้มากมาย ดังนั้นไอคอนที่คุณระบุ ต้องเป็นภาพวาดเวกเตอร์ Vector Drawable ช่วยให้คุณปรับขนาดชิ้นงานได้โดยไม่สูญเสียรายละเอียด นอกจากนี้ เวกเตอร์ drawable ยังช่วยให้ง่ายต่อการจัดแนวขอบและมุมตามขอบเขตพิกเซลที่มีความละเอียดน้อย
หากการดำเนินการที่กำหนดเองมีสถานะ เช่น สลับการตั้งค่าการเล่นเป็นเปิดหรือปิด ให้ระบุไอคอนที่แตกต่างกันสำหรับสถานะต่างๆ เพื่อให้ผู้ใช้เห็นการเปลี่ยนแปลงเมื่อเลือกการดำเนินการ
ระบุรูปแบบไอคอนอื่นสำหรับดำเนินการที่ปิดใช้
เมื่อการดำเนินการที่กำหนดเองไม่พร้อมใช้งานสำหรับบริบทปัจจุบัน ให้สลับ ไอคอนการดำเนินการที่กำหนดเองกับไอคอนทางเลือกที่แสดงว่าการดำเนินการ ถูกปิดใช้
ระบุรูปแบบเสียง
หากต้องการระบุว่าสื่อที่กำลังเล่นใช้รูปแบบเสียงพิเศษ
คุณสามารถระบุไอคอนที่จะแสดงในรถยนต์ที่รองรับฟีเจอร์นี้ได้ คุณ
สามารถตั้งค่า
KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
และ
KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
ในแพ็กเกจเนื้อหาพิเศษของรายการสื่อที่กำลังเล่น (ส่งไปยัง
MediaSession.setMetadata()
) อย่าลืมตั้งค่าเนื้อหาพิเศษทั้ง 2 รายการเพื่อรองรับเลย์เอาต์ต่างๆ
นอกจากนี้ คุณยังตั้งค่า KEY_IMMERSIVE_AUDIO
extra
เพื่อแจ้งให้ OEM รถยนต์ทราบว่านี่คือเสียงสมจริง และควรระมัดระวังเป็นอย่างยิ่ง
เมื่อตัดสินใจว่าจะใช้เอฟเฟกต์เสียงที่อาจรบกวน
เนื้อหาแบบสมจริงหรือไม่
เพิ่มลิงก์จากรายการที่กำลังเล่น
คุณสามารถกำหนดค่ารายการสื่อที่กำลังเล่นเพื่อให้คำบรรยายแทนเสียง คำอธิบาย หรือทั้ง 2 อย่างเป็นลิงก์ไปยังรายการสื่ออื่นๆ ซึ่งจะช่วยให้ผู้ใช้ไปยังรายการที่เกี่ยวข้องได้อย่างรวดเร็ว เช่น อาจไปยังเพลงอื่นๆ ของศิลปินคนเดียวกัน ตอนอื่นๆ ของพอดแคสต์นั้นๆ เป็นต้น หากรถรองรับฟีเจอร์นี้ ผู้ใช้ จะแตะลิงก์เพื่อไปยังเนื้อหานั้นได้
หากต้องการเพิ่มลิงก์ ให้กำหนดค่าข้อมูลเมตา
KEY_SUBTITLE_LINK_MEDIA_ID
(เพื่อลิงก์จากคำบรรยาย) หรือ
KEY_DESCRIPTION_LINK_MEDIA_ID
(เพื่อลิงก์จากคำอธิบาย) ดูรายละเอียดได้ที่เอกสารอ้างอิงสำหรับฟิลด์ข้อมูลเมตาเหล่านั้น
รองรับการสั่งงานด้วยเสียง
แอปสื่อของคุณต้องรองรับการสั่งงานด้วยเสียงเพื่อช่วยให้ผู้ขับได้รับประสบการณ์ที่ปลอดภัย และสะดวกสบายซึ่งช่วยลดสิ่งรบกวน เช่น หากแอปของคุณ กำลังเล่นสื่ออยู่ 1 รายการ ผู้ใช้สามารถพูดว่า"เปิด [ชื่อเพลง]" เพื่อสั่งให้แอปเล่นเพลงอื่นโดยไม่ต้องดูหรือแตะที่จอแสดงผลของรถยนต์ ผู้ใช้สามารถเริ่มคำค้นหาได้โดยคลิกปุ่มที่เหมาะสมบนพวงมาลัยหรือพูดคำสั่งเรียกใช้ "Ok Google"
เมื่อ Android Auto หรือ Android Automotive OS ตรวจจับและตีความการสั่งงานด้วยเสียง
ระบบจะส่งการสั่งงานด้วยเสียงนั้นไปยังแอปผ่าน onPlayFromSearch()
เมื่อได้รับการเรียกกลับนี้ แอปจะค้นหาเนื้อหาที่ตรงกับquery
สตริงและเริ่มเล่น
ผู้ใช้สามารถระบุหมวดหมู่ของคำต่างๆ ในคำค้นหาได้ เช่น แนวเพลง ศิลปิน อัลบั้ม ชื่อเพลง สถานีวิทยุ หรือเพลย์ลิสต์ เป็นต้น เมื่อสร้าง
การรองรับการค้นหา ให้พิจารณาหมวดหมู่ทั้งหมดที่เหมาะสมกับแอปของคุณ
หาก Android Auto หรือ Android Automotive OS ตรวจพบว่าคำค้นหาที่ระบุอยู่ใน
หมวดหมู่ใดหมวดหมู่หนึ่ง ระบบจะเพิ่มข้อมูลพิเศษในพารามิเตอร์ extras
คุณส่งข้อมูลเพิ่มเติมต่อไปนี้ได้
พิจารณาสตริง query
ที่ว่างเปล่า ซึ่ง Android Auto หรือ Android Automotive OS อาจส่งมาหากผู้ใช้ไม่ได้ระบุคำค้นหา
เช่น หากผู้ใช้พูดว่า "เปิดเพลงหน่อย" ในกรณีนี้ แอปอาจ
เลือกที่จะเริ่มแทร็กที่เล่นล่าสุดหรือแทร็กที่แนะนำใหม่
หากประมวลผลการค้นหาอย่างรวดเร็วไม่ได้ อย่าบล็อกใน onPlayFromSearch()
แต่ให้ตั้งค่าสถานะการเล่นเป็น STATE_CONNECTING
และทำการค้นหาในเธรดแบบไม่พร้อมกัน
เมื่อเริ่มเล่นแล้ว ให้พิจารณาป้อนข้อมูลคิวของเซสชันสื่อด้วยเนื้อหาที่เกี่ยวข้อง เช่น หากผู้ใช้ขอให้เล่นอัลบั้ม แอปของคุณอาจเติมคิวด้วยรายการเพลงของอัลบั้ม นอกจากนี้ ให้พิจารณาใช้การรองรับผลการค้นหาที่เรียกดูได้เพื่อให้ผู้ใช้เลือกแทร็กอื่นที่ตรงกับคำค้นหาได้
นอกจากคำค้นหา "เล่น" แล้ว Android Auto และ Android Automotive OS ยังจดจำคำค้นหาด้วยเสียงเพื่อควบคุมการเล่น เช่น "หยุดเพลงชั่วคราว" และ "เพลงถัดไป" และจับคู่คำสั่งเหล่านี้กับโปรแกรมเรียกกลับของเซสชันสื่อที่เหมาะสม เช่น onPause()
และ onSkipToNext()
ดูตัวอย่างโดยละเอียดเกี่ยวกับวิธีใช้การดำเนินการเล่นที่เปิดใช้เสียงใน แอปได้ที่Google Assistant และแอปสื่อ
ใช้มาตรการป้องกันการรบกวน
เนื่องจากโทรศัพท์ของผู้ใช้จะเชื่อมต่อกับลำโพงของรถขณะใช้ Android Auto คุณจึงต้องใช้มาตรการป้องกันเพิ่มเติมเพื่อช่วยป้องกันไม่ให้ผู้ขับเสียสมาธิ
ปิดเสียงปลุกในรถ
แอปสื่อของ Android Auto ต้องไม่เริ่มเล่นเสียงผ่านลำโพงของรถ เว้นแต่ผู้ใช้จะเริ่มเล่น เช่น โดยการกดปุ่มเล่น แม้แต่การปลุกที่ผู้ใช้ตั้งเวลาจากแอปสื่อของคุณก็ต้องไม่เริ่ม เล่นเพลงผ่านลำโพงของรถ
หากต้องการปฏิบัติตามข้อกำหนดนี้ แอปของคุณ
สามารถใช้ CarConnection
เป็นสัญญาณก่อนเล่นเสียง แอปของคุณสามารถตรวจสอบว่าโทรศัพท์กำลัง
ฉายภาพไปยังหน้าจอรถยนต์หรือไม่โดยสังเกต LiveData
สำหรับประเภท
การเชื่อมต่อรถยนต์
และตรวจสอบว่าเท่ากับ
CONNECTION_TYPE_PROJECTION
หรือไม่
หากโทรศัพท์ของผู้ใช้กำลังฉายภาพ แอปสื่อที่รองรับการปลุกต้องทำอย่างใดอย่างหนึ่งต่อไปนี้
- ปิดใช้การปลุก
- เล่นการปลุกผ่าน
STREAM_ALARM
และแสดง UI บนหน้าจอโทรศัพท์เพื่อปิดใช้การปลุก
จัดการโฆษณาสื่อ
โดยค่าเริ่มต้น Android Auto จะแสดงการแจ้งเตือนเมื่อข้อมูลเมตาของสื่อเปลี่ยนแปลง
ในระหว่างเซสชันการเล่นเสียง เมื่อแอปสื่อเปลี่ยนจากการเล่นเพลง
เป็นการแสดงโฆษณา การแสดง
การแจ้งเตือนต่อผู้ใช้จะรบกวนการใช้งาน หากต้องการป้องกันไม่ให้ Android Auto แสดงการแจ้งเตือน
ในกรณีนี้ คุณต้องตั้งค่าคีย์ข้อมูลเมตาของสื่อ
METADATA_KEY_IS_ADVERTISEMENT
เป็น
METADATA_VALUE_ATTRIBUTE_PRESENT
ตามที่แสดงในข้อมูลโค้ดต่อไปนี้
Kotlin
import androidx.media.utils.MediaConstants override fun onPlayFromMediaId(mediaId: String, extras: Bundle?) { MediaMetadataCompat.Builder().apply { if (isAd(mediaId)) { putLong( MediaConstants.METADATA_KEY_IS_ADVERTISEMENT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) } // ...add any other properties you normally would. mediaSession.setMetadata(build()) } }
Java
import androidx.media.utils.MediaConstants; @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(); if (isAd(mediaId)) { builder.putLong( MediaConstants.METADATA_KEY_IS_ADVERTISEMENT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT); } // ...add any other properties you normally would. mediaSession.setMetadata(builder.build()); }
จัดการข้อผิดพลาดทั่วไป
เมื่อแอปพบข้อผิดพลาด ให้ตั้งค่าสถานะการเล่นเป็น STATE_ERROR
และระบุข้อความแสดงข้อผิดพลาดโดยใช้วิธี setErrorMessage()
ดูPlaybackStateCompat
สำหรับรายการรหัสข้อผิดพลาดที่คุณใช้ได้เมื่อตั้งค่าข้อความแสดงข้อผิดพลาด
ข้อความแสดงข้อผิดพลาดต้องแสดงต่อผู้ใช้และแปลเป็นภาษาท้องถิ่นตามภาษาปัจจุบันของผู้ใช้
จากนั้น Android Auto และ Android Automotive OS จะแสดงข้อความแสดงข้อผิดพลาดต่อผู้ใช้ได้
เช่น หากเนื้อหาไม่พร้อมให้บริการในภูมิภาคปัจจุบันของผู้ใช้ คุณสามารถ
ใช้รหัสข้อผิดพลาด ERROR_CODE_NOT_AVAILABLE_IN_REGION
เมื่อตั้งค่าข้อความแสดงข้อผิดพลาด
Kotlin
mediaSession.setPlaybackState( PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_ERROR) .setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_AVAILABLE_IN_REGION, getString(R.string.error_unsupported_region)) // ...and any other setters. .build())
Java
mediaSession.setPlaybackState( new PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_ERROR) .setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_AVAILABLE_IN_REGION, getString(R.string.error_unsupported_region)) // ...and any other setters. .build());
ดูข้อมูลเพิ่มเติมเกี่ยวกับสถานะข้อผิดพลาดได้ที่การใช้เซสชันสื่อ: สถานะ และข้อผิดพลาด
หากผู้ใช้ Android Auto ต้องเปิดแอปโทรศัพท์เพื่อแก้ไขข้อผิดพลาด ให้ข้อมูลดังกล่าวแก่ผู้ใช้ในข้อความ เช่น ข้อความแสดงข้อผิดพลาดอาจระบุว่า "ลงชื่อเข้าใช้ [ชื่อแอปของคุณ]" แทนที่จะเป็น "โปรดลงชื่อเข้าใช้"