कार के लिए मीडिया ऐप्लिकेशन बनाएं

Android Auto और Android Automotive OS की मदद से, अपने मीडिया ऐप्लिकेशन का कॉन्टेंट, कार में इस्तेमाल करने वालों तक पहुंचाया जा सकता है. कारों के लिए बने मीडिया ऐप्लिकेशन में मीडिया ब्राउज़र की सेवा उपलब्ध होनी चाहिए, ताकि Android Auto और Android Automotive OS या मीडिया ब्राउज़र वाला कोई अन्य ऐप्लिकेशन आपका कॉन्टेंट ढूंढ सके और उसे दिखा सके.

इस गाइड में यह माना गया है कि आपके पास पहले से ही ऐसा मीडिया ऐप्लिकेशन है जो फ़ोन पर ऑडियो चलाता है. साथ ही, यह भी माना गया है कि आपका मीडिया ऐप्लिकेशन, Android के मीडिया ऐप्लिकेशन के आर्किटेक्चर के मुताबिक है.

इस गाइड में, MediaBrowserService और MediaSession के उन ज़रूरी कॉम्पोनेंट के बारे में बताया गया है जिनकी ज़रूरत आपके ऐप्लिकेशन को Android Auto या Android Automotive OS पर काम करने के लिए होती है. मीडिया के बुनियादी इंफ़्रास्ट्रक्चर को पूरा करने के बाद, अपने मीडिया ऐप्लिकेशन में Android Auto के लिए सहायता जोड़ी जा सकती है. साथ ही, Android Automotive OS के लिए सहायता जोड़ी जा सकती है.

शुरू करने से पहले

  1. Android मीडिया एपीआई से जुड़ा दस्तावेज़ देखें.
  2. डिज़ाइन से जुड़े दिशा-निर्देशों के लिए, मीडिया ऐप्लिकेशन बनाना लेख पढ़ें.
  3. इस सेक्शन में दिए गए मुख्य शब्दों और कॉन्सेप्ट को देखें.

मुख्य शब्द और कॉन्सेप्ट

मीडिया ब्राउज़र सेवा
आपके मीडिया ऐप्लिकेशन की ओर से लागू की गई Android सेवा, जो MediaBrowserServiceCompat एपीआई के मुताबिक हो. आपका ऐप्लिकेशन, अपने कॉन्टेंट को दिखाने के लिए इस सेवा का इस्तेमाल करता है.
मीडिया ब्राउज़र
मीडिया ब्राउज़र सेवाओं को खोजने और उनका कॉन्टेंट दिखाने के लिए, मीडिया ऐप्लिकेशन का इस्तेमाल किया जाने वाला एपीआई. Android Auto और Android Automotive OS, मीडिया ब्राउज़र का इस्तेमाल करके आपके ऐप्लिकेशन की मीडिया ब्राउज़र सेवा ढूंढते हैं.
मीडिया आइटम

मीडिया ब्राउज़र, अपने कॉन्टेंट को MediaItem ऑब्जेक्ट के ट्री में व्यवस्थित करता है. किसी मीडिया आइटम में, इनमें से कोई एक या दोनों फ़्लैग हो सकते हैं:

  • FLAG_PLAYABLE: इससे पता चलता है कि आइटम, कॉन्टेंट ट्री में लीफ है. यह आइटम, किसी एक साउंड स्ट्रीम को दिखाता है. जैसे, किसी एल्बम का गाना, ऑडियो बुक का चैप्टर या पॉडकास्ट का एपिसोड.
  • FLAG_BROWSABLE: इससे पता चलता है कि आइटम, कॉन्टेंट ट्री का एक नोड है और उसमें चाइल्ड आइटम हैं. उदाहरण के लिए, आइटम किसी एल्बम को दिखाता है और उसके चाइल्ड एलिमेंट, एल्बम में मौजूद गाने होते हैं.

ब्राउज़ किया जा सकने वाला और चलाया जा सकने वाला मीडिया आइटम, प्लेलिस्ट की तरह काम करता है. किसी आइटम के सभी चाइल्ड आइटम चलाने के लिए, उस आइटम को चुना जा सकता है या उसके चाइल्ड आइटम ब्राउज़ किए जा सकते हैं.

वाहन के हिसाब से

Android Automotive OS ऐप्लिकेशन के लिए ऐसी गतिविधि जो Android Automotive OS के डिज़ाइन से जुड़े दिशा-निर्देशों का पालन करती हो. इन गतिविधियों के लिए इंटरफ़ेस, Android Automotive OS नहीं बनाता. इसलिए, आपको यह पक्का करना होगा कि आपका ऐप्लिकेशन डिज़ाइन से जुड़े दिशा-निर्देशों का पालन करता हो. आम तौर पर, इसमें टैप किए जाने वाले हिस्से और फ़ॉन्ट के साइज़ को बड़ा किया जाता है. साथ ही, दिन और रात मोड के साथ-साथ ज़्यादा कंट्रास्ट रेशियो की सुविधा भी दी जाती है.

वाहन के लिए ऑप्टिमाइज़ किए गए यूज़र इंटरफ़ेस सिर्फ़ तब दिखाए जा सकते हैं, जब कार के उपयोगकर्ता अनुभव से जुड़ी पाबंदियां (CUXRs) लागू न हों. ऐसा इसलिए है, क्योंकि इन इंटरफ़ेस के लिए उपयोगकर्ता को ज़्यादा ध्यान देने या इंटरैक्ट करने की ज़रूरत पड़ सकती है. कार के रुकने या पार्क होने पर, सीयूएक्सआर लागू नहीं होते. हालांकि, कार के चलने पर ये हमेशा लागू रहते हैं.

