Arabalar için medya uygulamaları oluşturma

Android Auto ve Android Automotive OS, medya uygulamanızın içeriğini kullanıcıların arabalarına getirmenize yardımcı olur.

Arabalar için medya uygulamaları oluşturmanın iki yolu vardır:

  • Bu kılavuzda, Android Auto ve Android Automotive OS'in bağlanabileceği bir uygulama oluşturmak için MediaBrowserService ve MediaSession nasıl kullanılacağı açıklanmaktadır. Bu uygulama, araç içi kullanıma yönelik olarak optimize edilmiş medya tarama ve oynatma görünümleri oluşturur.

  • Medya uygulamaları, özelleştirilebilir biçimlendirme, göz atma özellikleri ve genişletilmiş özel işlemler için Car App Library şablonları kullanılarak da oluşturulabilir. Uygulama ayrıntıları için Şablonlu bir medya uygulaması oluşturma başlıklı makaleyi inceleyin. Şablonlu medya uygulamaları şu anda yalnızca Android Auto'da desteklenmektedir.

Bu kılavuzda, uygulamanızın Android Auto veya Android Automotive OS'te çalışması için gereken MediaBrowserService ve MediaSession bileşenleri açıklanmaktadır. Temel medya altyapısını tamamladıktan sonra medya uygulamanıza Android Auto desteği ve Android Automotive OS desteği ekleyebilirsiniz.

Bu kılavuzda, telefonda ses çalan bir medya uygulamanızın olduğu ve medya uygulamanızın Android medya uygulaması mimarisine uygun olduğu varsayılmaktadır.

Başlamadan önce

  1. Android Media API belgelerini inceleyin.
  2. Tasarım rehberliği için Medya uygulamaları oluşturma başlıklı makaleyi inceleyin.
  3. Bu bölümde listelenen temel terimleri ve kavramları inceleyin.

Temel terimler ve kavramlar

Medya tarayıcı hizmeti
Medya uygulamanız tarafından uygulanan ve MediaBrowserServiceCompat API'sine uygun bir Android hizmeti. Uygulamanız, içeriğini göstermek için bu hizmeti kullanıyor.
Medya tarayıcı
Medya uygulamalarının medya tarayıcı hizmetlerini keşfetmek ve içeriklerini göstermek için kullandığı bir API. Android Auto ve Android Automotive OS, uygulamanızın medya tarayıcı hizmetini bulmak için medya tarayıcı kullanır.
Medya öğesi

Medya tarayıcı, içeriğini MediaItem nesnelerden oluşan bir ağaç yapısında düzenler. Bir medya öğesi aşağıdaki işaretlerden birini veya ikisini birden içerebilir:

  • FLAG_PLAYABLE: Öğenin, içerik ağacında bir yaprak olduğunu gösterir. Öğe, albümdeki bir şarkı, sesli kitaptaki bir bölüm veya podcast'in bir bölümü gibi tek bir ses akışını temsil eder.
  • FLAG_BROWSABLE: Öğenin içerik ağacında bir düğüm olduğunu ve alt öğeleri olduğunu gösterir. Örneğin, öğe bir albümü, alt öğeleri ise albümdeki şarkıları temsil eder.

Hem göz atılabilir hem de oynatılabilir bir medya öğesi, oynatma listesi gibi davranır. Öğenin tüm alt öğelerini oynatmak için öğeyi seçebilir veya alt öğelerine göz atabilirsiniz.

Araç optimizasyonlu

Android Automotive OS tasarım kurallarına uyan bir Android Automotive OS uygulaması için etkinlik. Bu etkinliklerin arayüzü Android Automotive OS tarafından çizilmez. Bu nedenle, uygulamanızın tasarım yönergelerine uyduğundan emin olmanız gerekir. Genellikle daha büyük dokunma hedefleri ve yazı tipi boyutları, gündüz ve gece modları desteği ve daha yüksek kontrast oranları bu kapsamdadır.

