Android Auto и Android Automotive OS (AAOS) обращаются к службе просмотра мультимедиа вашего приложения, чтобы узнать, какой контент доступен. Для поддержки этого вам необходимо реализовать эти два метода в службе просмотра мультимедиа.
Реализовать метод onGetRoot
Метод onGetRoot вашего сервиса возвращает информацию о корневом узле вашей иерархии контента. Android Auto и AAOS используют этот корневой узел для запроса остального контента с помощью метода onLoadChildren . В этом фрагменте кода показана реализация метода onGetRoot :
Котлин
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);
}
Подробный пример использования этого метода см. в методе onGetRoot в примере приложения Universal Android Music Player на GitHub.
Добавить проверку пакетов
Когда вызывается метод onGetRoot вашей службы, вызывающий пакет передает вашей службе идентификационную информацию. Ваша служба может использовать эту информацию, чтобы решить, может ли этот пакет получить доступ к вашему контенту.
Например, вы можете ограничить доступ к содержимому вашего приложения для списка одобренных пакетов:
- Сравните
clientPackageNameс вашим списком разрешенных пакетов. - Проверьте сертификат, использованный для подписи APK-файла пакета.
Если пакет не может быть проверен, верните null , чтобы запретить доступ к вашему контенту.
Чтобы предоставить системным приложениям, таким как Android Auto и AAOS, доступ к вашему контенту, ваша служба должна возвращать ненулевой объект BrowserRoot когда эти системные приложения вызывают метод onGetRoot .
Подпись системного приложения AAOS может различаться в зависимости от марки и модели автомобиля. Убедитесь, что разрешены подключения от всех системных приложений для поддержки AAOS.
Этот фрагмент кода показывает, как ваша служба может проверить, является ли вызывающий пакет системным приложением:
fun isKnownCaller(
callingPackage: String,
callingUid: Int
): Boolean {
...
val isCallerKnown = when {
// If the system is making the call, allow it.
callingUid == Process.SYSTEM_UID -> true
// If the app was signed by the same certificate as the platform
// itself, also allow it.
callerSignature == platformSignature -> true
// ... more cases
}
return isCallerKnown
}
Этот фрагмент кода взят из класса PackageValidator в примере приложения Universal Android Music Player на GitHub. Более подробный пример реализации проверки пакета для метода onGetRoot вашего сервиса можно найти в этом классе.
Помимо разрешения системным приложениям, необходимо разрешить Google Ассистенту подключаться к вашему MediaBrowserService . Google Ассистент использует разные имена пакетов для своих мобильных приложений и приложений AAOS.
Реализуйте метод onLoadChildren.
После получения объекта корневого узла Android Auto и AAOS создают меню верхнего уровня, вызывая метод onLoadChildren у объекта корневого узла, чтобы получить его потомков. Клиентские приложения создают подменю, вызывая тот же метод, используя объекты потомков.
Каждый узел в иерархии контента представлен объектом MediaBrowserCompat.MediaItem . Каждый из этих медиафайлов идентифицируется уникальной строкой идентификатора. Клиентские приложения рассматривают эти строки идентификаторов как непрозрачные токены.
Когда клиентское приложение хочет перейти к подменю или воспроизвести медиафайл, оно передает токен. Ваше приложение отвечает за сопоставление токена с соответствующим медиафайлом.
Этот фрагмент кода демонстрирует реализацию метода onLoadChildren
Котлин
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 if this is the root menu:
if (MY_MEDIA_ROOT_ID == parentMediaId) {
// Build the MediaItem objects for the top level
// and put them in the mediaItems list.
} else {
// Examine the passed parentMediaId to see which submenu we're at
// and put the descendants of that menu in the mediaItems list.
}
result.sendResult(mediaItems)
}
Java
@Override
public void onLoadChildren(final String parentMediaId,
final Result<List<MediaBrowserCompat.MediaItem>> result) {
// Assume for example that the music catalog is already loaded/cached.
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// Check if this is the root menu:
if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {
// Build the MediaItem objects for the top level
// and put them in the mediaItems list.
} else {
// Examine the passed parentMediaId to see which submenu we're at
// and put the descendants of that menu in the mediaItems list.
}
result.sendResult(mediaItems);
}
Пример использования этого метода можно посмотреть в методе onLoadChildren в примере приложения Universal Android Music Player на GitHub.
Структурируйте корневое меню
Android Auto и Android Automotive OS имеют определенные ограничения на структуру корневого меню. Эти ограничения передаются в MediaBrowserService через подсказки для корневого меню, которые можно прочитать через аргумент Bundle, передаваемый в onGetRoot() . При соблюдении этих подсказок система отображает содержимое корневого меню в виде навигационных вкладок. Если вы не будете следовать этим подсказкам, часть содержимого корневого меню может быть удалена или стать менее доступной для системы.

Рисунок 1. Корневой контент, отображаемый в виде навигационных вкладок.
Применяя эти подсказки, система отображает основной контент в виде навигационных вкладок. Если эти подсказки не применяются, часть основного контента может быть удалена или стать менее доступной. Эти подсказки передаются следующим образом:
Ограничение на количество дочерних вкладок : В большинстве случаев это число должно быть равно четырем, то есть может отображаться только четыре (или меньше) вкладок.
Поддерживаемые флаги для дочерних элементов корневого каталога : Ожидается, что это значение будет
MediaItem#FLAG_BROWSABLE, что означает, что в виде вкладок могут отображаться только просматриваемые элементы (а не воспроизводимые).Ограничение на количество пользовательских действий просмотра : проверьте, сколько пользовательских действий просмотра поддерживается.
Котлин
import androidx.media.utils.MediaConstants
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle
): BrowserRoot {
val maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
/* defaultValue= */ 4)
val supportedRootChildFlags = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
/* defaultValue= */ MediaItem.FLAG_BROWSABLE)
// Rest of method...
}
Java
import androidx.media.utils.MediaConstants;
// Later, in your MediaBrowserServiceCompat.
@Override
public BrowserRoot onGetRoot(
String clientPackageName, int clientUid, Bundle rootHints) {
int maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
/* defaultValue= */ 4);
int supportedRootChildFlags = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
/* defaultValue= */ MediaItem.FLAG_BROWSABLE);
// Rest of method...
}
Вы можете настроить ветвление логики структуры иерархии контента в зависимости от значений этих подсказок, особенно если ваша иерархия различается в разных интеграциях MediaBrowser помимо Android Auto и AAOS.
Например, если вы обычно отображаете основной воспроизводимый элемент, то, учитывая значение подсказки поддерживаемых флагов, вы можете захотеть вложить его под основной просматриваемый элемент.
Помимо корневых подсказок, используйте следующие рекомендации для оптимального отображения вкладок:
Монохромные (желательно белые) значки для каждого элемента вкладки.
Для каждого пункта вкладки используйте краткие и содержательные подписи (краткие подписи уменьшают вероятность того, что они будут усечены).