आपको Android Auto के लिए गतिविधियां डिज़ाइन करने की ज़रूरत नहीं है, क्योंकि Android Auto आपकी मीडिया ब्राउज़र सेवा की जानकारी का इस्तेमाल करके, गाड़ी के हिसाब से ऑप्टिमाइज़ किया गया इंटरफ़ेस बनाता है.

अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइलों को कॉन्फ़िगर करना

मीडिया ब्राउज़र सेवा बनाने से पहले, आपको अपने ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइलों को कॉन्फ़िगर करना होगा.

मीडिया ब्राउज़र सेवा का एलान करना

मीडिया आइटम ब्राउज़ करने के लिए, Android Auto और Android Automotive OS, मीडिया ब्राउज़र सेवा की मदद से आपके ऐप्लिकेशन से कनेक्ट होते हैं. अपने मेनिफ़ेस्ट में मीडिया ब्राउज़र सेवा का एलान करें, ताकि Android Auto और Android Automotive OS, सेवा को ढूंढ सकें और आपके ऐप्लिकेशन से कनेक्ट कर सकें.

यहां दिया गया कोड स्निपेट, मेनिफ़ेस्ट में मीडिया ब्राउज़र सेवा का एलान करने का तरीका दिखाता है. इस कोड को अपने Android Automotive OS मॉड्यूल की मेनिफ़ेस्ट फ़ाइल और अपने फ़ोन ऐप्लिकेशन की मेनिफ़ेस्ट फ़ाइल में शामिल करें.

<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, सिस्टम यूज़र इंटरफ़ेस में आपके ऐप्लिकेशन को दिखाने के लिए कर सकते हैं. दो तरह के आइकॉन ज़रूरी हैं:

  • लॉन्चर आइकॉन
  • एट्रिब्यूशन आइकॉन

लॉन्चर आइकॉन

लॉन्चर आइकॉन, सिस्टम यूज़र इंटरफ़ेस (यूआई) में आपके ऐप्लिकेशन को दिखाता है. जैसे, लॉन्चर और आइकॉन की ट्रे में. आपके पास यह बताने का विकल्प होता है कि आपको अपने मोबाइल ऐप्लिकेशन के आइकॉन का इस्तेमाल, कार के मीडिया ऐप्लिकेशन को दिखाने के लिए करना है. इसके लिए, मेनिफ़ेस्ट में यह एलान करें:

<application
    ...
    android:icon="@mipmap/ic_launcher"
    ...
/>

अपने मोबाइल ऐप्लिकेशन के आइकॉन के बजाय कोई दूसरा आइकॉन इस्तेमाल करने के लिए, मेनिफ़ेस्ट में अपनी मीडिया ब्राउज़र सेवा के <service> एलिमेंट पर android:icon प्रॉपर्टी सेट करें:

<application>
    ...
    <service
        ...
        android:icon="@mipmap/auto_launcher"
        ...
    />
</application>

एट्रिब्यूशन आइकॉन

पहली इमेज. मीडिया कार्ड पर एट्रिब्यूशन आइकॉन.

एट्रिब्यूशन आइकॉन का इस्तेमाल उन जगहों पर किया जाता है जहां मीडिया कॉन्टेंट को प्राथमिकता दी जाती है. जैसे, मीडिया कार्ड पर. सूचनाओं के लिए इस्तेमाल किए गए छोटे आइकॉन का फिर से इस्तेमाल करें. यह आइकॉन मोनोक्रोम होना चाहिए. आपके पास अपने ऐप्लिकेशन को दिखाने के लिए, कोई आइकॉन तय करने का विकल्प होता है. इसके लिए, मेनिफ़ेस्ट में यह एलान करें:

<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, आपकी मीडिया ब्राउज़र सेवा के साथ कैसे इंटरैक्ट करते हैं.

  1. उपयोगकर्ता, Android Automotive OS या Android Auto पर आपका ऐप्लिकेशन लॉन्च करता है.
  2. Android Automotive OS या Android Auto, onCreate() तरीके का इस्तेमाल करके, आपके ऐप्लिकेशन की मीडिया ब्राउज़र सेवा से संपर्क करता है. onCreate() तरीका लागू करने के लिए, आपको MediaSessionCompat ऑब्जेक्ट और उसका कॉलबैक ऑब्जेक्ट बनाना होगा और रजिस्टर करना होगा.
  3. Android Automotive OS या Android Auto, कॉन्टेंट की हैरारकी में रूट मीडिया आइटम पाने के लिए, आपकी सेवा के onGetRoot() तरीके को कॉल करता है. रूट मीडिया आइटम नहीं दिखाया जाता. इसके बजाय, इसका इस्तेमाल आपके ऐप्लिकेशन से ज़्यादा कॉन्टेंट पाने के लिए किया जाता है.
  4. Android Automotive OS या Android Auto, रूट मीडिया आइटम के चाइल्ड आइटम पाने के लिए, आपकी सेवा के onLoadChildren() तरीक़े को कॉल करता है. Android Automotive OS और Android Auto, इन मीडिया आइटम को कॉन्टेंट आइटम के टॉप लेवल के तौर पर दिखाते हैं. इस लेवल पर सिस्टम की क्या उम्मीद है, इस बारे में ज़्यादा जानकारी के लिए, इस पेज पर रूट मेन्यू को व्यवस्थित करना लेख पढ़ें.
  5. अगर उपयोगकर्ता ने ब्राउज़ किया जा सकने वाला कोई मीडिया आइटम चुना है, तो चुने गए मेन्यू आइटम के चाइल्ड आइटम को वापस पाने के लिए, आपकी सेवा के onLoadChildren() तरीके को फिर से कॉल किया जाता है.
  6. अगर उपयोगकर्ता कोई ऐसा मीडिया आइटम चुनता है जिसे चलाया जा सकता है, तो Android Automotive OS या Android Auto, उस कार्रवाई को करने के लिए मीडिया सेशन कॉलबैक के सही तरीके को कॉल करता है.
  7. अगर आपके ऐप्लिकेशन में यह सुविधा काम करती है, तो उपयोगकर्ता आपका कॉन्टेंट भी खोज सकता है. इस मामले में, Android Automotive OS या Android Auto, आपकी सेवा के onSearch() तरीके को कॉल करता है.