Araç için optimize edilmiş kullanıcı arayüzlerinin yalnızca Araba Kullanıcı Deneyimi Kısıtlamaları (CUXR'ler) geçerli olmadığında gösterilmesine izin verilir. Çünkü bu arayüzler, kullanıcının uzun süre dikkatini vermesini veya etkileşimde bulunmasını gerektirebilir. CUXR'ler, araç durdurulduğunda veya park edildiğinde geçerli değildir ancak araç hareket halindeyken her zaman geçerlidir.

Android Auto, medya tarayıcı hizmetinizdeki bilgileri kullanarak araca göre optimize edilmiş kendi arayüzünü oluşturduğundan Android Auto için etkinlik tasarlamanız gerekmez.

Uygulamanızın manifest dosyalarını yapılandırma

Medya tarayıcı hizmetinizi oluşturmadan önce uygulamanızın manifest dosyalarını yapılandırmanız gerekir.

Medya tarayıcı hizmetinizi beyan etme

Hem Android Auto hem de Android Automotive OS, medya öğelerine göz atmak için medya tarayıcı hizmetiniz üzerinden uygulamanıza bağlanır. Android Auto ve Android Automotive OS'in hizmeti keşfedip uygulamanıza bağlanabilmesi için medya tarayıcı hizmetinizi manifest dosyanızda beyan edin.

Aşağıdaki kod snippet'inde, medya tarayıcı hizmetinizi manifestinizde nasıl beyan edeceğiniz gösterilmektedir. Bu kodu, Android Automotive OS modülünüzün manifest dosyasına ve telefon uygulamanızın manifest dosyasına ekleyin.

<application>
    ...
    <service android:name=".MyMediaBrowserService"
             android:exported="true">
        <intent-filter>
            <action android:name="android.media.browse.MediaBrowserService"/>
        </intent-filter>
    </service>
    ...
</application>

Uygulama simgelerini belirtin

Android Auto ve Android Automotive OS'in, uygulamanızı sistem kullanıcı arayüzünde temsil etmek için kullanabileceği uygulama simgelerini belirtmeniz gerekir. İki simge türü gereklidir:

  • Başlatıcı simgesi
  • İlişkilendirme simgesi

Başlatıcı simgesi

Başlatıcı simgesi, uygulamanızı sistem kullanıcı arayüzünde (ör. başlatıcıda ve simge tepsisinde) temsil eder. Aşağıdaki manifest beyanını kullanarak araba medya uygulamanızı temsil etmek için mobil uygulamanızdaki simgeyi kullanmak istediğinizi belirtebilirsiniz:

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

Mobil uygulamanızın simgesinden farklı bir simge kullanmak için manifest dosyasındaki medya tarayıcı hizmetinizin android:icon öğesinde android:icon özelliğini ayarlayın:<service>

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

İlişkilendirme simgesi

1.şekil Medya kartındaki ilişkilendirme simgesi.

Atıf simgesi, medya içeriğinin öncelikli olduğu yerlerde (ör. medya kartlarında) kullanılır. Bildirimler için kullanılan küçük simgeyi yeniden kullanabilirsiniz. Bu simge tek renkli olmalıdır. Aşağıdaki manifest bildirimini kullanarak uygulamanızı temsil etmek için kullanılan bir simge belirtebilirsiniz:

<application>
    ...
    <meta-data
        android:name="androidx.car.app.TintableAttributionIcon"
        android:resource="@drawable/ic_status_icon" />
    ...
</application>

Medya tarayıcı hizmetinizi oluşturma

MediaBrowserServiceCompat sınıfını genişleterek bir medya tarayıcı hizmeti oluşturursunuz. Android Auto ve Android Automotive OS, hizmetinizi kullanarak şunları yapabilir:

  • Kullanıcıya bir menü sunmak için uygulamanızın içerik hiyerarşisine göz atın.
  • Ses oynatmayı kontrol etmek için uygulamanızın MediaSessionCompat nesnesinin jetonunu alın.

Ayrıca, medya tarayıcı hizmetinizi kullanarak diğer istemcilerin uygulamanızdaki medya içeriklerine erişmesine izin verebilirsiniz. Bu medya istemcileri, kullanıcının telefonundaki diğer uygulamalar veya diğer uzak istemciler olabilir.

Medya tarayıcı hizmeti iş akışı

Bu bölümde, Android Automotive OS ve Android Auto'nun tipik bir kullanıcı iş akışı sırasında medya tarayıcı hizmetinizle nasıl etkileşimde bulunduğu açıklanmaktadır.

  1. Kullanıcı, uygulamanızı Android Automotive OS veya Android Auto'da başlatır.
  2. Android Automotive OS veya Android Auto, onCreate() yöntemini kullanarak uygulamanızın medya tarayıcı hizmetiyle iletişim kurar. onCreate() yöntemini uygularken bir MediaSessionCompat nesnesi ve geri çağırma nesnesi oluşturup kaydetmeniz gerekir.
  3. Android Automotive OS veya Android Auto, içerik hiyerarşinizdeki kök medya öğesini almak için hizmetinizin onGetRoot() yöntemini çağırır. Kök medya öğesi gösterilmez. Bunun yerine, uygulamanızdan daha fazla içerik almak için kullanılır.
  4. Android Automotive OS veya Android Auto, hizmetinizin kök medya öğesinin alt öğelerini almak için onLoadChildren() yöntemini çağırır. Android Automotive OS ve Android Auto, bu medya öğelerini içerik öğelerinin en üst düzeyinde gösterir. Sistemin bu düzeyde ne beklediği hakkında daha fazla bilgi için bu sayfadaki Kök menüyü yapılandırma bölümüne bakın.
  5. Kullanıcı, göz atılabilir bir medya öğesi seçerse seçilen menü öğesinin alt öğelerini almak için hizmetinizin onLoadChildren() yöntemi tekrar çağrılır.
  6. Kullanıcı oynatılabilir bir medya öğesi seçerse Android Automotive OS veya Android Auto, bu işlemi gerçekleştirmek için uygun medya oturumu geri çağırma yöntemini çağırır.
  7. Uygulamanız destekliyorsa kullanıcılar içeriğinizi de arayabilir. Bu durumda, Android Automotive OS veya Android Auto, hizmetinizin onSearch() yöntemini çağırır.

İçerik hiyerarşinizi oluşturma

Android Auto ve Android Automotive OS, hangi içeriklerin kullanılabildiğini öğrenmek için uygulamanızın medya tarayıcı hizmetini çağırır. Bunu desteklemek için medya tarayıcı hizmetinizde iki yöntem uygulamanız gerekir: onGetRoot() ve onLoadChildren()

onGetRoot'u uygulama

Hizmetinizin onGetRoot() yöntemi, içerik hiyerarşinizin kök düğümü hakkında bilgi döndürür. Android Auto ve Android Automotive OS, onLoadChildren() yöntemini kullanarak içeriklerinizin geri kalanını istemek için bu kök düğümü kullanır.

Aşağıdaki kod snippet'inde, onGetRoot() yönteminin basit bir uygulaması gösterilmektedir:

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

Bu yöntemle ilgili daha ayrıntılı bir örnek için GitHub'daki Universal Android Music Player örnek uygulamasında onGetRoot() yöntemine bakın.

onGetRoot() için paket doğrulaması ekleyin

Hizmetinizin onGetRoot() yöntemine bir çağrı yapıldığında, arayan paket tanımlayıcı bilgileri hizmetinize iletir. Hizmetiniz, bu bilgileri kullanarak paketin içeriğinize erişip erişemeyeceğine karar verebilir. Örneğin, clientPackageName değerini izin verilenler listenizle karşılaştırarak ve paketin APK'sını imzalamak için kullanılan sertifikayı doğrulayarak uygulamanızın içeriğine erişimi onaylanmış paketlerin listesiyle kısıtlayabilirsiniz. Paket doğrulanamazsa içeriğinize erişimi reddetmek için null döndürün.

Android Auto ve Android Automotive OS gibi sistem uygulamalarının içeriğinize erişebilmesi için hizmetiniz, bu sistem uygulamaları onGetRoot() yöntemini çağırdığında her zaman null olmayan bir BrowserRoot döndürmelidir. Android Automotive OS sistem uygulamasının imzası, arabanın markasına ve modeline göre değişebilir. Bu nedenle, Android Automotive OS'i güçlü bir şekilde desteklemek için tüm sistem uygulamalarından gelen bağlantılara izin vermeniz gerekir.

Aşağıdaki kod snippet'inde, hizmetinizin arayan paketin bir sistem uygulaması olduğunu nasıl doğrulayabileceği gösterilmektedir:

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
}

Bu kod snippet'i, GitHub'daki Universal Android Music Player örnek uygulamasında bulunan PackageValidator sınıfından alınmıştır. Hizmetinizin onGetRoot() yöntemi için paket doğrulamasını nasıl uygulayacağınızla ilgili daha ayrıntılı bir örnek için bu sınıfa bakın.

Sistem uygulamalarına izin vermenin yanı sıra Google Asistan'ın MediaBrowserService cihazınıza bağlanmasına da izin vermeniz gerekir. Google Asistan'ın, Android Auto'nun dahil olduğu telefon ve Android Automotive OS için ayrı paket adları olduğunu unutmayın.

onLoadChildren() işlevini uygulama

Android Auto ve Android Automotive OS, kök düğüm nesnenizi aldıktan sonra alt öğelerini almak için kök düğüm nesnesinde onLoadChildren() çağrısı yaparak üst düzey bir menü oluşturur. İstemci uygulamaları, alt düğüm nesnelerini kullanarak aynı yöntemi çağırarak alt menüler oluşturur.

İçerik hiyerarşinizdeki her düğüm bir MediaBrowserCompat.MediaItem nesnesiyle temsil edilir. Bu medya öğelerinin her biri benzersiz bir kimlik dizesiyle tanımlanır. İstemci uygulamaları bu kimlik dizelerini opak jetonlar olarak ele alır. Bir istemci uygulaması bir alt menüye göz atmak veya bir medya öğesini oynatmak istediğinde jetonu iletir. Uygulamanız, jetonu uygun medya öğesiyle ilişkilendirmekten sorumludur.

Aşağıdaki kod snippet'inde, onLoadChildren() yönteminin basit bir uygulaması gösterilmektedir:

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

Bu yöntemin eksiksiz bir örneği için GitHub'daki Universal Android Music Player örnek uygulamasında onLoadChildren() yöntemine bakın.

Kök menüyü yapılandırma

Şekil 2. Kök içerik, gezinme sekmeleri olarak gösterilir.

Android Auto ve Android Automotive OS, kök menünün yapısıyla ilgili belirli kısıtlamalara sahiptir. Bunlar, MediaBrowserService ile Bundle bağımsız değişkeni kullanılarak okunabilen kök ipuçları aracılığıyla onGetRoot()'e iletilir. Bu ipuçlarını uyguladığınızda sistem, kök içeriği gezinme sekmeleri olarak en iyi şekilde gösterebilir. Bu ipuçlarını dikkate almazsanız bazı temel içerikler sistem tarafından kaldırılabilir veya daha az görünür hale getirilebilir. İki ipucu gönderilir:

