Android Auto และ Android Automotive OS ช่วยให้คุณนำเนื้อหาแอปสื่อไปแสดงต่อผู้ใช้ในรถยนต์ แอปสื่อสำหรับรถยนต์ต้องมีบริการเรียกดูสื่อเพื่อให้ Android Auto และ Android Automotive OS หรือแอปอื่นที่มีเครื่องมือเรียกดูสื่อค้นพบและแสดงเนื้อหาของคุณได้
คู่มือนี้จะถือว่าคุณมีแอปสื่อที่เล่นเสียงในโทรศัพท์อยู่แล้ว และแอปสื่อของคุณเป็นไปตามสถาปัตยกรรมแอปสื่อของ Android
คู่มือนี้จะอธิบายคอมโพเนนต์ที่จำเป็นของ MediaBrowserService
และ MediaSession
ที่แอปของคุณต้องมีจึงจะทำงานใน Android Auto หรือ Android Automotive OS ได้ หลังจากสร้างโครงสร้างพื้นฐานของสื่อหลักเสร็จสมบูรณ์แล้ว คุณจะ
เพิ่มการรองรับสำหรับ Android Auto และเพิ่มการรองรับ
Android Automotive OS ไปยังแอปสื่อได้
ก่อนเริ่มต้น
- อ่านเอกสารประกอบของ Android Media API
- อ่านสร้างแอปสื่อเพื่อดูคำแนะนำเกี่ยวกับการออกแบบ
- ตรวจสอบคําศัพท์และแนวคิดสําคัญที่ระบุไว้ในส่วนนี้
คําศัพท์และแนวคิดสําคัญ
- บริการเบราว์เซอร์สื่อ
- บริการ Android ที่ใช้งานโดยแอปสื่อของคุณ และเป็นไปตาม
MediaBrowserServiceCompat
API แอปของคุณใช้บริการนี้เพื่อแสดงเนื้อหาของแอป - เบราว์เซอร์สื่อ
- API ที่แอปสื่อใช้เพื่อค้นหาบริการเบราว์เซอร์สื่อและแสดงเนื้อหา Android Auto และ Android Automotive OS ใช้โปรแกรมเรียกดูสื่อเพื่อค้นหาบริการโปรแกรมเรียกดูสื่อของแอป
- รายการสื่อ
เครื่องมือเลือกสื่อจะจัดระเบียบเนื้อหาเป็นลําดับชั้นของออบเจ็กต์
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 เชื่อมต่อกับแอปของคุณผ่านบริการเบราว์เซอร์สื่อเพื่อเรียกดูรายการสื่อ ประกาศบริการเบราว์เซอร์สื่อในไฟล์ 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>
ไอคอนระบุแหล่งที่มา
ไอคอนการระบุแหล่งที่มาจะใช้ในที่ที่เนื้อหาสื่อมีความสำคัญมากกว่า เช่น ในการ์ดสื่อ ลองนำไอคอนขนาดเล็กที่ใช้สำหรับการแจ้งเตือนมาใช้ซ้ำ ไอคอนนี้ต้องเป็นโมโนโครม คุณสามารถระบุไอคอนที่ใช้แสดงแอปของคุณได้โดยใช้การประกาศไฟล์ Manifest ต่อไปนี้
<application>
...
<meta-data
android:name="androidx.car.app.TintableAttributionIcon"
android:resource="@drawable/ic_status_icon" />
...
</application>
สร้างบริการเบราว์เซอร์สื่อ
คุณสร้างบริการเบราว์เซอร์สื่อโดยการขยายคลาส MediaBrowserServiceCompat
จากนั้นทั้ง Android Auto และ Android Automotive OS จะใช้บริการของคุณเพื่อทำสิ่งต่อไปนี้ได้
- เรียกดูลําดับชั้นเนื้อหาของแอปเพื่อแสดงเมนูต่อผู้ใช้
- รับโทเค็นสําหรับออบเจ็กต์
MediaSessionCompat
ของแอปเพื่อควบคุมการเล่นเสียง
คุณยังใช้บริการเบราว์เซอร์สื่อเพื่อให้ไคลเอ็นต์อื่นๆ เข้าถึงเนื้อหาสื่อจากแอปของคุณได้ โดยไคลเอ็นต์สื่อเหล่านี้อาจเป็นแอปอื่นๆ ในโทรศัพท์ของผู้ใช้ หรือไคลเอ็นต์อาจเป็นไคลเอ็นต์ระยะไกลอื่นๆ
เวิร์กโฟลว์บริการเบราว์เซอร์สื่อ
ส่วนนี้อธิบายวิธีที่ 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 จะเรียกใช้บริการเบราว์เซอร์สื่อของแอปเพื่อค้นหาเนื้อหาที่พร้อมใช้งาน คุณต้องติดตั้งใช้งาน 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 เสมอเมื่ออุปกรณ์ระบบเหล่านี้เรียกใช้เมธอด 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()
method แบบง่าย
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
จัดโครงสร้างเมนูรูท
Android Auto และ Android Automotive OS มีข้อจำกัดเฉพาะเกี่ยวกับโครงสร้างของเมนูรูท ระบบจะสื่อสารข้อมูลเหล่านี้ไปยัง MediaBrowserService
ผ่านคำแนะนำรูท ซึ่งสามารถอ่านผ่านอาร์กิวเมนต์ Bundle
ที่ส่งไปยัง onGetRoot()
การทำตามคำแนะนำเหล่านี้จะช่วยให้ระบบแสดงเนื้อหาระดับรูทในรูปแบบแท็บการนำทางได้อย่างเหมาะสม หากไม่ทำตามคำแนะนำเหล่านี้ ระบบอาจทิ้งเนื้อหารูทบางส่วนหรือทำให้ระบบค้นพบเนื้อหาได้ยากขึ้น ระบบจะส่งคำแนะนำ 2 รายการดังนี้
- การจํากัดจํานวนรายการย่อยของรูท:ในกรณีส่วนใหญ่ ตัวเลขนี้จะเป็น 4 ซึ่งหมายความว่าไม่สามารถแสดง มากกว่า 4 แท็บ
- Flag ที่รองรับในรายการย่อยของรูท:
ค่านี้ควรเป็น
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
เช่น หากปกติคุณแสดงรายการที่เล่นได้ระดับรูท คุณอาจต้องการฝังรายการนั้นไว้ใต้รายการที่เรียกดูได้ระดับรูทแทน เนื่องจากค่าของคำแนะนำเกี่ยวกับ Flag ที่รองรับ
นอกจากคำแนะนำเกี่ยวกับรูทแล้ว ยังมีหลักเกณฑ์เพิ่มเติมอีก 2 ข้อที่ควรทำเพื่อให้แท็บแสดงผลอย่างมีประสิทธิภาพสูงสุด
- ระบุไอคอนโมโนโครม (ควรเป็นสีขาว) สำหรับรายการในแท็บแต่ละรายการ
- ระบุป้ายกำกับสั้นๆ แต่สื่อความหมายสำหรับรายการแท็บแต่ละรายการ การทำให้ป้ายกำกับสั้นอยู่เสมอ จะช่วยลดโอกาสที่สตริงจะถูกตัดออก
แสดงอาร์ตเวิร์กสื่อ
ต้องส่งอาร์ตเวิร์กสำหรับรายการสื่อเป็น URI ในพื้นที่โดยใช้ ContentResolver.SCHEME_CONTENT
หรือ ContentResolver.SCHEME_ANDROID_RESOURCE
URI ในเครื่องนี้ต้องจับคู่กับบิตแมปหรือรูปภาพที่วาดได้แบบเวกเตอร์ในทรัพยากรของแอปพลิเคชัน สำหรับออบเจ็กต์ 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
สร้าง
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
: รายการที่เกี่ยวข้องจะแสดงเป็นรายการ "หมวดหมู่" รายการเหล่านี้เหมือนกับรายการในรายการธรรมดา ยกเว้นจะมีการใช้ระยะขอบรอบไอคอนของรายการ เนื่องจากไอคอนจะดูดีขึ้นเมื่อมีขนาดเล็ก ไอคอนต้องเป็นรูปภาพเวกเตอร์ที่ปรับสีได้ คาดว่าจะมีให้สำหรับรายการที่เรียกดูได้เท่านั้น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
ที่เรียกดูได้ ซึ่งจะลบล้างสไตล์เนื้อหาเริ่มต้นสำหรับทั้งตัว 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 ที่มีชื่อว่า "เพลง" ที่มีรายการสื่อ A
- กลุ่ม 2 ที่ชื่อ "อัลบั้ม" ที่มีรายการสื่อ B
- กลุ่มที่ 3 ชื่อ "เพลง" ซึ่งมีรายการสื่อ C และ D
- กลุ่มที่ 4 ชื่อ "อัลบั้ม" ซึ่งมีรายการสื่อ E
หากต้องการแสดงรายการเหล่านี้เป็น 2 กลุ่ม แอปของคุณต้องส่งรายการสื่อตามลําดับต่อไปนี้แทน
- รายการสื่อ ก. ที่มี
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")
- รายการสื่อ ข. ที่มี
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 จะอ่านข้อมูลเมตาสำหรับเซสชันสื่อและมองหาค่าคงที่บางอย่างเพื่อระบุตัวบ่งชี้ที่จะแสดง
คุณสามารถใช้ค่าคงที่ต่อไปนี้ได้ทั้งในข้อมูลเพิ่มเติมของคำอธิบาย 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
: ระบุจำนวนความคืบหน้าของเนื้อหาแบบยาวเป็นเลข 2 ระหว่าง 0.0 ถึง 1.0 โดยเป็นเลข 2 หลัก ข้อมูลเพิ่มเติมนี้ให้ข้อมูลเพิ่มเติมเกี่ยวกับสถานะ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());
แสดงผลการค้นหาที่เลือกดูได้
แอปสามารถแสดงผลการค้นหาตามบริบทที่แสดงต่อผู้ใช้เมื่อผู้ใช้เริ่มการค้นหา 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. }
การดำเนินการเรียกดูที่กำหนดเอง
การดำเนินการเรียกดูที่กำหนดเองช่วยให้คุณเพิ่มไอคอนและป้ายกำกับที่กำหนดเองลงในออบเจ็กต์ MediaItem
ของแอปในแอปสื่อของรถยนต์ และจัดการการโต้ตอบของผู้ใช้กับการดำเนินการเหล่านี้ ซึ่งจะช่วยให้คุณขยายฟังก์ชันการทำงานของแอปสื่อได้หลายวิธี เช่น เพิ่มการดำเนินการ "ดาวน์โหลด" "เพิ่มในคิว" "เปิดวิทยุ" "รายการโปรด" หรือ "นำออก"
หากมีการดำเนินการที่กำหนดเองมากกว่าที่ OEM อนุญาตให้แสดง ระบบจะแสดงเมนูรายการเพิ่มเติมต่อผู้ใช้
วิธีการทำงานของฟีเจอร์
การทำงานเรียกดูที่กำหนดเองแต่ละรายการจะถูกกำหนดด้วย:
- รหัสการดำเนินการ (ตัวระบุสตริงที่ไม่ซ้ำกัน)
- ป้ายกำกับการดำเนินการ (ข้อความที่แสดงต่อผู้ใช้)
- URI ของไอคอนการดำเนินการ (Vector Drawable ที่ปรับสีได้)
คุณกําหนดรายการการเรียกดูแบบกําหนดเองทั่วโลกเป็นส่วนหนึ่งของ BrowseRoot
แล้วแนบชุดย่อยของการดำเนินการเหล่านี้กับ MediaItem.
แต่ละรายการได้
เมื่อผู้ใช้โต้ตอบกับการเรียกดูที่กําหนดเอง แอปของคุณจะได้รับการเรียกกลับใน onCustomAction()
จากนั้นคุณจัดการการดำเนินการและอัปเดตรายการการดำเนินการสำหรับ MediaItem
ได้ หากจำเป็น ซึ่งมีประโยชน์สําหรับการดําเนินการที่เก็บสถานะ เช่น "รายการโปรด" และ "ดาวน์โหลด" สำหรับการดำเนินการที่ไม่จําเป็นต้องอัปเดต เช่น "เปิดวิทยุ" คุณไม่จําเป็นต้องอัปเดตรายการการดําเนินการ
นอกจากนี้ คุณยังแนบการเรียกดูที่กำหนดเองไปยังรูทโหนดการเรียกดูได้ด้วย การดำเนินการเหล่านี้จะแสดงในแถบเครื่องมือรองใต้แถบเครื่องมือหลัก
วิธีใช้การเรียกดูการกระทําที่กําหนดเอง
ขั้นตอนในการเพิ่มการเรียกให้ดำเนินการเรียกดูที่กำหนดเองลงในโปรเจ็กต์มีดังนี้
- ลบล้าง 2 วิธีในการติดตั้งใช้งาน
MediaBrowserServiceCompat
ดังนี้ - แยกวิเคราะห์ขีดจํากัดการดําเนินการเมื่อรันไทม์
- ใน
onGetRoot()
รับจำนวนการดำเนินการสูงสุดที่อนุญาตสำหรับแต่ละMediaItem
โดยใช้คีย์BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
ในBundle
rootHints
ขีดจำกัดเป็น 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
เพิ่มเติมBundle
ให้เพิ่มรายการการดำเนินการเป็นArraylist
Parcelable
โดยใช้คีย์BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
- ใน
- เพิ่มการดำเนินการลงในออบเจ็กต์
MediaItem
ดังนี้- คุณสามารถเพิ่มการดำเนินการไปยังออบเจ็กต์
MediaItem
แต่ละรายการได้โดยใส่รายการรหัสการดำเนินการในข้อมูลเพิ่มเติมของMediaDescriptionCompat
โดยใช้คีย์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
เพิ่มออบเจ็กต์การดำเนินการเรียกดูที่กำหนดเอง Bundle
ทั้งหมดลงใน ArrayList
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
รายการ
- แยกวิเคราะห์รหัสสื่อจาก
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 จะเรียกใช้เมธอดของออบเจ็กต์ Callback อย่างใดอย่างหนึ่ง
หากต้องการจัดการการเล่นเนื้อหา แอปของคุณต้องขยายMediaSessionCompat.Callback
คลาสแบบนามธรรม และนำเมธอดที่แอปรองรับไปใช้งาน
ใช้เมธอดการเรียกกลับทั้งหมดต่อไปนี้ที่เหมาะกับประเภทเนื้อหาที่แอปของคุณนำเสนอ
onPrepare()
- เรียกใช้เมื่อมีการเปลี่ยนแปลงแหล่งที่มาของสื่อ นอกจากนี้ Android Automotive OS ยังเรียกใช้เมธอดนี้ทันทีหลังจากการบูตด้วย แอปสื่อต้องใช้วิธีนี้
onPlay()
- เรียกใช้หากผู้ใช้เลือกเล่นโดยไม่เลือกรายการใดรายการหนึ่ง แอปของคุณต้องเล่นเนื้อหาเริ่มต้น หรือหากการเล่นหยุดชั่วคราวด้วย
onPause()
แอปของคุณจะต้องเล่นต่อหมายเหตุ: แอปไม่ควรเริ่มเล่นเพลงโดยอัตโนมัติเมื่อ Android Automotive OS หรือ Android Auto เชื่อมต่อกับบริการเบราว์เซอร์สื่อ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการตั้งค่าสถานะการเล่นเริ่มต้น
onPlayFromMediaId()
- เรียกใช้เมื่อผู้ใช้เลือกเล่นรายการที่เฉพาะเจาะจง โดยระบบจะส่งรหัสที่บริการเบราว์เซอร์สื่อกำหนดให้กับรายการสื่อในลําดับชั้นเนื้อหาให้กับเมธอด
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 จะแสดงปุ่มสำหรับการดำเนินการที่เปิดใช้แต่ละรายการ
และคิวการเล่น เมื่อคลิกปุ่มแล้ว ระบบจะเรียกใช้ Callback ที่เกี่ยวข้องจาก 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
ใช้ค่าคงที่เหล่านี้เป็นคีย์ในแพ็กเกจ และใช้บูลีน true
เป็นค่า
ตั้งค่า PlaybackState เริ่มต้น
เมื่อ Android Auto และ Android Automotive OS สื่อสารกับบริการเบราว์เซอร์สื่อของคุณ เซสชันสื่อจะสื่อสารสถานะการเล่นเนื้อหาโดยใช้ PlaybackStateCompat
แอปของคุณไม่ควรเริ่มเล่นเพลงโดยอัตโนมัติเมื่อ Android Automotive OS
หรือ Android Auto เชื่อมต่อกับบริการเบราว์เซอร์สื่อ แต่ต้องอาศัย Android Auto และ Android Automotive OS แทนเพื่อกลับมาเล่นต่อหรือเริ่มเล่นตามสถานะของรถยนต์หรือการดำเนินการของผู้ใช้
โดยให้ตั้งค่า PlaybackStateCompat
เริ่มต้นของเซสชันสื่อเป็น STATE_STOPPED
, STATE_PAUSED
, STATE_NONE
หรือ STATE_ERROR
เซสชันสื่อภายใน Android Auto และ Android Automotive OS จะใช้งานได้เฉพาะระหว่างขับรถเท่านั้น ผู้ใช้จึงเริ่มและหยุดเซสชันเหล่านี้บ่อยครั้ง ติดตามสถานะเซสชันก่อนหน้าของผู้ใช้เพื่อมอบประสบการณ์การใช้งานที่ราบรื่นระหว่างไดรฟ์ต่างๆ เพื่อที่ว่าเมื่อแอปสื่อได้รับคำขอให้กลับมาทำงานอีกครั้ง ผู้ใช้จะกลับมาเล่นต่อจากจุดที่ค้างไว้ได้โดยอัตโนมัติ ตัวอย่างเช่น รายการสื่อที่เล่นล่าสุด PlaybackStateCompat
และคิว
เพิ่มการดําเนินการการเล่นที่กําหนดเอง
คุณสามารถเพิ่มการดำเนินการเล่นที่กำหนดเองเพื่อแสดงการดำเนินการเพิ่มเติมที่แอปสื่อของคุณรองรับ หากมีพื้นที่เพียงพอ (และไม่ได้สงวนไว้) Android จะเพิ่มการดำเนินการที่กำหนดเองไปยังตัวควบคุมการขนส่ง ไม่เช่นนั้น การดำเนินการที่กำหนดเองจะแสดงในเมนูรายการเพิ่มเติม การดําเนินการแบบกําหนดเองจะแสดงตามลําดับที่เพิ่มลงใน PlaybackStateCompat
ใช้การดําเนินการแบบกําหนดเองเพื่อให้ลักษณะการทํางานแตกต่างจากการดําเนินการมาตรฐาน อย่าใช้เพื่อแทนที่หรือทำซ้ำการดำเนินการมาตรฐาน
คุณสามารถเพิ่มการดำเนินการที่กำหนดเองได้โดยใช้เมธอด addCustomAction()
ในคลาส PlaybackStateCompat.Builder
ข้อมูลโค้ดต่อไปนี้แสดงวิธีเพิ่มการดำเนินการ "เริ่มช่องวิทยุ" ที่กําหนดเอง
Kotlin
stateBuilder.addCustomAction( PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon ).run { setExtras(customActionExtras) build() } )
Java
stateBuilder.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon) .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
ไอคอนสําหรับการดําเนินการที่กำหนดเอง
การดำเนินการที่กำหนดเองแต่ละรายการที่คุณสร้างขึ้นต้องใช้ทรัพยากรไอคอน แอปในรถยนต์ทำงานได้กับหน้าจอหลายขนาดและหลายหน้าจอ ดังนั้นไอคอนที่คุณระบุต้องเป็นเวกเตอร์ที่ถอนออกได้ รูปภาพที่วาดได้แบบเวกเตอร์ช่วยให้คุณปรับขนาดชิ้นงานได้โดยไม่สูญเสียรายละเอียด รูปภาพที่วาดได้แบบเวกเตอร์ยังช่วยให้จัดแนวขอบและมุมตามขอบเขตพิกเซลที่มีความละเอียดน้อยได้ง่าย
หากการดำเนินการที่กำหนดเองมีสถานะ เช่น เปิดหรือปิดการตั้งค่าการเล่น ให้ระบุไอคอนที่แตกต่างกันสำหรับสถานะต่างๆ เพื่อให้ผู้ใช้เห็นการเปลี่ยนแปลงเมื่อเลือกการดำเนินการ
ระบุสไตล์ไอคอนอื่นสําหรับการดําเนินการที่ปิดใช้
เมื่อการดำเนินการที่กำหนดเองไม่พร้อมใช้งานสำหรับบริบทปัจจุบัน ให้เปลี่ยนไอคอนการดำเนินการที่กำหนดเองเป็นไอคอนอื่นที่แสดงว่าการดำเนินการถูกปิดใช้
ระบุรูปแบบเสียง
หากต้องการระบุว่าสื่อที่เล่นอยู่ใช้รูปแบบเสียงพิเศษ คุณสามารถระบุไอคอนที่จะแสดงผลในรถยนต์ที่รองรับฟีเจอร์นี้ คุณสามารถตั้งค่า
KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
และ
KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
ในแพ็กเกจพิเศษของรายการสื่อที่เล่นอยู่ในปัจจุบัน (ส่งไปยัง
MediaSession.setMetadata()
) โปรดตั้งค่าทั้ง 2 รายการของฟีเจอร์พิเศษเหล่านั้นเพื่อให้รองรับเลย์เอาต์ที่แตกต่างกัน
นอกจากนี้ คุณยังตั้งค่าข้อมูลเพิ่มเติม KEY_IMMERSIVE_AUDIO
เพื่อแจ้งให้ OEM รถยนต์ทราบว่านี่เป็นเสียงสมจริง และ 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 ยังจดจําคําค้นหาด้วยเสียงเพื่อควบคุมการเล่น เช่น "หยุดเพลงชั่วคราว" และ "เพลงถัดไป" และจับคู่คําสั่งเหล่านี้กับการเรียกกลับเซสชันสื่อที่เหมาะสม เช่น 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 จำเป็นต้องเปิดแอปโทรศัพท์เพื่อแก้ไขข้อผิดพลาด ให้แจ้งข้อมูลดังกล่าวให้ผู้ใช้ทราบในข้อความ เช่น ข้อความแสดงข้อผิดพลาดอาจระบุว่า "ลงชื่อเข้าใช้ [ชื่อแอปของคุณ]" แทนที่จะเป็น "โปรดลงชื่อเข้าใช้"