कॉन्टेंट की हैरारकी बनाना

Android Auto और Android Automotive OS, आपके ऐप्लिकेशन की मीडिया ब्राउज़र सेवा को कॉल करके यह पता लगाते हैं कि कौनसा कॉन्टेंट उपलब्ध है. इस सुविधा का इस्तेमाल करने के लिए, आपको अपनी मीडिया ब्राउज़र सेवा में दो तरीके लागू करने होंगे: 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);
}

इस तरीके के बारे में ज़्यादा जानकारी के लिए, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में onGetRoot() तरीका देखें.

onGetRoot() के लिए पैकेज की पुष्टि करने की सुविधा जोड़ना

जब आपकी सेवा के onGetRoot() तरीके से कॉल किया जाता है, तो कॉल करने वाला पैकेज आपकी सेवा को पहचान से जुड़ी जानकारी भेजता है. आपकी सेवा, इस जानकारी का इस्तेमाल यह तय करने के लिए कर सकती है कि वह पैकेज आपका कॉन्टेंट ऐक्सेस कर सकता है या नहीं. उदाहरण के लिए, clientPackageName की तुलना अनुमति वाली सूची से करके और पैकेज के APK पर हस्ताक्षर करने के लिए इस्तेमाल किए गए सर्टिफ़िकेट की पुष्टि करके, अपने ऐप्लिकेशन के कॉन्टेंट को अनुमति वाले पैकेज की सूची तक सीमित किया जा सकता है. अगर पैकेज की पुष्टि नहीं हो पाती है, तो अपने कॉन्टेंट का ऐक्सेस देने से मना करने के लिए, null को वापस भेजें.

Android Auto और Android Automotive OS जैसे सिस्टम ऐप्लिकेशन को आपके कॉन्टेंट का ऐक्सेस देने के लिए, जब ये सिस्टम ऐप्लिकेशन onGetRoot() विधि को कॉल करते हैं, तो आपकी सेवा को हमेशा कोई ऐसा BrowserRoot दिखाना चाहिए जो शून्य न हो. कार के मॉडल और मैन्युफ़ैक्चरर के हिसाब से, 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
}

यह कोड स्निपेट, GitHub पर मौजूद Universal Android Music Player के सैंपल ऐप्लिकेशन में मौजूद PackageValidator क्लास का एक हिस्सा है. अपनी सेवा के 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);
}

इस तरीके का पूरा उदाहरण देखने के लिए, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में onLoadChildren() तरीका देखें.

रूट मेन्यू को व्यवस्थित करना

दूसरी इमेज. रूट कॉन्टेंट, नेविगेशन टैब के तौर पर दिखता है.

Android Auto और Android Automotive OS में, रूट मेन्यू के स्ट्रक्चर से जुड़ी कुछ खास पाबंदियां होती हैं. इनकी जानकारी, रूट हिंट के ज़रिए MediaBrowserService को दी जाती है. इन्हें onGetRoot() में पास किए गए Bundle आर्ग्युमेंट के ज़रिए पढ़ा जा सकता है. इन सुझावों का पालन करने से, सिस्टम रूट कॉन्टेंट को नेविगेशन टैब के तौर पर बेहतर तरीके से दिखा पाता है. इन सुझावों का पालन न करने पर, हो सकता है कि सिस्टम कुछ रूट कॉन्टेंट को हटा दे या उसे खोजने में ज़्यादा मुश्किल बना दे. दो हिंट भेजे जाते हैं:

काम के रूट हिंट पढ़ने के लिए, इस कोड का इस्तेमाल करें:

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...
}

इन हिंट की वैल्यू के आधार पर, कॉन्टेंट के क्रम के स्ट्रक्चर के लिए लॉजिक को ब्रैंच किया जा सकता है. ऐसा तब ज़रूरी होता है, जब Android Auto और Android Automotive OS के बाहर के MediaBrowser इंटिग्रेशन के बीच आपकी हैरारकी अलग-अलग हो. उदाहरण के लिए, अगर आम तौर पर कोई चलाया जा सकने वाला रूट आइटम दिखाया जाता है, तो हो सकता है कि आप उसे ब्राउज़ किए जा सकने वाले रूट आइटम के नीचे नेस्ट करना चाहें. ऐसा, इस्तेमाल किए जा सकने वाले फ़्लैग के संकेत की वैल्यू की वजह से किया जा सकता है.

रूट हिंट के अलावा, टैब को बेहतर तरीके से रेंडर करने के लिए, कुछ और दिशा-निर्देशों का पालन करना ज़रूरी है:

  • हर टैब आइटम के लिए मोनोक्रोम, खास तौर पर सफ़ेद रंग के आइकॉन दें.
  • हर टैब आइटम के लिए, छोटे लेकिन काम के लेबल दें. लेबल छोटे रखने से, स्ट्रिंग के काटे जाने की संभावना कम हो जाती है.