İlgili kök ipuçlarını okumak için aşağıdaki kodu kullanın:

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

Özellikle hiyerarşiniz Android Auto ve Android Automotive OS dışındaki MediaBrowser entegrasyonlar arasında farklılık gösteriyorsa içerik hiyerarşinizin yapısıyla ilgili mantığı bu ipuçlarının değerlerine göre dallandırmayı seçebilirsiniz. Örneğin, normalde bir kök oynanabilir öğe gösteriyorsanız desteklenen işaretlerin ipucu değeri nedeniyle bunu bir kök göz atılabilir öğenin altına yerleştirmek isteyebilirsiniz.

Kök ipuçlarının yanı sıra, sekmelerin en iyi şekilde oluşturulmasını sağlamak için uymanız gereken birkaç ek yönerge vardır:

  • Her sekme öğesi için tek renkli, tercihen beyaz simgeler sağlayın.
  • Her sekme öğesi için kısa ama anlamlı etiketler sağlayın. Etiketleri kısa tutmak, dizelerin kesilme olasılığını azaltır.

Görüntülü reklam medya öğesi

Medya öğelerinin resimleri, ContentResolver.SCHEME_CONTENT veya ContentResolver.SCHEME_ANDROID_RESOURCE kullanılarak yerel URI olarak iletilmelidir. Bu yerel URI, uygulamanın kaynaklarında bit eşlem veya vektör çizilebilir öğeye çözümlenmelidir. İçerik hiyerarşisindeki öğeleri temsil eden MediaDescriptionCompat nesneleri için URI'yi setIconUri() üzerinden iletin. Şu anda oynatılan öğeyi temsil eden MediaMetadataCompat nesneleri için URI'yi aşağıdaki anahtarlardan herhangi birini kullanarak putString() üzerinden iletin:

Aşağıdaki adımlarda, bir web URI'sinden nasıl resim indirileceği ve yerel bir URI aracılığıyla nasıl gösterileceği açıklanmaktadır. Daha eksiksiz bir örnek için Universal Android Music Player örnek uygulamasında openFile() ve çevreleyen yöntemlerin uygulanmasına bakın.

  1. Web URI'sine karşılık gelen bir content:// URI'si oluşturun. Medya tarayıcı hizmeti ve medya oturumu, bu içerik URI'sini Android Auto ve Android Automotive OS'e iletir.

    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() uygulamanızda, ilgili URI için bir dosyanın mevcut olup olmadığını kontrol edin. Aksi takdirde, resim dosyasını indirip önbelleğe alın. Aşağıdaki kod snippet'inde Glide kullanılıyor.

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

İçerik sağlayıcılar hakkında daha fazla bilgi için İçerik sağlayıcı oluşturma başlıklı makaleyi inceleyin.

İçerik stillerini uygulama

Göz atılabilir veya oynatılabilir öğeler kullanarak içerik hiyerarşinizi oluşturduktan sonra, bu öğelerin arabada nasıl görüntüleneceğini belirleyen içerik stilleri uygulayabilirsiniz.

Aşağıdaki içerik stillerini kullanabilirsiniz:

Liste öğeleri

Bu içerik stilinde başlıklar ve meta veriler, resimlere göre önceliklidir.

Tablo öğeleri

Bu içerik stilinde, başlıklar ve meta veriler yerine resimlere öncelik verilir.

Varsayılan içerik stillerini ayarlama

Hizmetinizin onGetRoot() yönteminin BrowserRoot ekstralar paketine belirli sabitleri ekleyerek medya öğelerinizin nasıl görüntüleneceğiyle ilgili genel varsayılanlar ayarlayabilirsiniz. Android Auto ve Android Automotive OS, bu paketi okur ve uygun stili belirlemek için bu sabitleri arar.

Pakette anahtar olarak aşağıdaki ekstralar kullanılabilir:

Anahtarlar, bu öğelerin sunumunu etkilemek için aşağıdaki tam sayı sabit değerleriyle eşlenebilir:

  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM: İlgili öğeler liste öğeleri olarak sunulur.
  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM: İlgili öğeler ızgara öğeleri olarak sunulur.
  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM: İlgili öğeler "kategori" liste öğeleri olarak sunulur. Bunlar, öğelerin simgeleri küçük olduğunda daha iyi göründüğünden, öğelerin simgelerinin etrafına kenar boşlukları uygulanması dışında normal liste öğeleriyle aynıdır. Simgeler, renklendirilebilir vektör çizimleri olmalıdır. Bu ipucunun yalnızca göz atılabilir öğeler için sağlanması beklenir.
  • DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM: İlgili öğeler "kategori" ızgara öğeleri olarak sunulur. Bunlar, öğelerin simgelerinin etrafına kenar boşlukları uygulanması dışında normal tablo öğeleriyle aynıdır. Bunun nedeni, simgelerin küçükken daha iyi görünmesidir. Simgeler, renklendirilebilir vektör çizimleri olmalıdır. Bu ipucunun yalnızca göz atılabilir öğeler için sağlanması beklenir.

Aşağıdaki kod snippet'inde, göz atılabilir öğeler için varsayılan içerik stilinin ızgara, oynatılabilir öğeler için ise liste olarak nasıl ayarlanacağı gösterilmektedir:

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

Öğe başına içerik stilleri ayarlama

Content Style API, göz atılabilir herhangi bir medya öğesinin alt öğeleri ve medya öğesinin kendisi için varsayılan içerik stilini geçersiz kılmanıza olanak tanır.

Göz atılabilir bir medya öğesinin alt öğeleri için varsayılanı geçersiz kılmak istiyorsanız medya öğesinin MediaDescription bölümünde bir ekler paketi oluşturun ve daha önce bahsedilen ipuçlarını ekleyin. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE bu öğenin oynatılabilir alt öğeleri için geçerliyken DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE bu öğenin göz atılabilir alt öğeleri için geçerlidir.

Bir medya öğesinin kendisi için varsayılanı geçersiz kılmak istiyorsanız (alt öğeleri için değil) medya öğesinin MediaDescription bölümünde bir ekler paketi oluşturun ve DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM anahtarıyla bir ipucu ekleyin. Öğenin sunumunu belirtmek için daha önce açıklanan değerleri kullanın.

Aşağıdaki kod snippet'inde, hem kendisi hem de alt öğeleri için varsayılan içerik stilini geçersiz kılan, göz atılabilir bir MediaItem öğesinin nasıl oluşturulacağı gösterilmektedir. Kendisini kategori liste öğesi, göz atılabilir alt öğelerini liste öğesi ve oynatılabilir alt öğelerini ızgara öğesi olarak biçimlendirir:

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);
}
SINGLE_ITEM ipucu kullanılır.

Başlık ipuçlarını kullanarak öğeleri gruplandırma

İlgili medya öğelerini birlikte gruplandırmak için öğe başına ipucu kullanırsınız. Bir gruptaki her medya öğesi, MediaDescription içinde bir ek paket bildirmelidir. Bu paket, DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE anahtarıyla eşleme ve aynı dize değerini içermelidir. Grubun başlığı olarak kullanılan bu dizeyi yerelleştirin.

Aşağıdaki kod snippet'inde, "Songs" alt grup başlığına sahip bir MediaItem öğesinin nasıl oluşturulacağı gösterilmektedir:

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

