अपने कॉन्टेंट की हैरारकी तैयार करना

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

onGetRoot को लागू करना

आपकी सेवा का onGetRoot तरीका, आपके कॉन्टेंट के क्रम के रूट नोड के बारे में जानकारी देता है. Android Auto और AAOS, इस रूट नोड का इस्तेमाल करके 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 तरीके को कॉल किया जाता है, तो कॉल करने वाला पैकेज आपकी सेवा को पहचान करने वाली जानकारी भेजता है. आपकी सेवा इस जानकारी का इस्तेमाल करके यह तय कर सकती है कि उस पैकेज को आपका कॉन्टेंट ऐक्सेस करने की अनुमति दी जा सकती है या नहीं.

उदाहरण के लिए, अपने ऐप्लिकेशन के कॉन्टेंट का ऐक्सेस, मंज़ूरी पा चुके पैकेज की सूची तक सीमित किया जा सकता है:

  • अनुमति वाले चैनलों की सूची में शामिल चैनलों से clientPackageName की तुलना करें.
  • पैकेज के APK पर हस्ताक्षर करने के लिए इस्तेमाल किए गए सर्टिफ़िकेट की पुष्टि करें.

अगर पैकेज की पुष्टि नहीं हो पाती है, तो null पर वापस जाएं और अपने कॉन्टेंट का ऐक्सेस देने से मना करें.

Android Auto और AAOS जैसे सिस्टम ऐप्लिकेशन को आपके कॉन्टेंट का ऐक्सेस देने के लिए, आपकी सेवा को BrowserRoot के तौर पर नॉन-नल वैल्यू दिखानी होगी. ऐसा तब होगा, जब ये सिस्टम ऐप्लिकेशन onGetRoot तरीके को कॉल करेंगे.

AAOS सिस्टम ऐप्लिकेशन का सिग्नेचर, कार के मेक और मॉडल के हिसाब से अलग-अलग होता है. पक्का करें कि आपने सभी सिस्टम ऐप्लिकेशन को AAOS के साथ कनेक्ट करने की अनुमति दी हो.

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

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 AAOS शामिल है.

onLoadChildren को लागू करना

रूट नोड ऑब्जेक्ट मिलने के बाद, Android Auto और AAOS, टॉप-लेवल मेन्यू बनाते हैं. इसके लिए, वे रूट नोड ऑब्जेक्ट पर 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&lt;MediaBrowserCompat.MediaItem> = mutableListOf()

    // Check if 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 descendants of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems)
}

Java

@Override
public void onLoadChildren(final String parentMediaId,
    final Result&lt;List&lt;MediaBrowserCompat.MediaItem>> result) {

    // Assume for example that the music catalog is already loaded/cached.

    List&lt;MediaBrowserCompat.MediaItem> mediaItems = new ArrayList&lt;>();

    // Check if 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 descendants of that menu in the mediaItems list.
    }
    result.sendResult(mediaItems);
}

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

रूट मेन्यू को स्ट्रक्चर करना

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

रूट कॉन्टेंट को नेविगेशन टैब के तौर पर दिखाया गया है

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

इन संकेतों को लागू करने पर, सिस्टम रूट कॉन्टेंट को नेविगेशन टैब के तौर पर दिखाता है. इन संकेतों को लागू न करने पर, हो सकता है कि कुछ मुख्य कॉन्टेंट को हटा दिया जाए या उसे कम खोजा जा सके. ये सुराग इस तरह से भेजे जाते हैं:

Kotlin

import androidx.media.utils.MediaConstants

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 और AAOS के बाहर MediaBrowser इंटिग्रेशन के हिसाब से अलग-अलग होता है.

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

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

  • हर टैब आइटम के लिए मोनोक्रोम (सफ़ेद रंग के) आइकॉन

  • हर टैब आइटम के लिए छोटे और काम के लेबल (छोटे लेबल से, लेबल के कटने की संभावना कम हो जाती है)