मीडिया आर्टवर्क दिखाना

मीडिया आइटम के आर्टवर्क को लोकल यूआरआई के तौर पर पास किया जाना चाहिए. इसके लिए, ContentResolver.SCHEME_CONTENT या ContentResolver.SCHEME_ANDROID_RESOURCE का इस्तेमाल करें. यह लोकल यूआरआई, ऐप्लिकेशन के संसाधनों में मौजूद बिटमैप या वेक्टर ड्रॉबल में रिज़ॉल्व होना चाहिए. कॉन्टेंट के क्रम में आइटम दिखाने वाले MediaDescriptionCompat ऑब्जेक्ट के लिए, यूआरआई को setIconUri() के ज़रिए पास करें. फ़िलहाल चल रहे आइटम को दिखाने वाले MediaMetadataCompat ऑब्जेक्ट के लिए, यूआरआई को putString() के ज़रिए पास करें. इसके लिए, इनमें से किसी भी बटन का इस्तेमाल करें:

यहां बताया गया है कि वेब यूआरआई से आर्टवर्क को कैसे डाउनलोड करें और उसे लोकल यूआरआई के ज़रिए कैसे दिखाएं. ज़्यादा जानकारी के लिए, Universal Android Music Player के सैंपल ऐप्लिकेशन में, openFile() और उससे जुड़े तरीकों को लागू करने का उदाहरण देखें.

  1. वेब यूआरआई से जुड़ा content:// यूआरआई बनाएं. मीडिया ब्राउज़र सेवा और मीडिया सेशन, इस कॉन्टेंट यूआरआई को Android Auto और Android Automotive OS को पास करते हैं.

    Kotlin

    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();
    }
    
  2. ContentProvider.openFile() को लागू करते समय, देखें कि उससे जुड़े यूआरआई के लिए कोई फ़ाइल मौजूद है या नहीं. अगर ऐसा नहीं है, तो इमेज फ़ाइल को डाउनलोड करके कैश मेमोरी में सेव करें. यहां दिया गया कोड स्निपेट, Glide का इस्तेमाल करता है.

    Kotlin

    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);
    }
    

कॉन्टेंट उपलब्ध कराने वाली कंपनियों के बारे में ज़्यादा जानने के लिए, कॉन्टेंट उपलब्ध कराने वाली कंपनी बनाना लेख पढ़ें.

कॉन्टेंट स्टाइल लागू करना

ब्राउज़ किए जा सकने वाले या चलाए जा सकने वाले आइटम का इस्तेमाल करके, कॉन्टेंट की हैरारकी बनाने के बाद, कॉन्टेंट स्टाइल लागू किए जा सकते हैं. इन स्टाइल से यह तय होता है कि कार में वे आइटम कैसे दिखेंगे.

इन कॉन्टेंट स्टाइल का इस्तेमाल किया जा सकता है:

आइटम की सूची

इस कॉन्टेंट स्टाइल में, इमेज के बजाय टाइटल और मेटाडेटा को प्राथमिकता दी जाती है.

ग्रिड आइटम

इस कॉन्टेंट स्टाइल में, टाइटल और मेटाडेटा के बजाय इमेज को प्राथमिकता दी जाती है.

कॉन्टेंट के लिए डिफ़ॉल्ट स्टाइल सेट करना

मीडिया आइटम दिखाने के तरीके के लिए, ग्लोबल डिफ़ॉल्ट सेट किए जा सकते हैं. इसके लिए, अपनी सेवा के onGetRoot() तरीके के BrowserRoot एक्सट्रा बंडल में कुछ कॉन्स्टेंट शामिल करें. 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: इसके हिसाब से, आइटम "कैटगरी" ग्रिड आइटम के तौर पर दिखाए जाते हैं. ये सामान्य ग्रिड आइटम की तरह ही होते हैं. हालांकि, इन आइटम के आइकॉन के चारों ओर मार्जिन लागू होते हैं, क्योंकि छोटे आइकॉन बेहतर दिखते हैं. आइकॉन, रंग में बदले जा सकने वाले वेक्टर ड्रॉबल होने चाहिए. यह संकेत, सिर्फ़ उन आइटम के लिए दिया जाएगा जिन्हें ब्राउज़ किया जा सकता है.

यहां दिए गए कोड स्निपेट में, ब्राउज़ किए जा सकने वाले आइटम के लिए ग्रिड और चलाए जा सकने वाले आइटम के लिए सूचियों में डिफ़ॉल्ट कॉन्टेंट स्टाइल सेट करने का तरीका बताया गया है:

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 के साथ मैपिंग शामिल होनी चाहिए. इस स्ट्रिंग को स्थानीय भाषा में अनुवाद करें. इसका इस्तेमाल, ग्रुप के टाइटल के तौर पर किया जाता है.

यहां दिया गया कोड स्निपेट, "Songs" के सबग्रुप के शीर्षक के साथ MediaItem बनाने का तरीका दिखाता है:

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*/);
}

आपके ऐप्लिकेशन में वे सभी मीडिया आइटम होने चाहिए जिन्हें आपको एक साथ ग्रुप करना है. उदाहरण के लिए, मान लें कि आपको मीडिया आइटम के दो ग्रुप, "गाने" और "एल्बम" को उसी क्रम में दिखाना है. साथ ही, आपका ऐप्लिकेशन पांच मीडिया आइटम को इस क्रम में पास करता है:

  1. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") वाला मीडिया आइटम A
  2. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") वाला मीडिया आइटम B
  3. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") वाला मीडिया आइटम C
  4. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") वाला मीडिया आइटम D
  5. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") वाला मीडिया आइटम E