Uygulamanız, gruplandırmak istediğiniz tüm medya öğelerini bitişik bir blok olarak iletmelidir. Örneğin, "Şarkılar" ve "Albümler" olmak üzere iki grup medya öğesini bu sırayla göstermek istediğinizi ve uygulamanızın beş medya öğesini aşağıdaki sırayla ilettiğini varsayalım:

  1. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") içeren A medya öğesi
  2. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") içeren B medya öğesi
  3. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") ile medya öğesi C
  4. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") ile medya öğesi D
  5. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") içeren E medya öğesi

"Şarkılar" ve "Albümler" grubundaki medya öğeleri bitişik bloklar halinde tutulmadığından Android Auto ve Android Automotive OS bunu aşağıdaki dört grup olarak yorumlar:

  • "Şarkılar" adlı 1. grup (A medya öğesini içerir)
  • Medya öğesi B'yi içeren "Albümler" adlı 2. grup
  • C ve D medya öğelerini içeren "Şarkılar" adlı 3. grup
  • Medya öğesi E'yi içeren "Albümler" adlı 4. grup

Bu öğeleri iki grupta göstermek için uygulamanızın medya öğelerini aşağıdaki sırayla iletmesi gerekir:

  1. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") içeren A medya öğesi
  2. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") ile medya öğesi C
  3. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") ile medya öğesi D
  4. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") içeren B medya öğesi
  5. extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums") içeren E medya öğesi

Ek meta veri göstergelerini görüntüleme

Medya tarayıcı ağacındaki ve oynatma sırasındaki içeriklerle ilgili bilgileri bir bakışta görmek için ek meta veri göstergeleri ekleyebilirsiniz. Göz atma ağacında Android Auto ve Android Automotive OS, bir öğeyle ilişkili ekstraları okur ve hangi göstergelerin görüntüleneceğini belirlemek için belirli sabitleri arar. Medya oynatma sırasında Android Auto ve Android Automotive OS, medya oturumunun meta verilerini okur ve gösterilecek göstergeleri belirlemek için belirli sabitleri arar.

3.Şekil Şarkıyı ve sanatçıyı tanımlayan meta verilerin yanı sıra uygunsuz içeriği gösteren bir simge içeren oynatma görünümü.

Şekil 4. İlk öğede oynatılmamış içerik için nokta, ikinci öğede ise kısmen oynatılmış içerik için ilerleme çubuğu bulunan göz atma görünümü.

Aşağıdaki sabitler hem MediaItem açıklama ekstralarında hem de MediaMetadata ekstralarında kullanılabilir:

Aşağıdaki sabitler yalnızca MediaItem açıklama eklerinde kullanılabilir:

Kullanıcı medya göz atma ağacına göz atarken görünen göstergeleri görüntülemek için bu sabitlerden birini veya daha fazlasını içeren bir ekler paketi oluşturun ve bu paketi MediaDescription.Builder.setExtras() yöntemine iletin.

Aşağıdaki kod snippet'inde, %70'i tamamlanmış bir uygunsuz medya öğesi için göstergelerin nasıl görüntüleneceği gösterilmektedir:

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

Şu anda oynatılan bir medya öğesi için göstergeleri görüntülemek üzere METADATA_KEY_IS_EXPLICIT veya EXTRA_DOWNLOAD_STATUS için Long değerlerini mediaSession öğenizin MediaMetadataCompat bölümünde bildirebilirsiniz. Oynatma görünümünde DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS veya DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE göstergelerini görüntüleyemezsiniz.

Aşağıdaki kod snippet'inde, oynatma görünümündeki mevcut şarkının uygunsuz içerik barındırdığı ve indirildiği nasıl belirtileceği gösterilmektedir:

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

İçerik oynatılırken göz atma görünümündeki ilerleme çubuğunu güncelleme

Daha önce de belirtildiği gibi, göz atma görünümünde kısmen oynatılan içerik için ilerleme çubuğu göstermek üzere DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE ekstrasını kullanabilirsiniz. Ancak, kullanıcı kısmen oynatılan içeriği Android Auto veya Android Automotive OS'de oynatmaya devam ederse bu gösterge zaman geçtikçe yanlış hale gelir.

Android Auto ve Android Automotive OS'de ilerleme çubuğunun güncel kalması için MediaMetadataCompat ve PlaybackStateCompat içinde ek bilgiler sağlayarak devam eden içerikleri göz atma görünümündeki medya öğelerine bağlayabilirsiniz. Medya öğesinin otomatik olarak güncellenen bir ilerleme çubuğuna sahip olması için aşağıdaki koşulların karşılanması gerekir:

Aşağıdaki kod snippet'inde, şu anda oynatılan öğenin göz atma görünümündeki bir öğeye nasıl bağlandığı gösterilmektedir:

Kotlin

import androidx.media.utils.MediaConstants

// When the MediaItem is constructed to show in the browse view.
// Suppose the item was 25% complete when the user launched the browse view.
val mediaItemExtras = Bundle()
mediaItemExtras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25)
val description =
    MediaDescriptionCompat.Builder()
        .setMediaId("my-media-id")
        .setExtras(mediaItemExtras)
        // ...and any other setters.
        .build()
return MediaBrowserCompat.MediaItem(description, /* flags */)

// Elsewhere, when the user has selected MediaItem for playback.
mediaSession.setMetadata(
    MediaMetadataCompat.Builder()
        .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id")
        // ...and any other setters.
        .build())

