Android Auto ve Android Automotive OS, medya uygulaması içeriğinizi arabadaki kullanıcılara sunmanıza yardımcı olur. Android Auto ve Android Automotive OS'in ya da medya tarayıcısı olan başka bir uygulamanın içeriğinizi bulup görüntüleyebilmesi için arabalar için medya uygulaması bir medya tarayıcısı hizmeti sağlamalıdır.
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ılmıştır.
Bu kılavuzda, Android Auto veya Android Automotive OS'te çalışması için uygulamanızın ihtiyaç duyduğu MediaBrowserService
ve MediaSession
bileşenleri açıklanmaktadır. Temel medya altyapısını tamamladıktan sonra medya uygulamanıza Android Auto desteği ekleyebilir ve Android Automotive OS desteği ekleyebilirsiniz.
Başlamadan önce
- Android Media API belgelerini inceleyin.
- Tasarımla ilgili bilgi edinmek için Medya uygulamaları oluşturma başlıklı makaleyi inceleyin.
- 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'ye uygun bir Android hizmeti. Uygulamanız, içeriğini göstermek için bu hizmeti kullanıyor. - Medya tarayıcısı
- Medya uygulamaları tarafından medya tarayıcı hizmetlerini keşfetmek ve içeriklerini görüntülemek için kullanılan bir API. Android Auto ve Android Automotive OS, uygulamanızın medya tarayıcısı hizmetini bulmak için medya tarayıcısı kullanır.
- Medya öğesi
Medya tarayıcısı, içeriğini
MediaItem
öğelerinden oluşan bir ağaçta düzenler. Bir medya öğesinde aşağıdaki işaretlerden biri veya her ikisi de bulunabilir:FLAG_PLAYABLE
: Öğenin içerik ağacında yaprak olduğunu belirtir. Öğe, albümdeki bir şarkı, sesli kitaptaki bir bölüm veya podcast bölümünün 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 belirtir. Örneğin, öğe bir albümü temsil eder ve alt öğeleri albümdeki şarkılardır.
Hem göz atılabilir hem de oynatılabilir olan medya öğeleri oynatma listesi gibi çalışır. Öğenin kendisini seçerek tüm alt öğelerini oynatabilir veya çocuklarına göz atabilirsiniz.
- Araç için optimize edilmiş
Android Automotive OS tasarım yönergelerine uygun bir Android Automotive OS uygulaması için etkinlik. Bu etkinliklerin arayüzü Android Automotive OS tarafından çizilmediğinden, uygulamanızın tasarım yönergelerine uyduğundan emin olmanız gerekir. Genellikle bu, daha büyük dokunma hedefleri ve yazı tipi boyutları, gündüz ve gece modları desteği ve daha yüksek kontrast oranları içerir.
Araç için optimize edilmiş kullanıcı arayüzlerinin yalnızca Araç Kullanıcı Deneyimi Kısıtlamaları (CUXR'ler) geçerli olmadığında gösterilmesine izin verilir. Bu arayüzler, kullanıcının uzun süreli dikkatini veya etkileşimini gerektirebilir. CUXR'ler, araç durduğunda veya park edildiğinde geçerli değildir ancak araç hareket halindeyken her zaman geçerlidir.
Android Auto, medya tarayıcısı hizmetinizdeki bilgileri kullanarak kendi araca özel arayüzünü çizdiği için Android Auto için etkinlik tasarlamanıza gerek yoktur.
Uygulamanızın manifest dosyalarını yapılandırma
Medya tarayıcısı 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ısı hizmetiniz aracılığıyla uygulamanıza bağlanır. Android Auto ve Android Automotive OS'in hizmeti keşfetmesine ve uygulamanıza bağlanmasına izin vermek için medya tarayıcısı hizmetinizi manifest dosyanızda beyan edin.
Aşağıdaki kod snippet'inde, medya tarayıcısı hizmetinizi manifest dosyanızda nasıl beyan edeceğiniz gösterilmektedir. Bu kodu Android Automotive OS modülünüzün 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, sistem kullanıcı arayüzünde (ör. başlatıcıda ve simge tepsisinde) uygulamanızı 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ızdan farklı bir simge kullanmak için manifest dosyasında medya tarayıcısı hizmetinizin <service>
öğesinde android:icon
mülkünü ayarlayın:
<application>
...
<service
...
android:icon="@mipmap/auto_launcher"
...
/>
</application>
İlişkilendirme simgesi
İlişkilendirme 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 beyanını 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. Böylece hem Android Auto hem de Android Automotive OS, hizmetinizi kullanarak aşağıdakileri 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
sınıfı nesnesinin jetonunu alın.
Diğer istemcilerin uygulamanızdaki medya içeriğine erişmesini sağlamak için medya tarayıcısı hizmetinizi de kullanabilirsiniz. Bu medya istemcileri, bir kullanıcının telefonundaki başka uygulamalar veya başka uzak istemciler olabilir.
Medya tarayıcısı 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ısı hizmetinizle nasıl etkileşime geçtiği açıklanmaktadır.
- Kullanıcı, uygulamanızı Android Automotive OS veya Android Auto'da başlatır.
- Android Automotive OS veya Android Auto,
onCreate()
yöntemini kullanarak uygulamanızın medya tarayıcısı hizmetiyle iletişim kurar.onCreate()
yöntemini uygularken birMediaSessionCompat
nesnesi ve geri çağırma nesnesi oluşturup kaydetmeniz gerekir. - 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. - Android Automotive OS veya Android Auto, kök medya öğesinin alt öğelerini almak için hizmetinizin
onLoadChildren()
yöntemini çağırır. Android Automotive OS ve Android Auto, bu medya öğelerini içerik öğelerinin üst düzeyi olarak 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. - Kullanıcı, göz atılabilir bir medya öğesi seçerse seçilen menü öğesinin alt öğelerini almak için hizmetinizin yöntemi tekrar çağrılır.
onLoadChildren()
- 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.
- Uygulamanız destekliyorsa kullanıcı da içeriğinizi 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 mevcut olduğunu öğrenmek için uygulamanızın medya tarayıcısı hizmetini çağırır. Medya tarayıcısı hizmetinizde bunu desteklemek için
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çeriğinizin 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öntemin daha ayrıntılı bir örneği için GitHub'daki Universal Android Music Player örnek uygulamasında yer alan onGetRoot()
yöntemine bakın.
onGetRoot() için paket doğrulaması ekleme
Hizmetinizin onGetRoot()
yöntemiyle bir arama yapıldığında, arayan paketi kimlik bilgilerini hizmetinize iletir. Hizmetiniz, bu paketin içeriğinize erişip erişemeyeceğine karar vermek için bu bilgileri kullanabilir. Örneğin, clientPackageName
öğesini 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ış paketler listesine kısıtlayabilirsiniz. Paket doğrulanamıyorsa içeriğinize erişimi reddetmek için null
değerini döndürün.
Android Auto ve Android Automotive OS gibi sistem uygulamalarının içeriğinize erişmesini sağlamak için bu sistem uygulamaları onGetRoot()
yöntemini çağırdığında hizmetiniz her zaman boş olmayan bir BrowserRoot
değeri döndürmelidir. Android Automotive OS sistem uygulamasının imzası, aracın markasına ve modeline göre değişiklik gösterebilir. 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'i, hizmetinizin çağrı paketinin bir sistem uygulaması olduğunu nasıl doğrulayabileceğini gösterir:
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ındaki PackageValidator
sınıfından alınmıştır. Hizmetinizin onGetRoot()
yöntemi için paket doğrulamasının nasıl uygulanacağına dair 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 izin vermeniz gerekir. Google Asistan'ın, Android Auto'yu içeren telefon ve Android Automotive OS için ayrı paket adlarına sahip 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
nesnesi ile temsil edilir. Bu medya öğelerinin her biri benzersiz bir kimlik dizesiyle tanımlanır. İstemci uygulamaları bu kimlik dizelerini opak jetonlar olarak işler. Bir istemci uygulaması bir alt menüye göz atmak veya bir medya öğesini oynatmak istediğinde jetonu iletir. Jetonu uygun medya öğesiyle ilişkilendirmek uygulamanızın sorumluluğundadır.
Aşağıdaki kod snippet'i, onLoadChildren()
yönteminin basit bir uygulamasını gösterir:
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 tam örneği için GitHub'daki Universal Android Music Player örnek uygulamasındaki onLoadChildren()
yöntemine bakın.
Kök menüyü yapılandırma
Android Auto ve Android Automotive OS, kök menünün yapısıyla ilgili belirli kısıtlamalara sahiptir. Bunlar MediaBrowserService
ürününe kök ipuçları aracılığıyla iletilir. Bu ipuçları, onGetRoot()
ürününe iletilen Bundle
bağımsız değişkeni aracılığıyla okunabilir.
Bu ipuçlarının uygulanması, sistemin kök içeriği gezinme sekmeleri olarak en iyi şekilde görüntüleyebilmesini sağlar. Bu ipuçlarına uymazsanız bazı kök içerikler kaldırılabilir veya sistem tarafından daha az bulunabilir hale getirilebilir. İki ipucu gönderilir:
- Kök alt öğe sayısıyla ilgili sınır: Genellikle bu sayı dörttür. Bu nedenle, dörtten fazla sekme gösterilemez.
- Kök alt öğelerde desteklenen işaretler: Bu değerin
MediaItem#FLAG_BROWSABLE
olmasını bekleyebilirsiniz. Bu, oynatılabilir öğeler değil, yalnızca göz atılabilir öğelerin sekme olarak gösterilebileceği anlamına gelir.
Alakalı 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 değişiyorsa içerik hiyerarşinizin yapısı için mantığı bu ipuçlarının değerlerine göre dallandırmayı seçebilirsiniz.
Örneğin, normalde kök oynatılabilir bir öğe gösteriyorsanız desteklenen flag'ler ipucundan dolayı bunun yerine kök göz atılabilir bir öğenin altına iç içe yerleştirmek isteyebilirsiniz.
Kök ipuçlarının yanı sıra, sekmelerin en iyi şekilde oluşturulmasını sağlamak için uyulması gereken birkaç ek yönerge vardır:
- Her sekme öğesi için tek renkli ve tercihen beyaz simgeler sağlayın.
- Her sekme öğesi için kısa ancak anlamlı etiketler girin. Etiketleri kısa tutmak, dizelerin kesilme olasılığını azaltır.
Medya posterini göster
Medya öğelerinin posteri, ContentResolver.SCHEME_CONTENT
veya ContentResolver.SCHEME_ANDROID_RESOURCE
kullanılarak yerel bir URI olarak iletilmelidir.
Bu yerel URI, uygulamanın kaynaklarında bir bit eşleme veya vektör çizilebilir öğeye yönlendirmelidir. İç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 birini kullanarak putString()
üzerinden iletin:
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI
MediaMetadataCompat.METADATA_KEY_ART_URI
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI
Aşağıdaki adımlarda, bir web URI'sinden posterin nasıl indirileceği ve yerel bir URI üzerinden nasıl gösterileceği açıklanmaktadır. Daha kapsamlı bir örnek için Universal Android Music Player örnek uygulamasında openFile()
ve ilgili yöntemlerin uygulamasına bakın.
Web URI'sine karşılık gelen bir
content://
URI oluşturun. Medya tarayıcısı 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(); }
ContentProvider.openFile()
uygulamanızda, ilgili URI için bir dosya olup olmadığını kontrol edin. Aksi takdirde resim dosyasını indirip önbelleğe alın. Aşağıdaki kod snippet'i Glide'ı kullanır.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österileceğini belirleyen içerik stilleri uygulayabilirsiniz.
Aşağıdaki içerik stillerini kullanabilirsiniz:
- Liste öğeleri
-
Bu içerik stilinde, resimlere kıyasla başlıklar ve meta verilere öncelik verilir.
- Izgara öğeleri
-
Bu içerik stilinde, resimlere başlıklar ve meta verilere göre öncelik verilir.
Varsayılan içerik stillerini ayarlama
Hizmetinizin onGetRoot()
yöntemindeki BrowserRoot
ekstra paketine belirli sabit değerleri ekleyerek medya öğelerinizin nasıl görüntüleneceği için genel varsayılan ayarlar belirleyebilirsiniz. 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:
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: Göz atma ağacındaki tüm göz atılabilir öğeler için bir sunum ipucunu gösterir.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: Göz atma ağacındaki tüm oynanabilir öğeler için bir sunum ipucunu gösterir.
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 sıradan liste öğeleriyle aynıdır. Tek fark, simgeler küçük olduğunda daha iyi göründükleri için kenar boşluklarının öğelerin simgelerinin etrafına uygulanmasıdır. Simgelerin tonlanabilir 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, simgeler küçükken daha iyi göründüğü için simgelerin etrafına kenar boşlukları uygulanması dışında normal tablo öğeleriyle aynıdır. Simgeler, boyanabilir drawable vektörler olmalıdır. Bu ipucunun yalnızca göz atılabilir öğeler için sağlanması beklenir.
Aşağıdaki kod snippet'inde, taranabilir öğeler için varsayılan içerik stilinin ızgaralar, oynatılabilir öğeler için de listeler 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 stillerini ayarlayın
Content Style API, herhangi bir medya öğesinin kendisi ve herhangi bir göz atılabilir medya öğesinin alt öğeleri için varsayılan içerik stilini geçersiz kılmanıza olanak tanır.
Göz atılabilir medya öğesinin alt öğeleri için varsayılanı geçersiz kılmak için medya öğesinin MediaDescription
öğesinde ekstra paketi oluşturun ve daha önce bahsedilen ipuçlarını ekleyin. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
, söz konusu öğenin oynanabilir alt öğeleri için geçerlidir. DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
ise söz konusu öğenin taranabilir alt öğeleri için geçerlidir.
Belirli bir medya öğesinin alt öğeleri için değil, kendisi için varsayılanı geçersiz kılmak isterseniz medya öğesinin MediaDescription
öğesinde bir ekstra 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 kendi hem de alt öğelerinin varsayılan içerik stilini geçersiz kılan, göz atılabilir bir MediaItem
öğesinin nasıl oluşturulacağı gösterilmektedir. Kendisini bir kategori listesi öğ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); }
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 öğesinin MediaDescription
öğesinde, DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE
anahtarına ve aynı dize değerine sahip bir eşleme içeren bir ekstralar paketi tanımlaması gerekir. Grubun başlığı olarak kullanılan bu dizeyi yerelleştirin.
Aşağıdaki kod snippet'inde, "Songs"
alt grup başlıklı 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, birlikte gruplandırmak istediğiniz tüm medya öğelerini bitişik bir blok olarak iletmelidir. Örneğin, "Şarkılar" ve "Albümler" adlı iki medya öğesi grubunu bu sırayla görüntülemek istediğinizi ve uygulamanızın beş medya öğesini aşağıdaki sırayla ilettiğini varsayalım:
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
içeren A medya öğesiextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
içeren medya öğesi Bextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
içeren medya öğesi Cextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
ile medya öğesi Dextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
içeren E medya öğesi
"Şarkılar" grubu ve "Albümler" grubunun medya öğeleri bitişik bloklar halinde tutulmadığından, Android Auto ve Android Automotive OS bunu aşağıdaki dört grup olarak yorumlar:
- A medya öğesini içeren "Şarkılar" adlı 1. grup
- B medya öğesini içeren "Albümler" adlı 2. grup
- C ve D medya öğelerini içeren "Şarkılar" adlı 3. grup
- E medya öğesini içeren "Albümler" adlı 4. Grup
Bu öğeleri iki grupta görüntülemek için uygulamanızın medya öğelerini aşağıdaki sırayla iletmesi gerekir:
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
içeren A medya öğesiextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
içeren C medya öğesiextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
ile medya öğesi Dextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
içeren B medya öğesiextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
içeren E medya öğesi
Ek meta veri göstergelerini göster
Medya tarayıcısı ağacındaki ve oynatma sırasındaki içerik için bir bakışta bilgi sağlamak üzere ek meta veri göstergeleri ekleyebilirsiniz. Android Auto ve Android Automotive OS, göz atma ağacında bir öğeyle ilişkili ekstraları okur ve hangi göstergelerin gösterileceğini belirlemek için belirli sabitleri arar. Android Auto ve Android Automotive OS, medya oynatma sırasında medya oturumunun meta verilerini okur ve gösterilecek göstergeleri belirlemek için belirli sabitler arar.
Aşağıdaki sabitler MediaItem
açıklama ekstralarında ve MediaMetadata
ekstralarında hem kullanılabilir:
EXTRA_DOWNLOAD_STATUS
: Bir öğenin indirme durumunu gösterir. Anahtar olarak bu sabit değeri kullanın. Aşağıdaki uzun sabitler olası değerlerdir:STATUS_DOWNLOADED
: öğe tamamen indirilmiştir.STATUS_DOWNLOADING
: Öğe indiriliyor.STATUS_NOT_DOWNLOADED
: Öğe indirilmez.
METADATA_KEY_IS_EXPLICIT
: Öğenin uygunsuz içerik barındırıp barındırmadığını gösterir. Bir öğenin uygunsuz olduğunu belirtmek için anahtar olarak bu sabit değeri, değer olarak da uzunMETADATA_VALUE_ATTRIBUTE_PRESENT
değerini kullanın.
Aşağıdaki sabitler yalnızca MediaItem
açıklama ekstralarında kullanılabilir:
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
: Podcast bölümleri veya sesli kitaplar gibi uzun içeriklerin tamamlanma durumunu gösterir. Anahtar olarak bu sabit değeri kullanın. Olası değerler aşağıdaki tam sayı sabitleridir:DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: Öğe hiç oynatılmamıştır.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: Öğe kısmen oynatılmış ve mevcut konum ortada bir yerdedir.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: Öğe tamamlanmıştır.
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: Uzun içeriklerdeki tamamlanma ilerleme durumunu 0,0 ile 1,0 arasında (bu değerler dahil) iki kat olarak gösterir. Bu ek, Android Auto veya Android Automotive OS'in ilerleme çubuğu gibi daha anlamlı bir ilerleme göstergesi göstermesi içinPARTIALLY_PLAYING
durumu hakkında daha fazla bilgi sağlar. Bu ekstrayı kullanıyorsanız bu göstergeyi ilk gösterimden sonra nasıl güncel tutacağınızı öğrenmek için bu kılavuzdaki içerik oynatılırken göz atma görünümündeki ilerleme çubuğunu güncelleme bölümüne bakın.
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 en az birini içeren bir ekstralar paketi oluşturun ve bu paketi MediaDescription.Builder.setExtras()
yöntemine iletin.
Aşağıdaki kod snippet'i, %70 tamamlanmış uygunsuz bir medya öğesi için göstergelerin nasıl görüntüleneceğini gösterir:
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 öğesinin göstergelerini görüntülemek için mediaSession
öğenizin MediaMetadataCompat
alanında METADATA_KEY_IS_EXPLICIT
veya EXTRA_DOWNLOAD_STATUS
için Long
değerlerini belirtebilirsiniz. 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'i, oynatma görünümündeki mevcut şarkının uygunsuz ve indirilmiş olduğunu nasıl belirteceğinizi gösterir:
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üncelleyin
Daha önce de belirtildiği gibi, göz atma görünümünde kısmen oynatılan içerik için bir ilerleme çubuğu göstermek üzere DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
ek öğesini kullanabilirsiniz. Ancak kullanıcı, kısmen oynatılan içeriği Android Auto veya Android Automotive OS'ten oynatmaya devam ederse bu gösterge zaman geçtikçe yanlış olur.
Android Auto ve Android Automotive OS'in ilerleme çubuğunu güncel tutması için devam eden içeriği, göz atma görünümündeki medya öğelerine bağlamak üzere MediaMetadataCompat
ve PlaybackStateCompat
öğelerinde ek bilgiler sağlayabilirsiniz. Medya öğesinin otomatik olarak güncellenen bir ilerleme çubuğu olması için aşağıdaki koşulların karşılanması gerekir:
- Oluşturulduğunda
MediaItem
, eklerindeDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
değerini 0,0 ile 1,0 arasında (bu değerler dahil) göndermelidir. MediaMetadataCompat
,MediaItem
'ye iletilen medya kimliğine eşit bir dize değeriyleMETADATA_KEY_MEDIA_ID
göndermelidir.PlaybackStateCompat
,MediaItem
'ye iletilen medya kimliğine eşit bir dize değeriyle eşleşenPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
anahtarına sahip bir ekstra içermelidir.
Aşağıdaki kod snippet'inde, şu anda oynatılan öğenin göz atma görünümündeki bir öğeye bağlı olduğunun nasıl belirtileceği 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());
Göz atılabilir arama sonuçlarını göster
Uygulamanız, kullanıcılar arama sorgusu başlattığında onlara gösterilecek bağlama dayalı 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 göre değişen olanaklar aracılığıyla gösterir. Daha fazla bilgi edinmek için bu kılavuzdaki Sesli işlemleri destekle bölümüne bakın.
Göz atılabilir arama sonuçlarını görüntülemek için hizmetinizin onGetRoot()
yöntemindeki ekstralar paketine BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
sabit anahtarını dahil edin ve true
boole değeriyle eşleyin.
Aşağıdaki kod snippet'i, onGetRoot()
yönteminde desteğin nasıl etkinleştirileceğini gösterir:
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ı sunmaya başlamak için medya tarayıcısı hizmetinizde onSearch()
yöntemini geçersiz kılın. Android Auto ve Android Automotive OS, kullanıcı bir arama sorgusu arayüzü veya "Arama sonuçları" olanağı çağrıldığında kullanıcının arama terimlerini bu yönteme yönlendirir.
Arama sonuçlarını, daha göz atılabilir hale getirmek için başlık öğelerini kullanarak hizmetinizin onSearch()
yönteminden düzenleyebilirsiniz. Örneğin, uygulamanızda müzik çalıyorsa arama sonuçlarını
albüme, sanatçıya ve şarkılara 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
Özel Göz Atma İşlemleri, arabanın medya uygulamasındaki MediaItem
nesnelerine özel simgeler ve etiketler eklemenize ve bu işlemlerle kullanıcı etkileşimlerini yönetmenize olanak tanır. Bu sayede, "İndir", "Sıraya ekle", "Radyo oynat", "Favori" veya "Kaldır" gibi işlemler ekleyerek medya uygulamasının işlevini çeşitli şekillerde genişletebilirsiniz.
OEM'nin gösterilmesine izin verdiğinden daha fazla özel işlem varsa kullanıcıya bir taşma menüsü sunulur.
İşleyiş şekli nasıldır?
Her bir Özel Göz Atma İşlemi şunlarla tanımlanır:
- İşlem kimliği (benzersiz bir dize tanımlayıcısı)
- İşlem etiketi (kullanıcıya gösterilen metin)
- İşlem Simgesi URI'si (Tonlama uygulanabilen bir çekilebilir vektör)
BrowseRoot
öğenizin bir parçası olarak, özel göz atma işlemlerinin listesini global olarak tanımlarsınız. Ardından, bu işlemlerin bir alt kümesini ayrı ayrı öğelere ekleyebilirsiniz.
MediaItem.
Bir kullanıcı özel bir göz atma işlemiyle etkileşime geçtiğinde 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, "Favori" ve "İndir" gibi durum bilgisine sahip işlemler için kullanışlıdır. "Radyoyu Çal" gibi güncellenmesi gerekmeyen
işlemler için işlem listesini güncellemeniz gerekmez.
Özel göz atma işlemlerini bir göz atma düğümü köküne de ekleyebilirsiniz. Bu işlemler, ana araç çubuğunun altındaki ikincil araç çubuğunda gösterilir.
Özel Göz Atma İşlemleri nasıl uygulanır?
Projenize özel göz atma işlemleri eklemek için aşağıdaki adımları uygulayın:
MediaBrowserServiceCompat
uygulamanızda iki yöntemi geçersiz kılın:- İşlem sınırlarını çalışma zamanında ayrıştırın:
onGetRoot()
içinde,rootHints
Bundle
içindekiBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
anahtarını kullanarak herMediaItem
için izin verilen maksimum işlem sayısını alın. 0 sınırı, özelliğin sistem tarafından desteklenmediğini belirtir.
- Özel Göz Atma İşlemlerinin küresel 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şlemBundle
nesnelerini bir listeye ekleyin.
- Her işlem için aşağıdaki anahtarlara sahip bir
- Genel listeyi
BrowseRoot
cihazınıza ekleyin:BrowseRoot
EkstralarBundle
bölümünde,BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
anahtarını kullanarak işlem listesiniParcelable
Arraylist
olarak ekleyin.
MediaItem
nesnelerinize işlem ekleyin:DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST
anahtarını kullanarakMediaDescriptionCompat
ekstralarındaki işlem kimliklerinin listesini dahil ederek bağımsızMediaItem
nesnelerine işlem ekleyebilirsiniz. Bu liste,BrowseRoot
içinde tanımladığınız genel işlem listesinin bir alt kümesi olmalıdır.
- İşlemleri yönetme ve ilerleme durumunu veya sonuçları döndürme:
onCustomAction
içinde, işlem kimliğine ve ihtiyacınız olan diğer verilere göre işlemi yönetin. İşlemi tetikleyenMediaItem
öğesinin kimliğiniEXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
anahtarını kullanarak ekstralardan öğrenebilirsiniz.- İlerleme veya sonuç grubuna
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
anahtarını ekleyerek birMediaItem
için işlem listesini güncelleyebilirsiniz.
Özel Göz Atma İşlemleri'ni kullanmaya başlamak için BrowserServiceCompat
üzerinde yapabileceğiniz
değişikliklerden bazılarını aşağıda bulabilirsiniz.
BrowserServiceCompat'i geçersiz kılma
MediaBrowserServiceCompat
ürününde aşağıdaki yöntemleri geçersiz kılmanız gerekiyor.
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ç tane Özel Göz Atma İş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 bir göz atma işlemi oluşturma
Her işlemin ayrı bir Bundle
içine paketlenmesi gerekir.
- İş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 İşlemleri Ekleme
Tüm Özel Göz Atma İşlemi Bundle
nesnelerini bir ArrayList
öğesine 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 İşlemi listesi ekleyin
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
'ye 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);
onCustomAction
sonucunu derle
Bundle extras
kaynağından 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); }
- Asenkron 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üncelle(bir öğedeki işlemleri güncellemek için kullanın)
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üncelle
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- Kullanıcıya mesaj
- Hata oluşursa
result.sendError(resultBundle).
numaralı telefonu arayın - İlerleme durumu güncellenirse
result.sendProgressUpdate(resultBundle)
numaralı telefonu arayın. result.sendResult(resultBundle)
'ü arayarak sonlandırın.
İşlem Durumunu Güncelle
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
anahtarıyla result.sendProgressUpdate(resultBundle)
yöntemini kullanarak MediaItem
öğesini işlemin yeni durumunu yansıtacak şekilde güncelleyebilirsiniz. Bu sayede kullanıcıya ilerleme ve yaptığı işlemin sonucu hakkında anlık geri bildirim verebilirsiniz.
Örnek: İndirme İşlemi
Aşağıda, üç durumu olan bir indirme işlemini uygulamak için bu özelliği nasıl kullanabileceğinize dair bir örnek verilmiştir:
- İndir: İş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. - İndiriliyor: Bu durum, indirme işleminin devam ettiğini gösterir. Kullanıcıya bir ilerleme çubuğu veya başka bir gösterge göstermek için bu durumu kullanabilirsiniz.
- İndirilen: Bu durum, indirme işleminin tamamlandığını gösterir. İndirme işlemi tamamlandığında, "İndiriliyor"u "İndirildi" ile değiştirebilir ve öğenin yenilenmesi gerektiğini belirtmek için
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
tuşuylasendResult
'ü çağırabilirsiniz. Ayrıca kullanıcıya başarı mesajı göstermek içinEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
tuşunu kullanabilirsiniz.
Bu yaklaşım, kullanıcıya indirme işlemi ve mevcut durumu hakkında net geri bildirim sağlamanıza olanak tanır. İndirme durumlarını (%25, %50, %75) simgelerle göstererek daha da fazla ayrıntı ekleyebilirsiniz.
Örnek: Favori İşlem
İki durumu olan bir favori işlem de örnek verilebilir:
- Favori: Bu işlem, kullanıcının favoriler listesinde bulunmayan öğeler için gösterilir. Kullanıcı bu işlemi seçtiğinde "Favorilere eklendi" ile değiştirebilir ve kullanıcı arayüzünü güncellemek için
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
tuşuylasendResult
işlevini çağırabilirsiniz. - Favorilere eklendi: Bu işlem, kullanıcının favoriler listesindeki öğeler için görüntülenir. Kullanıcı bu işlemi seçtiğinde, kullanıcı arayüzünü güncellemek için işlemi "Favori" ile değiştirebilir ve
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
tuşuylasendResult
öğesini çağırabilirsiniz.
Bu yaklaşım, kullanıcıların favori öğelerini yönetmeleri için net ve tutarlı bir yol sunar.
Bu örnekler, Özel Göz Atma İşlemleri'nin esnekliğini ve arabanın medya uygulamasında gelişmiş bir kullanıcı deneyimi için gerçek zamanlı geri bildirimle çeşitli işlevleri uygulamak üzere nasıl kullanabileceğinizi gösterir.
Bu özelliğin tam bir örnek uygulaması için TestMediaApp
projesine göz atabilirsiniz.
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 arama yöntemlerini uygulamanız gerekir.
Medya oturumu kaydetme
Medya tarayıcısı hizmetinizin onCreate()
yönteminde bir MediaSessionCompat
oluşturun, ardından setSessionToken()
'i ç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ısı hizmetinden elde ettiği uygulamanızın MediaSessionCompat
nesnesinden MediaSessionCompat.Callback
sınıfını kullanır. Kullanıcı, oynatma işlemini duraklatma veya sonraki parçaya atlama gibi içerik oynatma işlemlerini kontrol etmek 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ın soyut MediaSessionCompat.Callback
sınıfını genişletmesi ve desteklediği yöntemleri uygulaması gerekir.
Uygulamanızın sunduğu içerik türü için uygun 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 önyüklemeden hemen sonra çağırır. Medya uygulamanız bu yöntemi uygulamalıdır.
onPlay()
- Kullanıcı belirli bir öğe seçmeden oynamayı seçerse çağrılır. Uygulamanız varsayılan içeriğini oynatmalı veya oynatma
onPause()
ile duraklatıldıysa oynatmayı devam ettirmelidir.Not: Android Automotive OS veya Android Auto, medya tarayıcınız hizmetine bağlandığında uygulamanız otomatik olarak müzik çalmaya başlamamalıdır. Daha fazla bilgi için ilk oynatma durumunu ayarlama ile ilgili bölüme bakın.
onPlayFromMediaId()
- Kullanıcı belirli bir öğeyi çalmayı seçtiğinde çağrılır. Yöntem, medya tarayıcısı hizmetinizin içerik hiyerarşinizdeki medya öğesine atadığı kimliği alır.
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 atlamayı seçtiğinde çağrılır.
onSkipToPrevious()
- Kullanıcı bir önceki öğeye atlamayı seçtiğinde çağrılır.
onStop()
- Kullanıcı oynatmayı durdurmayı seçtiğinde çağrılır.
İstediğiniz işlevi sağlamak için uygulamanızda bu yöntemleri geçersiz kılın. İşlevselliği uygulamanız tarafından desteklenmeyen bir yöntemi uygulamanız gerekmez. Örneğin, uygulamanızda spor yayını gibi canlı yayın oynatılıyorsa onSkipToNext()
yöntemini uygulamanız gerekmez. Bunun yerine onSkipToNext()
'ün 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ı üzerinden oynattığı şekilde oynatabilir. Android Auto ve Android Automotive OS, ses içeriğini otomatik olarak aracın sistemine göndererek aracın hoparlörlerinden çalar.
Ses içeriği oynatma hakkında daha fazla bilgi için MediaPlayer'a genel bakış, Ses uygulamasına genel bakış ve ExoPlayer'a genel bakış sayfalarına göz atın.
Standart oynatma işlemlerini ayarlama
Android Auto ve Android Automotive OS, PlaybackStateCompat
nesnesinde etkinleştirilen işlemlere dayalı oynatma kontrollerini gösterir.
Uygulamanız varsayılan olarak aşağıdaki işlemleri desteklemelidir:
Uygulamanızın içeriğiyle alakalı olduğu takdirde uygulamanız aşağıdaki işlemleri de destekleyebilir:
Ayrıca, kullanıcıya gösterilebilecek bir oynatma listesi oluşturabilirsiniz 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ğırma işlevini onSkipToQueueItem()
tanımlayın.
Ayrıca, şu anda çalan içeriği gösteren Şu anda çalan simgesine de destek ekleyin. Bunu yapmak için setActiveQueueItemId()
yöntemini çağırın ve sırada oynatılan öğenin kimliğini iletin. Sırayla ilgili bir değişiklik olduğunda setActiveQueueItemId()
değerini güncellemeniz gerekir.
Etkinleştirilen her işlem ve oynatma sırası için Android Auto ve Android Automotive OS düğmeleri gösterilir. Düğmeler tıklandığında sistem, MediaSessionCompat.Callback
kaynağından ilgili geri çağırma işlevini çağırır.
Kullanılmayan alanı ayır
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örüntülemek 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
değeri ACTION_SKIP_TO_NEXT
, SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
ise ACTION_SKIP_TO_PREVIOUS
öğesine karşılık gelir. Bu sabit değerleri, pakette anahtar olarak ve değerleri için true
boole değeri kullanın.
İlk PlaybackState değerini ayarlama
Android Auto ve Android Automotive OS, medya tarayıcı hizmetinizle iletişim kurarken medya oturumunuz, içerik oynatma durumunu PlaybackStateCompat
kullanarak bildirir.
Android Automotive OS veya Android Auto, medya tarayıcısı hizmetinize bağlandığında uygulamanız otomatik olarak müzik çalmamalıdır. Bunun yerine, oynatmayı arabanın durumuna veya kullanıcı işlemlerine göre devam ettirmek ya da başlatmak için Android Auto ve Android Automotive OS'ten yararlanın.
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 ettiği için kullanıcılar bu oturumları sık sık başlatıp durdurur. Kullanıcıların sürücüler arasında sorunsuz bir deneyim yaşamasını sağlamak için kullanıcının önceki oturum durumunu takip edin. Böylece, medya uygulaması devam etme isteği aldığında kullanıcı otomatik olarak kaldığı yerden devam edebilir (ör. son oynatılan medya öğesi, PlaybackStateCompat
ve sıra).
Özel oynatma işlemleri ekleyin
Medya uygulamanızın desteklediği ek işlemleri görüntülemek için özel oynatma işlemleri ekleyebilirsiniz. Alan izin veriyorsa (ve ayrılmış değilse) Android, özel işlemleri taşıma kontrollerine ekler. Aksi takdirde, özel işlemler
taşma menüsünde gösterilir. Özel işlemler, PlaybackStateCompat
'ye eklendikleri sırayla gösterilir.
Standart işlemlerden farklı bir davranış sağlamak için özel işlemleri kullanın. Standart işlemleri değiştirmek veya kopyalamak için bunları 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
stateBuilder.addCustomAction( PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon ).run { setExtras(customActionExtras) build() } )
Java
stateBuilder.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon) .setExtras(customActionExtras) .build());
Bu yöntemin daha ayrıntılı bir örneği için GitHub'daki Universal Android Music Player örnek uygulamasındaki 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'i, uygulamanızın "Radyo kanalı başlatma" işlemine nasıl tepki verebileceğini gösterir:
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öntemin daha ayrıntılı bir örneği için GitHub'daki Universal Android Music Player örnek uygulamasında yer alan onCustomAction
yöntemine bakın.
Özel işlemler için simgeler
Oluşturduğunuz her özel işlem için bir simge kaynağı gerekir. Arabalardaki uygulamalar birçok farklı ekran boyutunda ve yoğunluğunda çalışabileceğinden, 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 çekilebilir özelliği, 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 duruma bağlıysa (ör. oynatma ayarını açar veya kapatır) kullanıcıların işlemi seçtiğinde bir değişiklik görebilmesi için farklı durumlar için farklı simgeler sağlayın.
Devre dışı bırakılan işlemler için alternatif simge stilleri sağlama
Bir özel işlem, geçerli bağlam için kullanılamadığında özel işlem simgesini, işlemin devre dışı bırakıldığını gösteren alternatif bir simgeyle değiştirin.
Ses biçimini belirtin
Oynatılan medyanın özel bir ses biçimini kullandığını belirtmek için bu özelliği destekleyen araçlarda oluşturulan simgeleri belirtebilirsiniz. KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
ve KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
öğelerini, şu anda oynatılan medya öğesinin ekstralar paketinde ayarlayabilirsiniz (MediaSession.setMetadata()
öğesine iletilir). 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 OEM'lerine bunun etkileyici ses olduğunu ve etkileyici içeriği etkileyebilecek ses efektleri uygulayıp uygulamayacakları konusunda çok dikkatli olmaları gerektiğini bildirebilirsiniz.
Şu anda oynatılan öğeden bağlantılar ekle
Şu anda oynatılan medya öğesini, altyazı, açıklama veya her ikisi de diğer medya öğelerine yönlendiren bağlantılar olacak şekilde yapılandırabilirsiniz. Bu sayede kullanıcılar ilgili öğelere hızlıca atlayabilir. Örneğin, aynı sanatçının diğer şarkılarına veya podcast'in diğer bölümlerine atlayabilirler. Araç bu özelliği destekliyorsa kullanıcılar bağlantıya dokunarak ilgili 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
(açıklamadan bağlantı vermek için) yapılandırın. Ayrıntılar için bu meta veri alanlarının referans dokümanlarına bakın.
Sesli işlemleri destekleme
Medya uygulamanız, sürücülere dikkat dağıtıcı unsurları en aza indiren güvenli ve kullanışlı bir deneyim sunmak için sesli işlemleri desteklemelidir. Örneğin, uygulamanızda bir medya öğesi çalıyorsa kullanıcı, "[şarkı adını]çal" diyerek uygulamanızdan arabanın ekranına bakmadan veya ekrana dokunmadan farklı bir şarkı çalmasını söyleyebilir. Kullanıcılar, direksiyonlarındaki uygun düğmeleri tıklayarak veya "Ok Google" anahtar 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 gönderilir.
Uygulama bu geri aramayı aldığında query
dizesine eşleşen içeriği bulur ve oynatmaya başlar.
Kullanıcılar sorgularında tür, sanatçı, albüm, şarkı adı, radyo istasyonu veya şarkı listesi gibi farklı terim kategorileri belirtebilir. Arama desteği oluştururken uygulamanız için anlamlı olan tüm kategorileri göz önünde bulundurun. Android Auto veya Android Automotive OS, belirli bir sorgunun belirli kategorilere uyduğunu algılarsa extras
parametresine ek bilgiler ekler. Aşağıdaki ekstralar gönderilebilir:
Kullanıcı arama terimlerini belirtmezse Android Auto veya Android Automotive OS tarafından gönderilebilecek boş bir query
dizesi için yer ayırın.
Örneğin, kullanıcı "Müzik çal" derse. Bu durumda uygulamanız, son çalınan veya yeni önerilen bir parçayı başlatmayı seçebilir.
Bir arama hızlı bir şekilde işlenemiyorsa onPlayFromSearch()
'te engellemeyin.
Bunun yerine, oynatma durumunu STATE_CONNECTING
olarak ayarlayın ve aramayı eşzamansız bir ileti dizisinde gerçekleştirin.
Oynatma işlemi başladıktan sonra, medya oturumunun sırasını ilgili içerikle doldurmayı düşünebilirsiniz. Ö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ği uygulamayı da düşünebilirsiniz.
Android Auto ve Android Automotive OS, "çal" sorgularına ek olarak "müziği duraklat" ve "sonraki şarkı" gibi oynatmayı kontrol etmek için sesli sorguları 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şı önlemler alın
Android Auto kullanılırken kullanıcının telefonu aracının hoparlörlerine bağlı olduğundan sürücünün dikkatinin dağılmasını önlemek için ek önlemler almanız gerekir.
Arabadaki alarmları engelleme
Kullanıcı çalmaya başlamadığı sürece (örneğin, oynat düğmesine basarak) Android Auto medya uygulamaları, araç hoparlörlerinden ses çalmaya başlamamalıdır. Medya uygulamanızdan kullanıcı tarafından planlanan alarmlar bile araç hoparlörlerinden müzik çalmaya başlamamalıdır.
Uygulamanız bu şartı karşılamak için ses çalmadan önce sinyal olarak CarConnection
'i kullanabilir. Uygulamanız, araba bağlantı türü için LiveData
değerini gözlemleyip CONNECTION_TYPE_PROJECTION
değerine eşit olup olmadığını kontrol ederek telefonun bir araç ekranına yansıtılıp yansıtılmadığını kontrol edebilir.
Kullanıcının telefonu yansıtı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, ses oynatma oturumu sırasında medya meta verileri değiştiğinde varsayılan olarak bir bildirim gösterir. Bir medya uygulaması müzik çalmaktan reklam yayınlamaya
geçtiğinde, kullanıcıya bir bildirim göstermek dikkat dağıtıcıdır. Bu durumda Android Auto'nun bildirim görüntülemesini önlemek için medya meta veri 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ı giderme
Uygulamada hata oluştuğunda oynatma durumunu STATE_ERROR
olarak ayarlayın ve setErrorMessage()
yöntemini kullanarak bir hata mesajı gösterin. Hata mesajını ayarlarken kullanabileceğiniz hata kodlarının listesi için PlaybackStateCompat
adresine göz atın.
Hata mesajları kullanıcıya yönelik olmalı ve kullanıcının mevcut yerel ayarlarına göre yerelleştirilmelidir. Böylece Android Auto ve Android Automotive OS, hata mesajını kullanıcıya gösterebilir.
Örneğin, içerik kullanıcının mevcut bölgesinde 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 bir hatayı çözmek için telefon uygulamanızı açması gerekirse mesajda bu bilgiyi kullanıcıya sağlayın. Örneğin, hata mesajınızda "Lütfen oturum açın" yerine "[Uygulamanızın adı] uygulamasında oturum açın" yazıyor olabilir.