"गाने" ग्रुप और "एल्बम" ग्रुप के मीडिया आइटम को एक साथ एक ही ब्लॉक में नहीं रखा जाता. इसलिए, Android Auto और Android Automotive OS इन चार ग्रुप के तौर पर इसका इस्तेमाल करते हैं:

  • "गाने" नाम का पहला ग्रुप, जिसमें मीडिया आइटम A शामिल है
  • दूसरा ग्रुप "एल्बम" है, जिसमें मीडिया आइटम B शामिल है
  • तीसरा ग्रुप "गाने" है, जिसमें मीडिया आइटम C और D शामिल हैं
  • "एल्बम" नाम का चौथा ग्रुप, जिसमें मीडिया आइटम E शामिल है

इन आइटम को दो ग्रुप में दिखाने के लिए, आपके ऐप्लिकेशन को मीडिया आइटम को इस क्रम में पास करना होगा:

  1. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") वाला मीडिया आइटम A
  2. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") वाला मीडिया आइटम C
  3. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") वाला मीडिया आइटम D
  4. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") वाला मीडिया आइटम B
  5. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") वाला मीडिया आइटम E

मेटाडेटा के अन्य इंडिकेटर दिखाना

मीडिया ब्राउज़र ट्री और वीडियो चलाने के दौरान, कॉन्टेंट के बारे में एक नज़र में जानकारी देने के लिए, मेटाडेटा के अन्य इंडिकेटर शामिल किए जा सकते हैं. ब्राउज़ ट्री में, 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_KEY_COMPLETION_PERCENTAGE: इससे पता चलता है कि लंबी अवधि के वीडियो को कितने प्रतिशत तक देखा गया है. यह वैल्यू 0.0 से 1.0 के बीच होती है. इस अतिरिक्त एट्रिब्यूट से, PARTIALLY_PLAYING की स्थिति के बारे में ज़्यादा जानकारी मिलती है. इससे Android Auto या Android Automotive OS, प्रोग्रेस बार जैसे ज़्यादा काम के प्रोग्रेस इंडिकेटर दिखाता है. अगर इस एक्सट्रा का इस्तेमाल किया जाता है, तो इस गाइड में कॉन्टेंट चलने के दौरान, ब्राउज़ व्यू में प्रोग्रेस बार को अपडेट करने सेक्शन देखें. इससे, शुरुआती इंप्रेशन के बाद इस इंडिकेटर को अप-टू-डेट रखने का तरीका जानने में मदद मिलेगी.

जब उपयोगकर्ता मीडिया ब्राउज़ ट्री को ब्राउज़ कर रहा हो, तब दिखने वाले इंडिकेटर दिखाने के लिए, एक या उससे ज़्यादा कॉन्स्टेंट वाला एक एक्स्ट्रा बंडल बनाएं और उस बंडल को 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 */);

फ़िलहाल चल रहे मीडिया आइटम के लिए इंडिकेटर दिखाने के लिए, अपने mediaSession के MediaMetadataCompat में METADATA_KEY_IS_EXPLICIT या EXTRA_DOWNLOAD_STATUS के लिए Long वैल्यू सबमिट की जा सकती हैं. वीडियो चलाने के दौरान दिखने वाले व्यू पर, 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 को MediaItem को भेजी गई स्ट्रिंग वैल्यू के बराबर स्ट्रिंग वैल्यू के साथ METADATA_KEY_MEDIA_ID भेजना चाहिए.
  • 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 OS, खोज क्वेरी इंटरफ़ेस या ऐसे फ़ंक्शन के ज़रिए ये नतीजे दिखाते हैं जो सेशन में पहले की गई क्वेरी पर आधारित होते हैं. ज़्यादा जानने के लिए, इस गाइड में बोलकर निर्देश देने की सुविधा के लिए सहायता सेक्शन देखें.

ब्राउज़ किए जा सकने वाले खोज नतीजे दिखाने के लिए, अपनी सेवा के onGetRoot() तरीके के एक्स्ट्रा बंडल में, बोलियन true पर मैप करते हुए, कॉन्स्टेंट बटन BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED को शामिल करें.

नीचे दिए गए कोड स्निपेट में, 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 OS, उपयोगकर्ता के खोज के लिए इस्तेमाल हुए शब्दों को इस तरीके पर भेजते हैं.

अपनी सेवा के 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 की अनुमति से ज़्यादा कस्टम कार्रवाइयां हैं, तो उपयोगकर्ता को एक 'ओवरफ़्लो मेन्यू' दिखेगा.

ये कैसे काम करते हैं?

हर कस्टम ब्राउज़ ऐक्शन को इनके साथ तय किया जाता है:

  • ऐक्शन आईडी (यूनीक स्ट्रिंग आइडेंटिफ़ायर)
  • कार्रवाई का लेबल (उपयोगकर्ता को दिखाया जाने वाला टेक्स्ट)
  • ऐक्शन आइकॉन का यूआरएल (ऐसा वेक्टर ड्रॉबल जिसे रंगा जा सकता है)

आपने अपने BrowseRoot के हिस्से के तौर पर, कस्टम ब्राउज़ ऐक्शन की सूची को ग्लोबल तौर पर तय किया है. इसके बाद, इन कार्रवाइयों के सबसेट को अलग-अलग MediaItem.

