Google Asistan, sesli komutlar kullanarak birçok cihazı kontrol etmenizi sağlar. Örneğin: Google Home, telefonunuz ve diğer cihazlar. Dahili olarak hem kendi medya komutlarını anlayabilir ("Beyoncé'den bir şey çal") ve medya denetimleri (ör. duraklatma, atla, ileri sarma, beğenme).
Asistan, bir medya kullanarak Android medya uygulamalarıyla iletişim kurar. oturum açın. Kullanabileceğim intents veya hizmetleri uygulamanızı başlatın ve oynatmaya başlayın. En iyi sonuçlar için uygulamanız bu sayfada açıklanan tüm özellikleri uygulayın.
Medya oturumu kullanma
Her ses ve video uygulaması bir medya oturumu Asistan'ın çalışabilmesi için aktarma kontrollerini içerir.
Asistan yalnızca bu bölümde listelenen işlemleri kullanırken,
en iyi uygulama, tüm hazırlık ve oynatma API’lerini
diğer uygulamalarla uyumluluk sağlayabilir. Desteklemediğiniz tüm işlemler için
medya oturumu geri çağırmaları,
ERROR_CODE_NOT_SUPPORTED
.
Uygulamanızın içinde bu işaretleri ayarlayarak medya ve aktarım kontrollerini etkinleştirin
MediaSession
nesne:
Kotlin
session.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS or MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS )
Java
session.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
Uygulamanızın medya oturumunda, desteklediği işlemler bildirilmeli ve
medya oturumu geri çağırmaları
olduğunu unutmayın. Desteklenen işlemlerinizi şurada beyan edin:
setActions()
.
İlgili içeriği oluşturmak için kullanılan Evrensel Android Müzik Çalar örnek proje, medya oturumu hazırlamaya ilişkin iyi bir örnektir.
Oynatma işlemleri
Bir hizmetten oynatmayı başlatmak için medya oturumunda şu PLAY
işlemleri ve bunların geri çağırmaları olmalıdır:
İşlem | Geri Arama |
---|---|
ACTION_PLAY |
onPlay() |
ACTION_PLAY_FROM_SEARCH |
onPlayFromSearch() |
ACTION_PLAY_FROM_URI (*) |
onPlayFromUri() |
Oturumunuzda şu PREPARE
işlemleri ve bunların geri çağırmaları da uygulanmalıdır:
İşlem | Geri Arama |
---|---|
ACTION_PREPARE |
onPrepare() |
ACTION_PREPARE_FROM_SEARCH |
onPrepareFromSearch() |
ACTION_PREPARE_FROM_URI (*) |
onPrepareFromUri() |
Hazırlık API'leri uygulandığında, sesli komuttan sonraki oynatma gecikmesi azaltılabilir. Oynatmadaki gecikme süresini iyileştirmek isteyen medya uygulamaları, içeriği önbelleğe almaya ve medya oynatmayı hazırlamaya başlamak için ek süre gerekir.
Arama sorgularını ayrıştır
Kullanıcı, "Şu anda caz çal" gibi belirli bir medya öğesini aradığında
[uygulama adınız]" veya "[şarkı adı] dinle",
onPrepareFromSearch()
veya
onPlayFromSearch()
geri çağırma yöntemi, bir sorgu parametresi ve ekstralar paketi alır.
Uygulamanız aşağıdaki adımları izleyerek sesli arama sorgusunu ayrıştırıp oynatmaya başlamalıdır: için şu adımları izleyin:
- Ekstra paketi ve sesli arama sonucunda döndürülen arama sorgusu dizesini kullan tıklayın.
- Bu sonuçlara dayalı bir oynatma sırası oluşturun.
- Sonuçlardaki en alakalı medya öğesini oynatın.
onPlayFromSearch()
yöntemi, sesten daha ayrıntılı bilgi içeren bir extras parametresi alır.
arayın. Bu ekstra özellikler, uygulamanızda çalınacak ses içeriğini bulmanıza yardımcı olur.
Arama sonuçları bu verileri sağlayamazsa mantığı kullanabilirsiniz.
ayrıştırmak ve ham arama sorgusuna göre uygun parçaları
emin olun.
Aşağıdaki ekstra özellikler Android Automotive OS ve Android Auto'da desteklenir:
Aşağıdaki kod snippet'i, onPlayFromSearch()
MediaSession.Callback
uygulama:
Kotlin
override fun onPlayFromSearch(query: String?, extras: Bundle?) { if (query.isNullOrEmpty()) { // The user provided generic string e.g. 'Play music' // Build appropriate playlist queue } else { // Build a queue based on songs that match "query" or "extras" param val mediaFocus: String? = extras?.getString(MediaStore.EXTRA_MEDIA_FOCUS) if (mediaFocus == MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE) { isArtistFocus = true artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST) } else if (mediaFocus == MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE) { isAlbumFocus = true album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM) } // Implement additional "extras" param filtering } // Implement your logic to retrieve the queue var result: String? = when { isArtistFocus -> artist?.also { searchMusicByArtist(it) } isAlbumFocus -> album?.also { searchMusicByAlbum(it) } else -> null } result = result ?: run { // No focus found, search by query for song title query?.also { searchMusicBySongTitle(it) } } if (result?.isNotEmpty() == true) { // Immediately start playing from the beginning of the search results // Implement your logic to start playing music playMusic(result) } else { // Handle no queue found. Stop playing if the app // is currently playing a song } }
Java
@Override public void onPlayFromSearch(String query, Bundle extras) { if (TextUtils.isEmpty(query)) { // The user provided generic string e.g. 'Play music' // Build appropriate playlist queue } else { // Build a queue based on songs that match "query" or "extras" param String mediaFocus = extras.getString(MediaStore.EXTRA_MEDIA_FOCUS); if (TextUtils.equals(mediaFocus, MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE)) { isArtistFocus = true; artist = extras.getString(MediaStore.EXTRA_MEDIA_ARTIST); } else if (TextUtils.equals(mediaFocus, MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE)) { isAlbumFocus = true; album = extras.getString(MediaStore.EXTRA_MEDIA_ALBUM); } // Implement additional "extras" param filtering } // Implement your logic to retrieve the queue if (isArtistFocus) { result = searchMusicByArtist(artist); } else if (isAlbumFocus) { result = searchMusicByAlbum(album); } if (result == null) { // No focus found, search by query for song title result = searchMusicBySongTitle(query); } if (result != null && !result.isEmpty()) { // Immediately start playing from the beginning of the search results // Implement your logic to start playing music playMusic(result); } else { // Handle no queue found. Stop playing if the app // is currently playing a song } }
Ses çalmak için sesli aramanın nasıl uygulanacağıyla ilgili daha ayrıntılı bir örnek için hakkında daha fazla bilgi edinmek için Evrensel Android Müzik Oynatıcı örneklem.
Boş sorguları işleme
Eğer onPrepare()
, onPlay()
, onPrepareFromSearch()
veya onPlayFromSearch()
bir arama sorgusu olmadan çağrılırsa, medya uygulamanız "geçerli"
medya Mevcut medya yoksa uygulama bir şeyler oynatmaya çalışmalıdır.
veya rastgele bir sıradan bir şarkı olarak. Asistan,
kullanıcı "[uygulamanızın adı] uygulamasında müzik çal" istediğinde bu API'ler
ek bilgiler.
Kullanıcı "[Uygulamanızın adı] uygulamasında müzik çal" dediğinde, Android Automotive OS veya
Android Auto, uygulamanızın onPlayFromSearch()
numarasını arayarak uygulamanızı başlatmayı ve ses çalmayı dener
yöntemidir. Ancak, kullanıcı medya öğesinin adını söylemediği için onPlayFromSearch()
yöntemi boş bir sorgu parametresi alır. Bu durumlarda, uygulamanız
en son dinlenen bir şarkı gibi bir ses çalarak hemen yanıt verir
bir sıra olabilir.
Sesli işlemler için eski desteği beyan etme
Çoğu durumda, yukarıda açıklanan oynatma işlemlerini işlemek, uygulamanızın gereken oynatma işlevselliğini sağlar. Ancak bazı sistemlerde uygulamanızın arama için Intent filtresi içerir. Bu Intent için destek beyan etmeniz gerekir filtre uygulayabilirsiniz.
Bir telefon uygulamasının manifest dosyasına şu kodu ekleyin:
<activity>
<intent-filter>
<action android:name=
"android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name=
"android.intent.category.DEFAULT" />
</intent-filter>
</activity>
Ulaşım denetimleri
Uygulamanızın medya oturumu etkinleştirildikten sonra Asistan sesli komutlar verebilir oynatmayı kontrol etmek ve medya meta verilerini güncellemek için kullanılır. Bunun işe yaraması için kodu, aşağıdaki işlemleri etkinleştirmeli ve ilgili geri aramalar:
İşlem | Geri Arama | Açıklama |
---|---|---|
ACTION_SKIP_TO_NEXT |
onSkipToNext() |
Sonraki video |
ACTION_SKIP_TO_PREVIOUS |
onSkipToPrevious() |
Önceki şarkı |
ACTION_PAUSE, ACTION_PLAY_PAUSE |
onPause() |
Duraklat |
ACTION_STOP |
onStop() |
Durdur |
ACTION_PLAY |
onPlay() |
Devam ettir |
ACTION_SEEK_TO |
onSeekTo() |
30 saniye geri sar |
ACTION_SET_RATING |
onSetRating(android.support.v4.media.RatingCompat) |
Beğenme/beğenme. |
ACTION_SET_CAPTIONING_ENABLED |
onSetCaptioningEnabled(boolean) |
Altyazıları açın/kapatın. |
Not:
- Arama komutlarının çalışması için
PlaybackState
,state, position, playback speed, and update time
ile güncel olmalıdır. Durum değiştiğinde uygulamanınsetPlaybackState()
öğesini çağırması gerekir. - Medya uygulaması, medya oturumu meta verilerini de güncel tutmalıdır. Bu, "Hangi şarkı çalıyor?" gibi soruları destekler. Geçerli alanlar (parça başlığı, sanatçı ve ad gibi) değiştiğinde uygulama
setMetadata()
işlevini çağırmalıdır. MediaSession.setRatingType()
, uygulamanın desteklediği puan türünü belirtecek şekilde ayarlanmalıdır ve uygulamanınonSetRating()
uygulamasını uygulaması gerekir. Uygulama derecelendirmeyi desteklemiyorsa derecelendirme türüRATING_NONE
olarak ayarlanmalıdır.
Desteklediğiniz sesli işlemler büyük olasılıkla içerik türüne göre değişiklik gösterir.
İçerik Türü | Gerekli İşlemler |
---|---|
Müzik |
Desteklenmesi gerekenler: Oynat, Duraklat, Durdur, Sonrakine atla ve Öncekine Atla Şunun için destek şiddetle önerilir:: Ara |
Podcast |
Desteklenmelidir: Oynat, Duraklat, Durdur ve Sar Şunun için destek önerin:: Sonrakine Atla ve Öncekine Atla |
Sesli kitap | Desteklenmelidir: Oynat, Duraklat, Durdur ve Sar |
Radyo | Desteklenmelidir: Oynat, Duraklat ve Durdur |
Haberler | Desteklenmesi gerekenler: Oynat, Duraklat, Durdur, Sonrakine atla ve Öncekine Atla |
Video |
Desteklenmesi gerekenler: Oynat, Duraklat, Durdur, Sar, Geri Sar ve İleri Sar Şunun için önemle tavsiye edilir:: Sonrakine Atla ve Öncekine Atla |
Yukarıda listelenen işlemlerin çoğunu ürün teklifleriniz için desteklemeniz gerekir ancak diğer eylemlere de incelikle yanıt vermelidir. Örneğin yalnızca önceki öğeye geri dönebilme olanağı varsa, bu artışa Ücretsiz katman kullanıcısı, Asistan'dan önceki öğeye dönmesini isterse hata mesajı verir. Daha fazla bilgi için hata işleme bölümüne bakın.
Deneyebileceğiniz sesli sorgularla ilgili örnek
Aşağıdaki tabloda, içe aktarılırken kullanmanız gereken bazı örnek sorgular uygulamanızı test edin:
MediaSession Geri Çağırması | Kullanılacak “Ok Google” ifadesi | |
---|---|---|
onPlay() |
"Oyna". "Devam ettir." |
|
onPlayFromSearch()
onPlayFromUri() |
Müzik |
"(uygulama adı) uygulamasında müzik veya şarkı çal." Bu boş bir sorgu. "(Uygulama adı) üzerinde (şarkı | sanatçı | albüm | tür | oynatma listesi) çal." |
Radyo | "(uygulama adı) uygulamasında (frekt | istasyon) çal." | |
Sesli kitap |
"(uygulama adı) uygulamasında sesli kitabımı oku." "(uygulama adı) üzerinde (sesli kitap) oku." |
|
Podcasts | "(uygulama adı) uygulamasında (podcast) adlı podcast'i çal." | |
onPause() |
"Duraklat." | |
onStop() |
"Durdur." | |
onSkipToNext() |
"Sonraki (şarkı | bölüm | parça)." | |
onSkipToPrevious() |
"Önceki (şarkı | bölüm | parça)." | |
onSeekTo() |
"Yeniden başlat." "## saniye ileri git." "## dakika geri git." |
|
Yok (
MediaMetadata
güncellendi) |
"Çalan ne?" |
Hatalar
Asistan, medya oturumundaki hataları oluştuğunda işler ve
kullanıcılara öğreteceğim. Medya oturumunuzun aktarım durumunu güncellediğinden ve
hatası kodunu PlaybackState
doğru şekilde ekleyin,
medya oturumuna gidin. Asistan
tarafından döndürülen tüm hata kodlarını tanır.
getErrorCode()
.
Yaygın olarak yanlış işlenen vakalar
Aşağıda, ele aldığınızdan emin olmanız gereken hata durumlarıyla ilgili bazı örnekler verilmiştir: şekilde değiştirebilirsiniz:
- Kullanıcının oturum açması gerekiyor
PlaybackState
hata kodunuERROR_CODE_AUTHENTICATION_EXPIRED
olarak ayarlayın.PlaybackState
hata mesajını ayarlayın.- Oynatma için gerekirse
PlaybackState
durumunuSTATE_ERROR
olarak ayarlayın. Aksi takdirdePlaybackState
öğesinin kalan kısmını olduğu gibi saklar.
- Kullanıcı, kullanılamayan bir işlem istiyor
PlaybackState
hata kodunu uygun şekilde ayarlayın. Örneğin,PlaybackState
-ERROR_CODE_NOT_SUPPORTED
İşlem desteklenmiyorsa veyaERROR_CODE_PREMIUM_ACCOUNT_REQUIRED
oturum açma korumalı olduğundan emin olun.PlaybackState
hata mesajını ayarlayın.PlaybackState
öğesinin geri kalanını olduğu gibi saklayın.
- Kullanıcı, uygulamada bulunmayan içerikleri istiyor
PlaybackState
hata kodunu uygun şekilde ayarlayın. Örneğin, şunu kullanın:ERROR_CODE_NOT_AVAILABLE_IN_REGION
.PlaybackState
hata mesajını ayarlayın.- Oynatmayı kesintiye uğratmak için
PlaybackSate
durumunuSTATE_ERROR
olarak ayarlayın. Aksi takdirdePlaybackState
geri kalanını olduğu gibi saklar.
- Kullanıcı, tam eşlemenin mevcut olmadığı içerikleri ister. Örneğin,
ücretsiz katman kullanıcısı, yalnızca premium seviyedeki kullanıcılara sunulan içerikleri isteyebilir.
- Hata döndürmenizi ve bunun yerine hataya öncelik vermenizi öneririz. benzer bir şey buluyor olabilirsiniz. Konuşmayı en çok Asistan yapar alakalı sesli yanıta ekleyebilirsiniz.
Bir amaçla oynatma
Asistan bir ses veya video uygulaması başlatabilir ve derin bağlantı ile test edin.
Amaç ve derin bağlantısı farklı kaynaklardan gelebilir:
- Asistan şu durumda: bir mobil uygulama başlatırken, işaretlenmiş içeriği almak için Google aramayı kullanabilir bağlantı içeren bir izleme işlemi sağlar.
- Asistan bir TV uygulamasını başlatırken uygulamanızda bir
TV Arama Sağlayıcısı
medya içeriğinin URI'larını açığa çıkarmak için kullanılır. Asistan,
derin bağlantı ve derin bağlantı için URI içeren bir intent döndürmesi gereken içerik sağlayıcı
isteğe bağlı bir işlemdir.
Sorgu, intent'de bir işlem döndürürse
Asistan bu işlemi ve URI'yı uygulamanıza geri gönderir.
Sağlayıcı
işlem yaparsanız Asistan, Intent'e
ACTION_VIEW
ekler.
Asistan, true
değeriyle ekstra EXTRA_START_PLAYBACK
ekler
ile ilişkilendirmeniz gerekir. Uygulamanız şu işlemi gerçekleştirdiğinde çalmaya başlar:
EXTRA_START_PLAYBACK
ile bir intent alır.
Etkin durumdayken amaçları işleme
Kullanıcılar, uygulamanız oynatılırken Asistan'dan bir şey çalmasını isteyebilir göz atmayı unutmayın. Bu, uygulamanızın şu an için yeni intent'ler alabileceği anlamına gelir: oynatma etkinliği başlatılmış ve etkin durumdayken oynatmayı başlatır.
Derin bağlantılar içeren amaçları destekleyen etkinlikler,
onNewIntent()
.
yeni istekleri ele alacağız.
Asistan, çalmaya başlarken başka değişiklikler
işaretler
ile ilişkilendirmeniz gerekir. Özellikle,
FLAG_ACTIVITY_CLEAR_TOP
veya
FLAG_ACTIVITY_NEW_TASK
veya her ikisi. Kodunuz
Android sistemi bu işaretleri işlemesi gerekmiyorsa Android sistemi bunlara yanıt verir.
Bu, yeni bir URI içeren ikinci bir oynatma isteği geldiğinde uygulamanızın davranışını etkileyebilir
önceki URI çalmaya devam eder. Uygulamanızın bu durumda nasıl tepki verdiğini test etmek iyi bir fikirdir. adb
komutunu kullanabilirsiniz
satır aracını kullanarak durumu simüle edin (sabit 0x14000000
değeri, iki işaretin bit tabanlı VEYA boole değeridir):
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<first_uri>"' -f 0x14000000
adb shell 'am start -a android.intent.action.VIEW --ez android.intent.extra.START_PLAYBACK true -d "<second_uri>"' -f 0x14000000
Bir hizmetten oynatma
Uygulamanızda
media browser service
.
Asistan'dan bağlantılara izin veren bir e-posta alırsınız,
Asistan, hizmetin ana makinesiyle iletişim kurarak uygulamayı başlatabilir.
media session
.
Medya tarayıcı hizmeti hiçbir zaman bir Etkinlik başlatmamalıdır.
Asistan, tanımladığınız PendingIntent
öğesine göre Etkinliğinizi başlatır
setSessionActivity() ile ifade edebilirsiniz.
Oturumunuzu açarken MediaSession.Token medya tarayıcı hizmetini başlatın. Desteklenen oynatma işlemlerini ayarlamayı unutmayın her zaman çalışır. Buna başlatma sırasında da dahildir. Asistan, medya içeriklerinizi bekler Asistan ilk oynatmayı göndermeden önce oynatma işlemlerini ayarlamak için komutunu kullanın.
Asistan, bir hizmetten başlamak için medya tarayıcısı istemci API'lerini uygular. Cihazınızda PLAY işlemi geri çağırmalarını tetikleyen TransportControls çağrılarını gerçekleştirir. uygulamanın medya oturumundan emin olun.
Aşağıdaki şemada, Asistan ve medya oturumu geri çağırmaları olduğunu unutmayın. (Hazırlama geri çağırmaları yalnızca (uygulamanız destekliyorsa).) Tüm çağrılar eşzamansızdır. Asistan şunları yapmaz: uygulamanızdan yanıt gelmesini bekleyin.
Kullanıcı çalmak için bir sesli komut verdiğinde Asistan kısa bir duyuruyla yanıt verir. Duyuru tamamlanır tamamlanmaz Asistan bir OYNAT işlemi yayınlar. Belirli bir oynatma durumu için beklemez.
Uygulamanız ACTION_PREPARE_*
işlemlerini destekliyorsa Asistan, duyuruyu başlatmadan önce PREPARE
işlemini çağırır.
MediaTarayıcı Hizmeti'ne bağlanma
Bir hizmeti kullanarak uygulamanızı başlatmak için Asistan'ın uygulamanın MediaTarayıcı Hizmeti'ne bağlanabilmesi ve
MediaSession.Token'ını alır. Bağlantı istekleri, hizmetin
onGetRoot()
.
yöntemidir. İstekleri yönetmenin iki yolu vardır:
- Tüm bağlantı isteklerini kabul et
- Yalnızca Asistan uygulamasından gelen bağlantı isteklerini kabul et
Tüm bağlantı isteklerini kabul et
Asistan'ın medya oturumunuza komut göndermesine izin vermek için BrowserRoot döndürmeniz gerekir. En kolay yol, tüm MediaTarayıcı uygulamalarının MediaTarayıcıHizmetinize bağlanmasına izin vermektir. Boş olmayan bir BrowserRoot döndürmeniz gerekir. İşte Universal Music Player'dan alınan geçerli kod:
Kotlin
override fun onGetRoot( clientPackageName: String, clientUid: Int, rootHints: Bundle? ): BrowserRoot? { // To ensure you are not allowing any arbitrary app to browse your app's contents, you // need to check the origin: if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { // If the request comes from an untrusted package, return an empty browser root. // If you return null, then the media browser will not be able to connect and // no further calls will be made to other media browsing methods. Log.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. Returning empty " + "browser root so all apps can use MediaController. $clientPackageName") return MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null) } // Return browser roots for browsing... }
Java
@Override public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { // To ensure you are not allowing any arbitrary app to browse your app's contents, you // need to check the origin: if (!packageValidator.isCallerAllowed(this, clientPackageName, clientUid)) { // If the request comes from an untrusted package, return an empty browser root. // If you return null, then the media browser will not be able to connect and // no further calls will be made to other media browsing methods. LogHelper.i(TAG, "OnGetRoot: Browsing NOT ALLOWED for unknown caller. " + "Returning empty browser root so all apps can use MediaController." + clientPackageName); return new MediaBrowserServiceCompat.BrowserRoot(MEDIA_ID_EMPTY_ROOT, null); } // Return browser roots for browsing... }
Asistan uygulaması paketini ve imzayı kabul edin
Asistan'ın paket adını ve imzasını kontrol ederek medya tarayıcısı hizmetinize bağlanmasına açıkça izin verebilirsiniz. Uygulamanız, MediaTarayıcıHizmeti'nizin onGetRoot yönteminde paket adını alır. Asistan'ın medya oturumunuza komut göndermesine izin vermek için BrowserRoot döndürmeniz gerekir. İlgili içeriği oluşturmak için kullanılan Evrensel Müzik Çalar örneği, bilinen paket adlarının ve imzaların bir listesini içerir. Aşağıda, Google Asistan tarafından kullanılan paket adları ve imzalar verilmiştir.
<signature name="Google" package="com.google.android.googlequicksearchbox">
<key release="false">19:75:b2:f1:71:77:bc:89:a5:df:f3:1f:9e:64:a6:ca:e2:81:a5:3d:c1:d1:d5:9b:1d:14:7f:e1:c8:2a:fa:00</key>
<key release="true">f0:fd:6c:5b:41:0f:25:cb:25:c3:b5:33:46:c8:97:2f:ae:30:f8:ee:74:11:df:91:04:80:ad:6b:2d:60:db:83</key>
</signature>
<signature name="Google Assistant on Android Automotive OS" package="com.google.android.carassistant">
<key release="false">17:E2:81:11:06:2F:97:A8:60:79:7A:83:70:5B:F8:2C:7C:C0:29:35:56:6D:46:22:BC:4E:CF:EE:1B:EB:F8:15</key>
<key release="true">74:B6:FB:F7:10:E8:D9:0D:44:D3:40:12:58:89:B4:23:06:A6:2C:43:79:D0:E5:A6:62:20:E3:A6:8A:BF:90:E2</key>
</signature>