Android Auto ve Android Automotive OS, medya uygulaması içeriğinizi arabalarında olan 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 bir 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 alt öğelerine 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 optimize edilmiş 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. Ardından hem Android Auto hem de Android Automotive OS, aşağıdakileri yapmak için hizmetinizi kullanabilir:
- 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.
Medya tarayıcısı hizmetinizi, diğer istemcilerin uygulamanızdaki medya içeriklerine erişmesine izin vermek için de kullanabilirsiniz. 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ı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 tarafından destekleniyorsa kullanıcı içeriklerinizi 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 mevcut olduğunu öğrenmek için uygulamanızın medya tarayıcısı hizmetini çağırır. Bunu desteklemek için medya tarayıcı hizmetinizde iki yöntem uygulamanız gerekir: onGetRoot()
ve onLoadChildren()
onGetRoot işlevini 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ındaki onGetRoot()
yöntemine bakın.
onGetRoot() için paket doğrulaması ekleme
Hizmetinizin onGetRoot()
yöntemine 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
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ğrulanamıyorsa içeriğinize erişimi reddetmek için null
simgesini döndürün.
Android Auto ve Android Automotive OS gibi sistem uygulamalarının içeriğinize erişebilmesi için bu sistem uygulamaları onGetRoot()
yöntemini çağrdığında hizmetinizin her zaman null olmayan bir BrowserRoot
döndürmesi gerekir. 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'inde, hizmetinizin çağıran paketin 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ı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'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 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'in kök menünün yapısıyla ilgili belirli kısıtlamaları vardır. Bunlar, onGetRoot()
'a iletilen Bundle
bağımsız değişkeni aracılığıyla okunabilen kök ipuçları aracılığıyla MediaBrowserService
'e iletilir.
Bu ipuçları, sistemin kök içeriği gezinme sekmeleri olarak en iyi şekilde göstermesini 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ı beklenir. 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 oynatılabilir bir kök öğe gösteriyorsanız desteklenen işaretler ipucunun değeri nedeniyle bunu, kök bir 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 uyulması 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 ancak anlamlı etiketler girin. Etiketlerin kısa tutulması, dizelerin kısaltılma olasılığını azaltır.
Medya posterini görüntüleme
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'inde Glide kullanılmaktadı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önteminin BrowserRoot
ekstralar paketine belirli sabitler ekleyerek medya öğelerinizin nasıl gösterileceğiyle ilgili 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 oynatılabilir öğ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, simgeler küçükken daha iyi göründüğü için simgelerin etrafına kenar boşlukları uygulanması dışında normal liste öğ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.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 stilleri ayarlama
Content Style API, tarayılabilen medya öğelerinin alt öğelerinin yanı sıra medya öğelerinin varsayılan içerik stilini geçersiz kılmanıza olanak tanır.
Göz atılabilir bir medya öğesinin alt öğelerinin varsayılan ayarını geçersiz kılmak için medya öğesinin MediaDescription
bölümünde bir ekstralar 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 göz atılabilir alt öğeleri için geçerlidir.
Alt öğelerinin değil, belirli bir medya öğesinin kendisinin varsayılan ayarını geçersiz kılmak için medya öğesinin MediaDescription
bölümünde bir ekstralar paketi oluşturun ve DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
anahtarını içeren 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ı kullanarak öğeleri gruplandırma
İlgili medya öğelerini 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 grubu başlığı olan 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" olmak üzere 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 medya öğesi Aextras.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 C medya öğesiextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
içeren medya öğesi Dextras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
içeren E medya öğesi
"Şarkılar" ve "Albümler" gruplarına ait medya öğeleri birbirine 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 medya öğesi Aextras.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 D 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, "Albums")
içeren E medya öğesi
Ek meta veri göstergelerini görüntüleme
Medya tarayıcısı ağacındaki ve oynatma sırasındaki içerikle ilgili bir bakışta bilgi sağlamak için 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. Olası değerler aşağıdaki uzun sabitlerdir:STATUS_DOWNLOADED
: öğe tamamen indirilmiştir.STATUS_DOWNLOADING
: Öğe indiriliyordur.STATUS_NOT_DOWNLOADED
: Öğe indirilmez.
METADATA_KEY_IS_EXPLICIT
: Öğenin uygunsuz içerik içerip içermediğini belirtir. 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ç oynanmamış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çerikteki tamamlanma yüzdesini 0,0 ile 1,0 arasında (dahil) bir çift 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 ekstra özelliği kullanıyorsanız ilk gösteriminden sonra bu göstergeyi nasıl güncelleyeceğinizi öğrenmek için bu kılavuzun içerik oynatılırken göz atma görünümünde 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'inde, %70'i tamamlanmış uygunsuz bir medya öğesi için göstergelerin nasıl gösterileceğ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 öğ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'inde, oynatma görünümündeki mevcut şarkının uygunsuz ve indirilmiş olduğunun 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 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ğuna sahip olması için aşağıdaki koşullar karşılanmalıdır:
- Oluşturulduğunda
MediaItem
, eklerindeDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
değerini 0,0 ile 1,0 arasında (bu değerler dahil) bir değerle göndermelidir. MediaMetadataCompat
,MediaItem
'ye iletilen medya kimliğine eşit bir dize değeriyleMETADATA_KEY_MEDIA_ID
göndermelidir.PlaybackStateCompat
,MediaItem
'e 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ı görüntüleme
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ılavuzun Sesli işlemleri destekleme bölümüne bakın.
Göz atılabilir arama sonuçları görüntülemek için sabit anahtar BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
değerini, hizmetinizin onGetRoot()
yönteminin ekstralar paketine true
mantıksal değeriyle eşlenecek şekilde ekleyin.
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ı 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ı" özelliğini çağrdığında kullanıcının arama terimlerini bu yönteme iletir.
Hizmetinizin onSearch()
yönteminden gelen arama sonuçlarını daha kolay göz atılabilir hale getirmek için başlık öğelerini kullanarak düzenleyebilirsiniz. Örneğin, uygulamanız 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, aracın medya uygulamasında uygulamanızın MediaItem
nesnelerine özel simgeler ve etiketler eklemenize ve kullanıcıların bu işlemlerle olan 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 özel göz atma işlemi aşağıdakilerle 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 (tonlandırılabilen bir drawable 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 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, "Favori" ve "İndir" gibi durum bilgisine sahip işlemler için kullanışlıdır. "Radyo ç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'ni uygulama
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 gösterir.
- Özel Göz Atma İşlemleri'nin dünya çapındaki 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
- Global listeyi
BrowseRoot
'inize 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ı kullanarak işlem kimliklerinin listesiniMediaDescriptionCompat
ekstralarına ekleyerek ayrıMediaItem
nesnelerine işlem ekleyebilirsiniz. Bu liste,BrowseRoot
içinde tanımladığınız global 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.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
anahtarını kullanarak, işlemi tetikleyenMediaItem
öğesinin kimliğini ekstralardan alabilirsiniz.- İ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
hesabınızda yapabileceğiniz bazı değişiklikler aşağıda verilmiştir.
BrowserServiceCompat'i geçersiz kılma
MediaBrowserServiceCompat
dosyasında 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ç tane ö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 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 iş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; }
Özel Göz Atma İşlemi listesini göz atma köküne 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
'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'yi ayrıştırma:@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ü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üncelleme Düğümüne Göz At
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- Kullanıcıya mesaj
- Hata varsa
result.sendError(resultBundle).
numaralı telefonu arayın - İlerleme güncellemesi varsa
result.sendProgressUpdate(resultBundle)
numaralı telefonu arayın. result.sendResult(resultBundle)
'ü arayarak sonlandırın.
İşlem durumunu güncelleme
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 işleminin ilerleme durumu ve sonucu hakkında anlık geri bildirim verebilirsiniz.
Örnek: İndirme İşlemi
Üç durumu olan bir indirme işlemini uygulamak için bu özelliği nasıl kullanabileceğinize dair bir örnek aşağıda 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 bir başarı mesajı göstermek içinEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
anahtarını kullanabilirsiniz.
Bu yaklaşım, kullanıcıya indirme işlemi ve mevcut durumu hakkında net geri bildirim vermenizi sağlar. İndirme durumunu %25, %50 ve% 75 olarak gösteren simgelerle 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. - Favori: Bu işlem, kullanıcının favoriler listesinde bulunan öğ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
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 işlemlerinin esnekliğini ve bunları kullanarak aracın medya uygulamasında gelişmiş bir kullanıcı deneyimi için anlık geri bildirimlerle çeşitli işlevler uygulamayı nasıl yapabileceğ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ştururken oynatma denetimi 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. Bu nesnenin nasıl uygulanacağı sonraki bölümde açıklanmıştı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
sınıfındaki 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.
Uygulamanızın içerik oynatmayı işleyebilmesi için 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 oynatmayı 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ı ö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 aracı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ış 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 denetimlerini 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.
Android Auto ve Android Automotive OS, etkinleştirilen her işlem için düğmelerin yanı sıra oynatma sırasını gösterir. Düğmeler tıklandığında sistem, MediaSessionCompat.Callback
kaynağından ilgili geri çağırma işlevini çağırı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ö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
, ACTION_SKIP_TO_NEXT
'a, SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
ise ACTION_SKIP_TO_PREVIOUS
'a karşılık gelir. Bu sabitleri pakette anahtar olarak kullanın ve değerleri için boole true
değerini kullanın.
İlk PlaybackState değerini ayarlama
Android Auto ve Android Automotive OS, medya tarayıcısı hizmetinizle iletişim kurarken medya oturumunuz PlaybackStateCompat
kullanarak içerik oynatma durumunu iletir.
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ğinden 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 ekleme
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
'e 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
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ö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'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öntemin daha ayrıntılı bir örneği için GitHub'daki Universal Android Music Player örnek uygulamasındaki 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 bu tam sayı değerini, özel işlemin ekstralarının EXTRAS_KEY_COMMAND_BUTTON_ICON_COMPAT
anahtarı için ayarlamanız gerekir. Desteklenen sistemlerde bu, CustomAction.Builder
öğesine iletilen simge kaynağını geçersiz kılar. Böylece sistem bileşenleri, işleminizi ve diğer oynatma işlemlerini tutarlı bir tarzda oluşturabilir.
Ayrıca bir simge kaynağı da belirtmeniz 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 ç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 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
Geçerli bağlamda kullanılamayan özel işlem simgelerini, işlemin devre dışı olduğunu gösteren alternatif simgelerle değiştirin.
Ses biçimini belirtin
Şu anda oynatılan medyanın özel bir ses biçimi 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.
Oynatılan öğeden bağlantı ekleme
Ş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ıda 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 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ız bir medya öğesi çalıyorsa kullanıcı, arabanın ekranına bakmadan veya ekrana dokunmadan uygulamanıza farklı bir şarkıyı çalmasını söylemek için"[şarkı adı]çal" diyebilir. 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ı ayarsız bir ileti dizisinde gerçekleştirin.
Oynatma işlemi başladıktan sonra medya oturumunun sırasını ilgili içerikle 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ıların sorgusuyla eşleşen farklı bir parça seçebilmesi için gezilebilir arama sonuçları desteği de sunabilirsiniz.
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şlemlerinin nasıl uygulanacağına dair 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
Android Auto medya uygulamaları, kullanıcı oynatmaya (ör. oynatma düğmesine basarak) başlamadığı sürece sesleri araba hoparlörlerinden ç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.
Bu koşulu karşılamak için uygulamanız, ses çalmadan önce CarConnection
simgesini sinyal olarak kullanabilir. Uygulamanız, araba bağlantısı türü için LiveData
değerini gözlemleyip CONNECTION_TYPE_PROJECTION
değerine eşit olup olmadığını kontrol ederek telefonun bir araba 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 bildirim gösterilmesi dikkat dağıtıcıdır. Android Auto'nun bu durumda bildirim göstermesini ö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ı sağlayın. Hata mesajını ayarlarken kullanabileceğiniz hata kodlarının listesini PlaybackStateCompat
sayfasında bulabilirsiniz.
Hata mesajları kullanıcıya yönelik olmalı ve kullanıcının mevcut yerel ayarları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 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 hatayı düzeltmek için telefon uygulamanızı açması gerekiyorsa bu bilgiyi mesajınızda kullanıcıya iletin. Örneğin, hata mesajınızda "Lütfen oturum açın" yerine "[Uygulamanızın adı] uygulamasında oturum açın" yazabilir.