जब कोई उपयोगकर्ता कस्टम ब्राउज़ ऐक्शन से इंटरैक्ट करता है, तो आपके ऐप्लिकेशन को onCustomAction() में कॉलबैक मिलता है. इसके बाद, कार्रवाई को मैनेज किया जा सकता है. साथ ही, ज़रूरत पड़ने पर MediaItem के लिए कार्रवाइयों की सूची को अपडेट किया जा सकता है. यह "पसंदीदा" और "डाउनलोड करें" जैसी स्टेटफ़ुल कार्रवाइयों के लिए काम आता है. "रेडियो चलाएं" जैसी उन कार्रवाइयों के लिए, आपको कार्रवाइयों की सूची अपडेट करने की ज़रूरत नहीं है जिन्हें अपडेट करने की ज़रूरत नहीं है.

ब्राउज़ नोड रूट में कस्टम ब्राउज़ ऐक्शन.

आठवीं इमेज. कस्टम ब्राउज़ ऐक्शन टूलबार

ब्राउज़ नोड रूट में कस्टम ब्राउज़ ऐक्शन भी अटैच किए जा सकते हैं. ये कार्रवाइयां, मुख्य टूलबार के नीचे मौजूद सेकंडरी टूलबार में दिखेंगी.

कस्टम ब्राउज़ ऐक्शन लागू करने का तरीका

अपने प्रोजेक्ट में कस्टम ब्राउज़ ऐक्शन जोड़ने के लिए, यह तरीका अपनाएं:

  1. MediaBrowserServiceCompat को लागू करने के लिए, इन दो तरीकों को बदलें:
  2. रनटाइम के दौरान कार्रवाई की सीमाओं को पार्स करें:
    • onGetRoot() में, rootHints Bundle में मौजूद बटन BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT का इस्तेमाल करके, हर MediaItem के लिए ज़्यादा से ज़्यादा कार्रवाइयों की संख्या देखें. 0 सेट करने का मतलब है कि सिस्टम पर यह सुविधा काम नहीं करती.
  3. कस्टम ब्राउज़ ऐक्शन की ग्लोबल सूची बनाएं:
    • हर कार्रवाई के लिए, इन कुंजियों के साथ एक Bundle ऑब्जेक्ट बनाएं: * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID: कार्रवाई का आईडी * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL: कार्रवाई का लेबल * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI: कार्रवाई के आइकॉन का यूआरआई * सभी कार्रवाई Bundle ऑब्जेक्ट को एक सूची में जोड़ें.
  4. ग्लोबल सूची को अपने BrowseRoot में जोड़ें:
    • BrowseRoot एक्सट्रा Bundle में, BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST बटन का इस्तेमाल करके, कार्रवाइयों की सूची को Parcelable Arraylist के तौर पर जोड़ें.
  5. अपने MediaItem ऑब्जेक्ट में कार्रवाइयां जोड़ें:
    • MediaItem ऑब्जेक्ट में कार्रवाइयां जोड़ी जा सकती हैं. इसके लिए, MediaDescriptionCompat एक्सट्रा में ऐक्शन आईडी की सूची शामिल करें. इसके लिए, बटन DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST का इस्तेमाल करें. यह सूची, BrowseRoot में तय की गई कार्रवाइयों की ग्लोबल सूची का सबसेट होनी चाहिए.
  6. कार्रवाइयों को मैनेज करें और प्रोग्रेस या नतीजे दिखाएं:
    • onCustomAction में, कार्रवाई आईडी और ज़रूरी अन्य डेटा के आधार पर कार्रवाई को मैनेज करें. EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID कीवर्ड का इस्तेमाल करके, एक्सट्रा से उस MediaItem का आईडी पाया जा सकता है जिसने ऐक्शन को ट्रिगर किया है.
    • प्रोग्रेस या नतीजे के बंडल में EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM बटन को शामिल करके, MediaItem के लिए कार्रवाइयों की सूची अपडेट की जा सकती है.

कस्टम ब्राउज़ ऐक्शन का इस्तेमाल शुरू करने के लिए, 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>")
    
  • ऐक्शन आइकॉन का यूआरआई
    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 से mediaId पार्स करें:
    @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 को अपडेट किया जा सकता है, ताकि कार्रवाई की नई स्थिति दिखे. इससे, उपयोगकर्ता को उसकी कार्रवाई की प्रोग्रेस और नतीजे के बारे में रीयल-टाइम में फ़ीडबैक दिया जा सकता है.

उदाहरण: डाउनलोड ऐक्शन

यहां एक उदाहरण दिया गया है, जिसमें तीन स्थितियों वाली डाउनलोड कार्रवाई लागू करने के लिए, इस सुविधा का इस्तेमाल करने का तरीका बताया गया है:

  1. डाउनलोड: यह कार्रवाई की शुरुआती स्थिति है. जब उपयोगकर्ता यह कार्रवाई चुनता है, तो इसे "डाउनलोड हो रहा है" से बदला जा सकता है. साथ ही, यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए sendProgressUpdate को कॉल किया जा सकता है.
  2. डाउनलोड हो रहा है: इस स्टेटस से पता चलता है कि डाउनलोड जारी है. उपयोगकर्ता को प्रगति बार या कोई अन्य इंडिकेटर दिखाने के लिए, इस स्थिति का इस्तेमाल किया जा सकता है.
  3. डाउनलोड हो गया: इस स्टेटस से पता चलता है कि डाउनलोड पूरा हो गया है. डाउनलोड होने के बाद, "डाउनलोड हो रहा है" को "डाउनलोड हो गया" से बदला जा सकता है. साथ ही, EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM बटन का इस्तेमाल करके sendResult को कॉल किया जा सकता है, ताकि यह पता चल सके कि आइटम को रीफ़्रेश किया जाना चाहिए. इसके अलावा, उपयोगकर्ता को सफलता का मैसेज दिखाने के लिए, EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE बटन का इस्तेमाल किया जा सकता है.