val playbackStateExtras = Bundle()
playbackStateExtras.putString(
    MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id")
mediaSession.setPlaybackState(
    PlaybackStateCompat.Builder()
        .setExtras(playbackStateExtras)
        // ...and any other setters.
        .build())

Java

import androidx.media.utils.MediaConstants;

// When the MediaItem is constructed to show in the browse view.
// Suppose the item was 25% complete when the user launched the browse view.
Bundle mediaItemExtras = new Bundle();
mediaItemExtras.putDouble(
    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25);
MediaDescriptionCompat description =
    new MediaDescriptionCompat.Builder()
        .setMediaId("my-media-id")
        .setExtras(mediaItemExtras)
        // ...and any other setters.
        .build();
return MediaBrowserCompat.MediaItem(description, /* flags */);

// Elsewhere, when the user has selected MediaItem for playback.
mediaSession.setMetadata(
    new MediaMetadataCompat.Builder()
        .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id")
        // ...and any other setters.
        .build());

Bundle playbackStateExtras = new Bundle();
playbackStateExtras.putString(
    MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id");
mediaSession.setPlaybackState(
    new PlaybackStateCompat.Builder()
        .setExtras(playbackStateExtras)
        // ...and any other setters.
        .build());

5.şekil Kullanıcının sesli aramasıyla ilgili medya öğelerini görüntülemek için "Arama sonuçları" seçeneği içeren oynatma görünümü.

Uygulamanız, kullanıcılar arama sorgusu başlattığında gösterilen bağlamsal arama sonuçları sağlayabilir. Android Auto ve Android Automotive OS, bu sonuçları arama sorgusu arayüzleri veya oturumda daha önce yapılan sorgulara dayalı olanaklar aracılığıyla gösterir. Daha fazla bilgi edinmek için bu kılavuzdaki Sesli işlemleri destekleme bölümüne bakın.

Göz atılabilir arama sonuçları göstermek için hizmetinizin onGetRoot() yönteminin ekstralar paketine BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED sabit anahtarını ekleyin ve bunu true boole'uyla eşleyin.

Aşağıdaki kod snippet'inde, onGetRoot() yönteminde desteğin nasıl etkinleştirileceği gösterilmektedir:

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

Arama sonuçları sağlamaya başlamak için medya tarayıcı hizmetinizdeki onSearch() yöntemini geçersiz kılın. Android Auto ve Android Automotive OS, kullanıcı bir arama sorgusu arayüzünü veya "Arama sonuçları" işlevini her çağırdığında kullanıcının arama terimlerini bu yönteme yönlendirir.

Hizmetinizin onSearch() yönteminden gelen arama sonuçlarını, daha kolay göz atılabilir hale getirmek için başlık öğeleri kullanarak düzenleyebilirsiniz. Örneğin, uygulamanızda müzik çalınıyorsa arama sonuçlarını albüme, sanatçıya ve şarkıya göre düzenleyebilirsiniz.

Aşağıdaki kod snippet'inde, onSearch() yönteminin basit bir uygulaması gösterilmektedir:

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

Özel Göz Atma İşlemleri

Tek bir özel göz atma işlemi.

6.şekil Tek Özel Göz Atma İşlemi

Özel Göz Atma İşlemleri, uygulamanızın MediaItem nesnelerine özel simgeler ve etiketler eklemenize, ayrıca bu işlemlerle kullanıcı etkileşimlerini yönetmenize olanak tanır. Bu sayede, "İndir", "Kuyruğa ekle", "Radyo çal", "Favorilere ekle" veya "Kaldır" gibi işlemler ekleyerek Medya Uygulaması'nın işlevselliğini çeşitli şekillerde genişletebilirsiniz.

Özel bir göz atma işlemleri taşma menüsü.

Şekil 7. Özel Göz Atma İşlemi taşması

OEM'nin görüntülenmesine izin verdiğinden daha fazla özel işlem varsa kullanıcıya bir taşma menüsü gösterilir.

İşleyiş şekli nasıldır?

Her özel göz atma işlemi şu şekilde tanımlanır:

  • İşlem kimliği (benzersiz dize tanımlayıcı)
  • İşlem etiketi (kullanıcıya gösterilen metin)
  • İşlem simgesi URI'si (renklendirilebilen bir drawable vektör)

BrowseRoot kapsamında, özel göz atma işlemlerinin listesini genel olarak tanımlarsınız. Ardından, bu işlemlerin bir alt kümesini ayrı ayrıMediaItem.

Kullanıcı, özel göz atma işlemiyle etkileşim kurduğunda uygulamanız onCustomAction() içinde geri çağırma alır. Ardından, işlemi gerçekleştirebilir ve gerekirse MediaItem için işlem listesini güncelleyebilirsiniz. Bu, "Favorilere ekle" ve "İndir" gibi durum bilgisi içeren işlemler için kullanışlıdır. "Radyo Çal" gibi güncellenmesi gerekmeyen işlemler için işlem listesini güncellemeniz gerekmez.

Bir göz atma düğümü kökündeki özel göz atma işlemleri.

Şekil 8. Özel Göz Atma İşlemi araç çubuğu

Özel Göz Atma İşlemleri'ni bir göz atma düğümü köküne de ekleyebilirsiniz. Bu işlemler, ana araç çubuğunun altındaki ikincil bir araç çubuğunda gösterilir.

Özel göz atma işlemlerini uygulama

Projenize özel göz atma işlemleri eklemek için aşağıdaki adımları uygulayın:

  1. MediaBrowserServiceCompat uygulamanızda iki yöntemi geçersiz kılın:
  2. Çalışma zamanında işlem sınırlarını ayrıştırın:
    • onGetRoot() içinde, rootHints Bundle içindeki BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT anahtarını kullanarak her MediaItem için izin verilen maksimum işlem sayısını alın. 0 sınırı, özelliğin sistem tarafından desteklenmediğini gösterir.
  3. Özel Göz Atma İşlemleri'nin genel listesini oluşturun:
    • Her işlem için aşağıdaki anahtarlara sahip bir Bundle nesnesi oluşturun: * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID: İşlem kimliği * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL: İşlem etiketi * EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI: İşlem simgesi URI'si * Tüm işlem Bundle nesnelerini bir listeye ekleyin.
  4. Genel listeyi BrowseRoot hesabınıza ekleyin:
  5. MediaItem nesnelerinize işlemler ekleyin:
    • DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST anahtarını kullanarak MediaDescriptionCompat ekstralarında işlem kimliklerinin listesini ekleyerek işlemleri tek tek MediaItem nesnelerine ekleyebilirsiniz. Bu liste, BrowseRoot içinde tanımladığınız genel işlem listesinin bir alt kümesi olmalıdır.
  6. İşlemleri gerçekleştirme ve ilerleme durumunu veya sonuçları döndürme:

Özel Göz Atma İşlemleri'ni kullanmaya başlamak için BrowserServiceCompat bölümünde yapabileceğiniz bazı değişiklikler aşağıda verilmiştir.

Override BrowserServiceCompat

MediaBrowserServiceCompat içinde aşağıdaki yöntemleri geçersiz kılmanız gerekir.

public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)

public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)

Ayrıştırma işlemleri sınırı

Kaç özel göz atma işleminin desteklendiğini kontrol etmeniz gerekir.

public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) {
    rootHints.getInt(
            MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0)
}

Özel Göz Atma İşlemi Oluşturma

Her işlem ayrı bir Bundle içine yerleştirilmelidir.

  • İşlem kimliği
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID,
                    "<ACTION_ID>")
  • İşlem Etiketi
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL,
                    "<ACTION_LABEL>")
  • İşlem simgesi URI'si
    bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI,
                    "<ACTION_ICON_URI>")

Parceable ArrayList'e özel göz atma işlemleri ekleme

Tüm Özel Göz Atma İşlemi Bundle nesnelerini bir ArrayList içine ekleyin.

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

Göz atma köküne özel göz atma işlemi listesi ekleme

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 adlı reklam grubuna işlem ekleme

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

Derleme onCustomAction sonucu

  • Bundle extras öğesinden mediaId değerini ayrıştırın:
    @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);
    }
  • Eşzamansız sonuçlar için sonucu ayırın. result.detach()
  • Derleme sonucu paketi
    • Kullanıcıya mesaj
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                mContext.getString(stringRes))
    • Öğeyi güncelleme(bir öğedeki işlemleri güncellemek için kullanılır)
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
    • Oynatma görünümünü açma
      //Shows user the PBV without changing the playback state
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
    • Göz atma düğümünü güncelleme
      //Change current browse node to mediaId
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
  • Hata varsa result.sendError(resultBundle). numaralı telefonu arayın.
  • İlerleme durumu güncellemesi için result.sendProgressUpdate(resultBundle) numaralı telefonu arayın.
  • result.sendResult(resultBundle) numarasını arayarak işlemi tamamlayın.

İşlem durumunu güncelleme

result.sendProgressUpdate(resultBundle) yöntemini EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM anahtarıyla kullanarak MediaItem değerini işlemin yeni durumunu yansıtacak şekilde güncelleyebilirsiniz. Bu sayede, kullanıcılara işlemlerinin ilerleme durumu ve sonucu hakkında anlık geri bildirim verebilirsiniz.

Örnek: İndirme İşlemi