इस तरीके से, उपयोगकर्ता को डाउनलोड की प्रोसेस और उसकी मौजूदा स्थिति के बारे में साफ़ तौर पर जानकारी दी जा सकती है. आइकॉन की मदद से ज़्यादा जानकारी भी जोड़ी जा सकती है, ताकि डाउनलोड की स्थिति 25%, 50%, और 75% दिख सके.

उदाहरण: पसंदीदा ऐक्शन

एक और उदाहरण, दो स्थितियों वाली पसंदीदा कार्रवाई है:

  1. पसंदीदा: यह कार्रवाई उन आइटम के लिए दिखती है जो उपयोगकर्ता की पसंदीदा सूची में नहीं हैं. जब उपयोगकर्ता यह कार्रवाई चुनता है, तो इसे "पसंदीदा" के साथ स्वैप किया जा सकता है. साथ ही, यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए, EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM बटन के साथ sendResult को कॉल किया जा सकता है.
  2. पसंदीदा के तौर पर मार्क किया गया: यह कार्रवाई उन आइटम के लिए दिखती है जो उपयोगकर्ता की पसंदीदा सूची में शामिल हैं. जब उपयोगकर्ता यह कार्रवाई चुनता है, तो इसे "पसंदीदा" के साथ स्वैप किया जा सकता है. साथ ही, यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए, EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM बटन का इस्तेमाल करके sendResult को कॉल किया जा सकता है.

इस तरीके से, उपयोगकर्ताओं को अपने पसंदीदा आइटम मैनेज करने का एक साफ़ और आसान तरीका मिलता है.

इन उदाहरणों से, पसंद के मुताबिक ब्राउज़ करने की कार्रवाइयों की सुविधा के बारे में पता चलता है. साथ ही, यह भी पता चलता है कि इनका इस्तेमाल करके, कार के मीडिया ऐप्लिकेशन में उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, रीयल-टाइम फ़ीडबैक के साथ कई तरह की सुविधाएं कैसे लागू की जा सकती हैं.

इस सुविधा को लागू करने का पूरा उदाहरण देखने के लिए, 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 ऑब्जेक्ट से मिले MediaSessionCompat.Callback क्लास का इस्तेमाल करते हैं. यह ऑब्जेक्ट, आपके ऐप्लिकेशन की मीडिया ब्राउज़र सेवा से मिला होता है. जब कोई उपयोगकर्ता कॉन्टेंट के प्लेबैक को कंट्रोल करना चाहता है, जैसे कि प्लेबैक को रोकना या अगले ट्रैक पर जाना, तो Android Auto और Android Automotive OS, कॉलबैक ऑब्जेक्ट के किसी एक तरीके को लागू करते हैं.

कॉन्टेंट चलाने की सुविधा को मैनेज करने के लिए, आपके ऐप्लिकेशन को एब्स्ट्रैक्ट 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, चालू की गई हर कार्रवाई के लिए बटन के साथ-साथ, वीडियो चलाने की सूची भी दिखाते हैं. बटन पर क्लिक करने पर, सिस्टम MediaSessionCompat.Callback से उनके संबंधित कॉलबैक को शुरू करता है.

इस्तेमाल नहीं किए गए स्टोरेज को रिज़र्व करना

Android Auto और Android Automotive OS, यूज़र इंटरफ़ेस (यूआई) में 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 में जोड़ा गया है.

स्टैंडर्ड कार्रवाइयों से अलग व्यवहार देने के लिए, कस्टम कार्रवाइयों का इस्तेमाल करें. इनका इस्तेमाल, स्टैंडर्ड ऐक्शन को बदलने या डुप्लीकेट करने के लिए न करें.

PlaybackStateCompat.Builder क्लास में addCustomAction() तरीका इस्तेमाल करके, कस्टम ऐक्शन जोड़े जा सकते हैं.

नीचे दिए गए कोड स्निपेट में, “रेडियो चैनल चलाएं” कार्रवाई को कस्टमाइज़ करने का तरीका बताया गया है:

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());

इस तरीके के बारे में ज़्यादा जानकारी के लिए, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में setCustomAction() तरीका देखें.

कस्टम ऐक्शन बनाने के बाद, आपका मीडिया सेशन 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)) {
        ...
    }
}

इस तरीके के बारे में ज़्यादा जानकारी के लिए, GitHub पर Universal Android Music Player के सैंपल ऐप्लिकेशन में onCustomAction तरीका देखें.

कस्टम ऐक्शन के लिए आइकॉन

आपकी बनाई गई हर कस्टम कार्रवाई के लिए, एक आइकॉन होना ज़रूरी है.

अगर उस आइकॉन का ब्यौरा, CommandButton.ICON_ के किसी एक स्थिर वैल्यू से मैच करता है, तो आपको कस्टम ऐक्शन के एक्सट्रा की EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT कुंजी के लिए, उस पूर्णांक की वैल्यू सेट करनी चाहिए. जिन सिस्टम पर यह सुविधा काम करती है उन पर, यह CustomAction.Builder को पास किए गए आइकॉन के संसाधन को बदल देगा. इससे सिस्टम के कॉम्पोनेंट, आपकी कार्रवाई और वीडियो चलाने से जुड़ी अन्य कार्रवाइयों को एक जैसी स्टाइल में रेंडर कर पाएंगे.

आपको आइकॉन का संसाधन भी बताना होगा. कार में मौजूद ऐप्लिकेशन, कई अलग-अलग स्क्रीन साइज़ और डेंसिटी पर काम कर सकते हैं. इसलिए, आपके दिए गए आइकॉन वेक्टर ड्रॉबल होने चाहिए. वैक्टर ड्रॉबल की मदद से, एसेट को स्केल किया जा सकता है. ऐसा करने पर, एसेट की क्वालिटी में कोई बदलाव नहीं होता. वेक्टर ड्रॉबल की मदद से, छोटे रिज़ॉल्यूशन में किनारों और कोनों को पिक्सल की सीमाओं के साथ अलाइन करना भी आसान हो जाता है.

अगर कोई कस्टम ऐक्शन स्टेटफ़ुल है, तो अलग-अलग स्टेटस के लिए अलग-अलग आइकॉन उपलब्ध कराएं. उदाहरण के लिए, यह किसी वीडियो के चलने की सेटिंग को चालू या बंद करता है. इससे, उपयोगकर्ताओं को ऐक्शन चुनने पर बदलाव दिख सकता है.

बंद की गई कार्रवाइयों के लिए, आइकॉन के अन्य स्टाइल उपलब्ध कराना

जब मौजूदा कॉन्टेक्स्ट के लिए कोई कस्टम ऐक्शन उपलब्ध न हो, तो कस्टम ऐक्शन आइकॉन को किसी ऐसे आइकॉन से बदलें जिससे पता चलता हो कि ऐक्शन बंद है.

छठी इमेज. स्टाइल के हिसाब से नहीं बनाए गए कस्टम ऐक्शन आइकॉन के सैंपल.

ऑडियो फ़ॉर्मैट की जानकारी देना

यह बताने के लिए कि फ़िलहाल चल रहा मीडिया किसी खास ऑडियो फ़ॉर्मैट का इस्तेमाल करता है, आपके पास ऐसे आइकॉन तय करने का विकल्प होता है जो इस सुविधा के साथ काम करने वाली कारों में रेंडर किए जाते हैं. फ़िलहाल चल रहे मीडिया आइटम के एक्सट्रा बंडल में, KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI और KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI को सेट किया जा सकता है. यह बंडल, MediaSession.setMetadata() को पास किया जाता है. अलग-अलग लेआउट के हिसाब से, दोनों एक्सट्रा को सेट करना न भूलें.

इसके अलावा, KEY_IMMERSIVE_AUDIO एक्सट्रा को सेट करके, कार के OEM को यह बताया जा सकता है कि यह इमर्सिव ऑडियो है. साथ ही, उन्हें यह तय करते समय बहुत सावधानी बरतनी चाहिए कि क्या ऐसे ऑडियो इफ़ेक्ट इस्तेमाल किए जाएं जिनसे इमर्सिव कॉन्टेंट में रुकावट आ सकती है.

फ़िलहाल चल रहे मीडिया आइटम को कॉन्फ़िगर किया जा सकता है, ताकि उसका सबटाइटल, ब्यौरा या दोनों, दूसरे मीडिया आइटम के लिंक हों. इससे उपयोगकर्ता, मिलते-जुलते आइटम पर तुरंत जा सकते हैं. उदाहरण के लिए, वे उसी कलाकार के अन्य गाने, उस पॉडकास्ट के अन्य एपिसोड वगैरह पर जा सकते हैं. अगर कार में यह सुविधा काम करती है, तो उपयोगकर्ता उस कॉन्टेंट को ब्राउज़ करने के लिए लिंक पर टैप कर सकते हैं.

लिंक जोड़ने के लिए, सबटाइटल से लिंक करने के लिए KEY_SUBTITLE_LINK_MEDIA_ID मेटाडेटा या ब्यौरे से लिंक करने के लिए KEY_DESCRIPTION_LINK_MEDIA_ID मेटाडेटा को कॉन्फ़िगर करें. ज़्यादा जानकारी के लिए, उन मेटाडेटा फ़ील्ड के लिए रेफ़रंस दस्तावेज़ देखें.

बोलकर फ़ोन इस्तेमाल करने की सुविधा

आपका मीडिया ऐप्लिकेशन, बोलकर फ़ोन का तेज़ी से इस्तेमाल करने की सुविधा के साथ काम करना चाहिए. इससे ड्राइवरों को सुरक्षित और आसान अनुभव मिलता है. साथ ही, ड्राइविंग के दौरान उनका ध्यान भटकने से भी बचा रहता है. उदाहरण के लिए, अगर आपका ऐप्लिकेशन कोई मीडिया आइटम चला रहा है, तो उपयोगकर्ता आपके ऐप्लिकेशन को कोई दूसरा गाना चलाने के लिए, कार के डिसप्ले को देखे या छुए बिना “[गाने का टाइटल]चलाएं” कह सकता है. उपयोगकर्ता, अपने स्टीयरिंग व्हील पर मौजूद बटन पर क्लिक करके या "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 पर अलार्म चलाएं और अलार्म बंद करने के लिए, फ़ोन की स्क्रीन पर यूज़र इंटरफ़ेस (यूआई) दें.

मीडिया विज्ञापनों को मैनेज करना

डिफ़ॉल्ट रूप से, ऑडियो चलाने के दौरान मीडिया का मेटाडेटा बदलने पर, 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 के किसी उपयोगकर्ता को गड़बड़ी को ठीक करने के लिए, आपके फ़ोन पर मौजूद ऐप्लिकेशन खोलना है, तो मैसेज में उसे यह जानकारी दें. उदाहरण के लिए, गड़बड़ी के मैसेज में "कृपया साइन इन करें" के बजाय, "[आपके ऐप्लिकेशन का नाम] में साइन इन करें" लिखा हो सकता है.

अन्य संसाधन