Bu özelliği kullanarak üç durumlu bir indirme işlemi uygulama örneğini aşağıda bulabilirsiniz:

  1. İndir: Bu, işlemin ilk durumudur. Kullanıcı bu işlemi seçtiğinde "İndiriliyor" ile değiştirebilir ve kullanıcı arayüzünü güncellemek için sendProgressUpdate işlevini çağırabilirsiniz.
  2. İndiriliyor: Bu durum, indirme işleminin devam ettiğini gösterir. Bu durumu, kullanıcıya bir ilerleme çubuğu veya başka bir gösterge göstermek için kullanabilirsiniz.
  3. İndirildi: Bu durum, indirme işleminin tamamlandığını gösterir. İndirme işlemi tamamlandığında "İndiriliyor" ifadesini "İndirildi" ile değiştirebilir ve öğenin yenilenmesi gerektiğini belirtmek için sendResult işlevini EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM anahtarıyla çağırabilirsiniz. Ayrıca, kullanıcıya başarı mesajı göstermek için EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE anahtarını da kullanabilirsiniz.

Bu yaklaşım, indirme işlemi ve mevcut durumu hakkında kullanıcıya net geri bildirim vermenizi sağlar. %25, %50 ve% 75 indirme durumlarını göstermek için simgelerle daha fazla ayrıntı ekleyebilirsiniz.

Örnek: Favori İşlem

Bir başka örnek de iki durumu olan favori bir işlem:

  1. Favori: Bu işlem, kullanıcının favoriler listesinde olmayan öğeler için gösterilir. Kullanıcı bu işlemi seçtiğinde, işlemi "Favorilere eklendi" ile değiştirebilir ve kullanıcı arayüzünü güncellemek için EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM anahtarıyla sendResult işlevini çağırabilirsiniz.
  2. Favorilere eklenenler: Bu işlem, kullanıcının favoriler listesindeki öğeler için gösterilir. Kullanıcı bu işlemi seçtiğinde "Favori" ile değiştirebilir ve kullanıcı arayüzünü güncellemek için sendResult işlevini EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM anahtarıyla çağırabilirsiniz.

Bu yaklaşım, kullanıcıların favori öğelerini yönetmesi için net ve tutarlı bir yol sunar.

Bu örnekler, Özel Göz Atma İşlemlerinin esnekliğini ve bunları kullanarak arabanın medya uygulamasında gelişmiş bir kullanıcı deneyimi için çeşitli işlevleri nasıl uygulayabileceğinizi gösterir.

Bu özelliğin eksiksiz bir örnek uygulaması için TestMediaApp projesine başvurabilirsiniz.

Oynatma kontrolünü etkinleştirme

Android Auto ve Android Automotive OS, oynatma kontrolü komutlarını hizmetinizin MediaSessionCompat üzerinden gönderir. Bir oturum kaydetmeniz ve ilişkili geri çağırma yöntemlerini uygulamanız gerekir.

Medya oturumu kaydetme

Medya tarayıcı hizmetinizin onCreate() yönteminde MediaSessionCompat oluşturun, ardından setSessionToken()'ı çağırarak medya oturumunu kaydedin.

Aşağıdaki kod snippet'inde medya oturumunun nasıl oluşturulacağı ve kaydedileceği gösterilmektedir:

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

Medya oturumu nesnesini oluşturduğunuzda, oynatma kontrolü isteklerini işlemek için kullanılan bir geri çağırma nesnesi ayarlarsınız. Bu geri çağırma nesnesini, uygulamanız için MediaSessionCompat.Callback sınıfının bir uygulamasını sağlayarak oluşturursunuz. Sonraki bölümde, bu nesnenin nasıl uygulanacağı açıklanmaktadır.

Oynatma komutlarını uygulama

Bir kullanıcı uygulamanızdan bir medya öğesinin oynatılmasını istediğinde Android Automotive OS ve Android Auto, uygulamanızın medya tarayıcı hizmetinden elde ettikleri uygulamanızın MediaSessionCompat nesnesindeki MediaSessionCompat.Callback sınıfını kullanır. Kullanıcılar, içeriğin oynatılmasını kontrol etmek (ör. oynatmayı duraklatmak veya sonraki parçaya geçmek) istediğinde Android Auto ve Android Automotive OS, geri çağırma nesnesinin yöntemlerinden birini çağırır.

İçerik oynatmayı işlemek için uygulamanız, soyut MediaSessionCompat.Callbacksınıfını genişletmeli ve uygulamanızın desteklediği yöntemleri uygulamalıdır.

Uygulamanızın sunduğu içerik türü için anlamlı olan aşağıdaki geri çağırma yöntemlerinin tümünü uygulayın:

onPrepare()
Medya kaynağı değiştirildiğinde çağrılır. Android Automotive OS de bu yöntemi başlatmadan hemen sonra çağırır. Medya uygulamanız bu yöntemi uygulamalıdır.
onPlay()
Kullanıcı belirli bir öğe seçmeden oynatmayı seçerse çağrılır. Uygulamanız varsayılan içeriğini oynatmalı veya oynatma onPause() ile duraklatıldıysa oynatmaya devam etmelidir.

Not: Android Automotive OS veya Android Auto, medya tarayıcı hizmetinize bağlandığında uygulamanız otomatik olarak müzik çalmaya başlamamalıdır. Daha fazla bilgi için ilk oynatma durumunu ayarlama bölümüne bakın.

onPlayFromMediaId()
Kullanıcı belirli bir öğeyi oynatmayı seçtiğinde çağrılır. Yönteme, medya tarayıcı hizmetinizin içerik hiyerarşinizdeki medya öğesine atadığı kimlik iletilir.
onPlayFromSearch()
Kullanıcı bir arama sorgusundan oynatmayı seçtiğinde çağrılır. Uygulama, iletilen arama dizesine göre uygun bir seçim yapmalıdır.
onPause()
Kullanıcı oynatmayı duraklatmayı seçtiğinde çağrılır.
onSkipToNext()
Kullanıcı bir sonraki öğeye geçmeyi seçtiğinde çağrılır.
onSkipToPrevious()
Kullanıcı bir önceki öğeye gitmeyi seçtiğinde çağrılır.
onStop()
Kullanıcı oynatmayı durdurmayı seçtiğinde çağrılır.

İstediğiniz işlevleri sağlamak için bu yöntemleri uygulamanızda geçersiz kılın. İşlevi uygulamanız tarafından desteklenmiyorsa yöntemi uygulamanız gerekmez. Örneğin, uygulamanızda spor yayını gibi bir canlı yayın oynatılıyorsa onSkipToNext() yöntemini uygulamanız gerekmez. Bunun yerine onSkipToNext() öğesinin varsayılan uygulamasını kullanabilirsiniz.

Uygulamanızın, içeriği arabanın hoparlörlerinden çalmak için özel bir mantığa ihtiyacı yoktur. Uygulamanız içerik oynatma isteği aldığında sesi, kullanıcının telefon hoparlörleri veya kulaklıkları aracılığıyla içerik oynattığı şekilde oynatabilir. Android Auto ve Android Automotive OS, sesli içeriği arabanın hoparlörlerinden çalmak için otomatik olarak arabanın sistemine gönderir.

Ses içeriği oynatma hakkında daha fazla bilgi için MediaPlayer'a genel bakış, Ses uygulamasına genel bakış ve ExoPlayer genel bakış bölümlerine bakın.

Standart oynatma işlemlerini ayarlama

Android Auto ve Android Automotive OS, PlaybackStateCompat nesnesinde etkinleştirilen işlemlere göre oynatma kontrollerini gösterir.

Uygulamanız varsayılan olarak aşağıdaki işlemleri desteklemelidir:

Uygulamanız, içeriğiyle alakalı olması durumunda aşağıdaki işlemleri de destekleyebilir:

Ayrıca, kullanıcıya gösterilebilecek bir oynatma sırası oluşturma seçeneğiniz de vardır ancak bu zorunlu değildir. Bunu yapmak için setQueue() ve setQueueTitle() yöntemlerini çağırın, ACTION_SKIP_TO_QUEUE_ITEM işlemini etkinleştirin ve geri çağırmayı onSkipToQueueItem() tanımlayın.

Ayrıca, Ne çalıyor? simgesi için destek ekleyin. Bu simge, şu anda neyin çaldığını gösterir. Bunu yapmak için setActiveQueueItemId() yöntemini çağırın ve kuyrukta şu anda oynatılan öğenin kimliğini iletin. Kuyrukta değişiklik olduğunda setActiveQueueItemId() güncellemeniz gerekir.

Android Auto ve Android Automotive OS, etkinleştirilen her işlem için düğmelerin yanı sıra oynatma sırasını da gösterir. Düğmeler tıklandığında sistem, MediaSessionCompat.Callback içindeki ilgili geri çağırmayı başlatır.

Kullanılmayan alanı ayırma

Android Auto ve Android Automotive OS, kullanıcı arayüzünde ACTION_SKIP_TO_PREVIOUS ve ACTION_SKIP_TO_NEXT işlemleri için yer ayırır. Uygulamanız bu işlevlerden birini desteklemiyorsa Android Auto ve Android Automotive OS, oluşturduğunuz özel işlemleri göstermek için bu alanı kullanır.

Bu alanları özel işlemlerle doldurmak istemiyorsanız Android Auto ve Android Automotive OS'in, uygulamanız ilgili işlevi desteklemediğinde alanı boş bırakması için bu alanları ayırabilirsiniz. Bunu yapmak için, ayrılmış işlevlere karşılık gelen sabitleri içeren bir ekstralar paketiyle setExtras() yöntemini çağırın. SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, ACTION_SKIP_TO_NEXT'e, SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV ise ACTION_SKIP_TO_PREVIOUS'e karşılık gelir. Bu sabitleri pakette anahtar olarak, değerleri için ise boole true olarak kullanın.

İlk PlaybackState'i ayarlama

Android Auto ve Android Automotive OS, medya tarayıcı hizmetinizle iletişim kurarken medya oturumunuz, PlaybackStateCompat kullanarak içerik oynatma durumunu bildirir. Uygulamanız, Android Automotive OS veya Android Auto medya tarayıcı hizmetinize bağlandığında müziği otomatik olarak çalmaya başlamamalıdır. Bunun yerine, arabanın durumuna veya kullanıcı işlemlerine göre oynatmayı devam ettirmek ya da başlatmak için Android Auto ve Android Automotive OS'e güvenin.

Bunu yapmak için medya oturumunuzun ilk PlaybackStateCompat değerini STATE_STOPPED, STATE_PAUSED, STATE_NONE veya STATE_ERROR olarak ayarlayın.

Android Auto ve Android Automotive OS'teki medya oturumları yalnızca sürüş süresi boyunca devam eder. Bu nedenle kullanıcılar bu oturumları sık sık başlatır ve durdurur. Sürücüler arasında sorunsuz bir deneyim sağlamak için kullanıcının önceki oturum durumunu takip edin. Böylece, medya uygulaması devam ettirme isteği aldığında kullanıcı, kaldığı yerden (ör. son oynatılan medya öğesi, PlaybackStateCompat ve sıra) otomatik olarak devam edebilir.

Özel oynatma işlemleri ekleme

Medya uygulamanızın desteklediği ek işlemleri göstermek için özel oynatma işlemleri ekleyebilirsiniz. Alan izin veriyorsa (ve ayrılmamışsa) Android, özel işlemleri aktarım kontrollerine ekler. Aksi takdirde, özel işlemler taşma menüsünde gösterilir. Özel işlemler, PlaybackStateCompat hesabına eklendikleri sırayla gösterilir.

Standart işlemlerden farklı davranışlar sağlamak için özel işlemleri kullanın. Bunları standart işlemleri değiştirmek veya kopyalamak için kullanmayın.

PlaybackStateCompat.Builder sınıfındaki addCustomAction() yöntemini kullanarak özel işlemler ekleyebilirsiniz.

Aşağıdaki kod snippet'inde, özel bir "Radyo kanalı başlat" işleminin nasıl ekleneceği gösterilmektedir:

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

Bu yöntemle ilgili daha ayrıntılı bir örnek için GitHub'daki Universal Android Music Player örnek uygulamasında setCustomAction() yöntemine bakın.

Özel işleminizi oluşturduktan sonra medya oturumunuz, onCustomAction() yöntemini geçersiz kılarak işleme yanıt verebilir.

Aşağıdaki kod snippet'inde, uygulamanızın "Radyo kanalı başlat" işlemine nasıl yanıt verebileceği gösterilmektedir:

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

Bu yöntemle ilgili daha ayrıntılı bir örnek için GitHub'daki Universal Android Music Player örnek uygulamasında onCustomAction yöntemine bakın.

Özel işlemler için simgeler

Oluşturduğunuz her özel işlem için bir simge gerekir.

Bu simgenin açıklaması CommandButton.ICON_ sabitlerinden biriyle eşleşiyorsa özel işlemin ekstralarının EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT anahtarı için bu tam sayı değerini ayarlamanız gerekir. Desteklenen sistemlerde bu, CustomAction.Builder öğesine iletilen simge kaynağını geçersiz kılarak sistem bileşenlerinin işleminizi ve diğer oynatma işlemlerini tutarlı bir tarzda oluşturmasına olanak tanır.

Ayrıca bir simge kaynağı da belirtmeniz gerekir. Arabalardaki uygulamalar birçok farklı ekran boyutunda ve yoğunluğunda çalışabilir. Bu nedenle, sağladığınız simgeler vektör çizilebilir olmalıdır. Vektör çizilebilir öğeler, ayrıntıları kaybetmeden öğeleri ölçeklendirmenize olanak tanır. Vektör çizilebilir öğeler, daha düşük çözünürlüklerde kenar ve köşeleri piksel sınırlarıyla hizalamayı da kolaylaştırır.

Özel bir işlem durum bilgiliyse (ör. oynatma ayarını açıp kapatıyorsa) farklı durumlar için farklı simgeler sağlayın. Böylece kullanıcılar işlemi seçtiklerinde bir değişiklik görebilir.

Devre dışı bırakılan işlemler için alternatif simge stilleri sağlama

Özel işlem geçerli bağlamda kullanılamıyorsa özel işlem simgesini, işlemin devre dışı olduğunu gösteren alternatif bir simgeyle değiştirin.

6.şekil Stil dışı özel işlem simgeleri örnekleri.

Ses biçimini belirtme

Şu anda oynatılan medyanın özel bir ses biçimi kullandığını belirtmek için bu özelliği destekleyen arabalarda oluşturulan simgeleri belirtebilirsiniz. Şu anda oynatılan medya öğesinin ekstralar paketinde (MediaSession.setMetadata()'a iletilir) KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI ve KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI değerlerini ayarlayabilirsiniz. Farklı düzenlere uyum sağlamak için bu ekstraların ikisini de ayarladığınızdan emin olun.

Ayrıca, KEY_IMMERSIVE_AUDIO ekstrasını ayarlayarak otomobil üreticilerine bunun sarmal ses olduğunu ve sarmal içerikle etkileşime girebilecek ses efektleri uygulayıp uygulamayacaklarına karar verirken çok dikkatli olmaları gerektiğini söyleyebilirsiniz.

Şu anda oynatılan medya öğesini, altyazısı, açıklaması veya her ikisi de diğer medya öğelerine bağlantı verecek şekilde yapılandırabilirsiniz. Bu sayede kullanıcı, ilgili öğelere hızlıca gidebilir. Örneğin, aynı sanatçının diğer şarkılarına veya söz konusu podcast'in diğer bölümlerine gidebilir. Araba bu özelliği destekliyorsa kullanıcılar bağlantıya dokunarak bu içeriğe göz atabilir.

Bağlantı eklemek için KEY_SUBTITLE_LINK_MEDIA_ID meta verilerini (altyazıdan bağlantı oluşturmak için) veya KEY_DESCRIPTION_LINK_MEDIA_ID meta verilerini (açıklamadan bağlantı oluşturmak için) yapılandırın. Ayrıntılar için bu meta veri alanlarının referans belgelerine bakın.

Sesli işlemleri destekleme

Sürücülere güvenli ve rahat bir deneyim sunmak için medya uygulamanızın sesli işlemleri desteklemesi gerekir. Bu sayede sürücülerin dikkati dağılmaz. Örneğin, uygulamanız bir medya öğesi oynatırken kullanıcı, arabanın ekranına bakmadan veya dokunmadan farklı bir şarkı çalmasını istemek için"[Şarkı adını]çal" diyebilir. Kullanıcılar, direksiyonlarındaki uygun düğmeleri tıklayarak veya "Ok Google" etkinleştirme kelimelerini söyleyerek sorgu başlatabilir.

Android Auto veya Android Automotive OS bir sesli işlemi algılayıp yorumladığında bu sesli işlem, onPlayFromSearch() üzerinden uygulamaya iletilir. Bu geri çağırma alındığında uygulama, query dizesiyle eşleşen içeriği bulur ve oynatmaya başlar.

Kullanıcılar sorgularında farklı terim kategorileri (ör. tür, sanatçı, albüm, şarkı adı, radyo istasyonu veya şarkı listesi) belirtebilir. Arama desteği oluştururken uygulamanız için anlamlı olan tüm kategorileri hesaba katın. Android Auto veya Android Automotive OS, belirli bir sorgunun belirli kategorilere uygun olduğunu algılarsa extras parametresine ek bilgiler ekler. Aşağıdaki ekler gönderilebilir:

Kullanıcı arama terimlerini belirtmezse Android Auto veya Android Automotive OS tarafından gönderilebilen boş query dizesini hesaba katın. Örneğin, kullanıcı "Müzik çal" derse. Bu durumda uygulamanız, kısa süre önce çalınan veya yeni önerilen bir parçayı başlatmayı tercih edebilir.

Bir arama hızlıca işlenemiyorsa onPlayFromSearch() içinde engellemeyin. Bunun yerine, oynatma durumunu STATE_CONNECTING olarak ayarlayın ve aramayı eşzamansız bir iş parçacığında gerçekleştirin.

Oynatma başladıktan sonra medya oturumunun sırasını ilgili içeriklerle doldurabilirsiniz. Örneğin, kullanıcı bir albümün çalınmasını isterse uygulamanız sırayı albümün parça listesiyle doldurabilir. Ayrıca, kullanıcının sorgusuyla eşleşen farklı bir parça seçebilmesi için göz atılabilir arama sonuçları desteğini uygulamayı da düşünebilirsiniz.

Android Auto ve Android Automotive OS, "oynat" sorgularının yanı sıra "müziği duraklat" ve "sonraki şarkı" gibi oynatmayı kontrol etmeye yönelik sesli sorguları da tanır ve bu komutları onPause() ve onSkipToNext() gibi uygun medya oturumu geri çağırmalarıyla eşleştirir.

Uygulamanızda sesli oynatma işlemlerini nasıl uygulayacağınızla ilgili ayrıntılı bir örnek için Google Asistan ve medya uygulamaları başlıklı makaleyi inceleyin.

Dikkat dağıtıcı unsurlara karşı koruma önlemleri uygulama

Android Auto kullanılırken kullanıcının telefonu aracının hoparlörlerine bağlı olduğundan sürücünün dikkatini dağıtmasını önlemek için ek önlemler almanız gerekir.

Araçtaki alarmları kapatma

Android Auto medya uygulamaları, kullanıcı oynatma düğmesine basarak oynatmayı başlatmadığı sürece arabanın hoparlörlerinden ses çalmaya başlamamalıdır. Medya uygulamanızdan kullanıcı tarafından planlanan bir alarm bile arabanın hoparlörlerinden müzik çalmaya başlamamalıdır.

Bu şartı karşılamak için uygulamanız, ses çalmadan önce sinyal olarak CarConnection kullanabilir. Uygulamanız, araba bağlantı türü için LiveData gözlemlenerek ve CONNECTION_TYPE_PROJECTION değerine eşit olup olmadığı kontrol edilerek telefonun araba ekranına yansıtılıp yansıtılmadığını kontrol edebilir.

Kullanıcının telefonu projeksiyon yapıyorsa alarmları destekleyen medya uygulamaları aşağıdakilerden birini yapmalıdır:

  • Alarmı devre dışı bırakın.
  • Alarmı STREAM_ALARM üzerinden çalın ve alarmı devre dışı bırakmak için telefon ekranında bir kullanıcı arayüzü sağlayın.

Medya reklamlarını işleme

Android Auto, varsayılan olarak ses oynatma oturumu sırasında medya meta verileri değiştiğinde bildirim gösterir. Bir medya uygulaması müzik çalmaktan reklam yayınlamaya geçtiğinde kullanıcıya bildirim göstermek dikkat dağıtıcı olur. Android Auto'nun bu durumda bildirim göstermesini önlemek için medya meta verileri anahtarını METADATA_KEY_IS_ADVERTISEMENT aşağıdaki kod snippet'inde gösterildiği gibi METADATA_VALUE_ATTRIBUTE_PRESENT olarak ayarlamanız gerekir:

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

Genel hataları işleme

Uygulamada bir hata oluştuğunda oynatma durumunu STATE_ERROR olarak ayarlayın ve setErrorMessage() yöntemini kullanarak bir hata mesajı sağlayın. Hata mesajını ayarlarken kullanabileceğiniz hata kodlarının listesi için PlaybackStateCompat başlıklı makaleyi inceleyin. Hata mesajları kullanıcıya yönelik olmalı ve kullanıcının mevcut yerel ayarına göre yerelleştirilmelidir. Android Auto ve Android Automotive OS, hata mesajını kullanıcıya gösterebilir.

Örneğin, içerik kullanıcının bulunduğu bölgede kullanılamıyorsa hata mesajını ayarlarken ERROR_CODE_NOT_AVAILABLE_IN_REGION hata kodunu kullanabilirsiniz.

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

Hata durumları hakkında daha fazla bilgi için Medya oturumu kullanma: Durumlar ve hatalar başlıklı makaleyi inceleyin.

Bir Android Auto kullanıcısının hatayı çözmek için telefon uygulamanızı açması gerekiyorsa mesajınızda bu bilgiyi kullanıcıya iletin. Örneğin, hata mesajınızda "Lütfen oturum açın" yerine "[Uygulama adınız] uygulamasında oturum açın" yazabilir.

Diğer kaynaklar