Saiba como cumprir esses tipos de comandos com interação por voz:
Cumprindo comandos de mídia
O comando relacionado à mídia pode ser dividido em três grupos diferentes:
- Fontes de mídia externas (como o Spotify instalado no AAOS).
 - Fontes de mídia de back-end (como música transmitida pelo VIA).
 - Fontes de mídia local (como rádio de carro).
 
Manipulando Comandos de Fonte de Mídia Externa
 Fontes de mídia externas são definidas como aplicativos Android que oferecem suporte a APIs MediaSession e MediaBrowse (consulte Criar aplicativos de mídia para carros na explicação detalhada sobre o uso dessas APIs).
 Importante. Para que um aplicativo assistente se conecte ao MediaBrowseService de todos os aplicativos de mídia instalados no sistema, ele deve:
-  Ser instalado como assinado pelo sistema (consulte Diretrizes de desenvolvimento de aplicativos de mídia para AAOS e o código 
PackageValidatorde amostra). -  Mantenha a permissão com privilégios do sistema 
android.permission.MEDIA_CONTENT_CONTROL(consulte Conceder permissões com privilégios do sistema ). 
Além de MediaBrowserCompat e MediaControllerCompat , o AAOS fornece o seguinte:
-  
CarMediaServicefornece informações centralizadas sobre a fonte de mídia selecionada no momento. Isso também é usado para retomar uma fonte de mídia reproduzida anteriormente após a reinicialização do desligamento do carro. -  
car-media-commonfornece métodos convenientes para listar, conectar e interagir com aplicativos de mídia. 
Abaixo estão as diretrizes específicas para a implementação de comandos comuns de interação por voz.
Obtenha uma lista de fontes de mídia instaladas
As fontes de mídia podem ser detectadas usando o PackageManager e filtrando os serviços que correspondem ao MediaBrowserService.SERVICE_INTERFACE . Em alguns carros, pode haver algumas implementações especiais de serviços de navegador de mídia, que devem ser excluídas. Abaixo segue um exemplo dessa lógica:
private Map<String, MediaSource> getAvailableMediaSources() {
    List<String> customMediaServices =
        Arrays.asList(mContext.getResources()
            .getStringArray(R.array.custom_media_packages));
    List<ResolveInfo> mediaServices = mPackageManager.queryIntentServices(
            new Intent(MediaBrowserService.SERVICE_INTERFACE),
            PackageManager.GET_RESOLVED_FILTER);
    Map<String, MediaSource> result = new HashMap<>();
    for (ResolveInfo info : mediaServices) {
        String packageName = info.serviceInfo.packageName;
        if (customMediaServices.contains(packageName)) {
            // Custom media sources should be ignored, as they might have a
            // specialized handling (e.g.: radio).
            continue;
        }
        String className = info.serviceInfo.name;
        ComponentName componentName = new ComponentName(packageName,
            className);
        MediaSource source = MediaSource.create(mContext, componentName);
        result.put(source.getDisplayName().toString().toLowerCase(),
            source);
    }
    return result;
}
Esteja ciente de que as fontes de mídia podem ser instaladas ou desinstaladas a qualquer momento. Para manter uma lista precisa, é recomendável implementar um BroadcastReceiver para as seguintes ações de intent: ACTION_PACKAGE_ADDED , ACTION_PACKAGE_CHANGED , ACTION_PACKAGE_REPLACED , ACTION_PACKAGE_REMOVED .
Conecte-se à fonte de mídia atualmente em reprodução
CarMediaService fornece métodos para obter a fonte de mídia selecionada no momento e quando essa fonte de mídia é alterada. Essas mudanças podem acontecer porque o usuário interagiu diretamente com a interface do usuário ou devido ao uso de botões de hardware no carro. Por outro lado, a biblioteca car-media-common oferece maneiras convenientes de se conectar a uma determinada fonte de mídia. Aqui está um snippet simplificado sobre como se conectar ao aplicativo de mídia atualmente selecionado:
public class MediaActuator implements
        MediaBrowserConnector.onConnectedBrowserChanged {
    private final Car mCar;
    private CarMediaManager mCarMediaManager;
    private MediaBrowserConnector mBrowserConnector;
    …
    public void initialize(Context context) {
        mCar = Car.createCar(context);
        mBrowserConnector = new MediaBrowserConnector(context, this);
        mCarMediaManager = (CarMediaManager)
            mCar.getCarManager(Car.CAR_MEDIA_SERVICE);
        mBrowserConnector.connectTo(mCarMediaManager.getMediaSource());
        …
    }
    @Override
    public void onConnectedBrowserChanged(
            @Nullable MediaBrowserCompat browser) {
        // TODO: Handle connected/disconnected browser
    }
    …
}
Controlar a reprodução da fonte de mídia atualmente em reprodução
Com um MediaBrowserCompat conectado, é muito simples enviar comandos de "controle de transporte" para o aplicativo de destino. Aqui está um exemplo simplificado:
public class MediaActuator …  {
    …
    private MediaControllerCompat mMediaController;
    @Override
    public void onConnectedBrowserChanged(
            @Nullable MediaBrowserCompat browser) {
        if (browser != null && browser.isConnected()) {
            mMediaController = new MediaControllerCompat(mContext,
                browser.getSessionToken());
        } else {
            mMediaController = null;
        }
    }
    private boolean playSongOnCurrentSource(String song) {
        if (mMediaController == null) {
            // No source selected.
            return false;
        }
        MediaControllerCompat.TransportControls controls =
            mMediaController.getTransportControls();
        PlaybackStateCompat state = controller.getPlaybackState();
        if (state == null || ((state.getActions() &
                PlaybackStateCompat.ACTION_PLAY_FROM_SEARCH) == 0)) {
            // Source can't play from search
            return false;
        }
        controls.playFromSearch(query, null);
        return true;
    }
    …
}
Manipulação de comandos de fonte de mídia local (rádio, CD-Player, Bluetooth, USB)
As fontes de mídia local expõem sua funcionalidade ao sistema usando as mesmas APIs MediaSession e MediaBrowse detalhadas acima. Para acomodar as particularidades de cada tipo de hardware, esses serviços MediaBrowse utilizam convenções específicas para organizar suas informações e comandos de mídia.
Manipulação de rádio
Radio MediaBrowseService pode ser identificado pelo filtro de intent ACTION_PLAY_BROADCASTRADIO . Espera-se que eles sigam os controles de reprodução e a estrutura de navegação de mídia descritos aqui: Implementando Rádio com Mídia . AAOS oferece a biblioteca car-broadcastradio-support contendo constantes e métodos para ajudar OEMs a criar implementações MediaBrowseService para seus próprios serviços de rádio que seguem o protocolo definido e fornece suporte para aplicativos que consomem sua árvore de navegação (por exemplo, VIAs).
Manipulação de entrada auxiliar, CD de áudio e mídia USB
Não há implementação padrão dessas fontes de mídia como parte do AOSP. A abordagem sugerida é:
- Faça com que os OEMs implementem serviços de mídia para cada um deles. Para obter detalhes, consulte Criar aplicativos de mídia para carros .
 - Essas implementações de MediaBrowseService seriam identificadas e respondidas nas ações de intenção definidas nas intenções de reprodução geral .
 - Esses serviços exporiam uma árvore de navegação seguindo as diretrizes descritas em Outros tipos de origem .
 
Manipulando o Bluetooth
O conteúdo de mídia Bluetooth é exposto por meio do perfil Bluetooth AVRCP. Para facilitar o acesso a essa funcionalidade, o AAOS inclui uma implementação MediaBrowserService e MediaSession que abstrai os detalhes da comunicação (consulte packages/apps/Bluetooth ).
A respectiva estrutura de árvore do navegador de mídia é definida na classe BrowseTree . Os comandos de controle de reprodução podem ser entregues de forma semelhante a qualquer outro aplicativo, usando sua implementação MediaSession.
Manipulando Comandos de Mídia de Streaming
Para implementar o streaming de mídia do lado do servidor, o VIA deve se tornar uma fonte de mídia, implementando a API MediaBrowse e MediaSession. Consulte Criar aplicativos de mídia para carros . Ao implementar essas APIs, um aplicativo de controle de voz seria capaz de (entre outras coisas):
- Participe perfeitamente na seleção da fonte de mídia
 - Ser retomado automaticamente após a reinicialização do carro
 - Forneça controle de reprodução e navegação usando a interface do usuário do Media Center
 - Receba eventos de botão de mídia de hardware padrão
 
Cumprindo Comandos de Navegação
Não há uma maneira padronizada de interagir com todos os aplicativos de navegação. Para integrações com o Google Maps, consulte Google Maps para Android Automotive Intents . Para integrações com outros aplicativos, entre em contato diretamente com os desenvolvedores do aplicativo. Antes de lançar um intent para qualquer aplicativo (incluindo o Google Maps), verifique se o intent pode ser resolvido (consulte Solicitações de intent ). Isso cria a oportunidade de informar o usuário caso o aplicativo de destino não esteja disponível.
Cumprindo Comandos do Veículo
O acesso às propriedades do veículo para leitura e gravação é fornecido por meio do CarPropertyManager . Os tipos de propriedades do veículo, sua implementação e outros detalhes são explicados aqui: AOSP/Desenvolver/Automotivo - Propriedades do Veículo . Para uma descrição precisa das propriedades suportadas pelo Android, é melhor consultar diretamente hardware/interfaces/automotive/vehicle/2.0/types.hal . A enumeração VehicleProperty definida contém propriedades padrão e específicas do fornecedor, tipos de dados, modo de alteração, unidades e definição de acesso de leitura/gravação.
Para acessar essas mesmas constantes do Java, você pode usar VehiclePropertyIds e suas classes complementares. Diferentes propriedades têm diferentes permissões do Android controlando seu acesso. Essas permissões são declaradas no manifesto CarService e o mapeamento entre propriedades e permissões descrito no VehiclePropertyIds Javadoc e aplicado em PropertyHalServiceIds .
Lendo uma propriedade de veículo
O seguinte é um exemplo que mostra como ler a velocidade do veículo.
public class CarActuator ... {
    private final Car mCar;
    private final CarPropertyManager mCarPropertyManager;
    private final TextToSpeech mTTS;
    /** Global VHAL area id */
    public static final int GLOBAL_AREA_ID = 0;
    public CarActuator(Context context, TextToSpeech tts) {
        mCar = Car.createCar(context);
        mCarPropertyManager = (CarPropertyManager) mCar.getCarManager(Car.PROPERTY_SERVICE);
        mTTS = tts;
        ...
    }
    @Nullable
    private void getSpeedInMetersPerSecond() {
        if (!mCarPropertyManager.isPropertyAvailable(VehiclePropertyIds.PERF_VEHICLE_SPEED,
                GLOBAL_AREA_ID)) {
            mTTS.speak("I'm sorry, but I can't read the speed of this vehicle");
            return;
        }
        // Data type and unit can be found in
        // automotive/vehicle/2.0/types.hal
        float speedInMps = mCarPropertyManager.getFloatProperty(
                VehiclePropertyIds.PERF_VEHICLE_SPEED, GLOBAL_AREA_ID);
        int speedInMph = (int)(speedInMetersPerSecond * 2.23694f);
        mTTS.speak(String.format("Sure. Your current speed is %d miles "
                + "per hour", speedInUserUnit);
    }
    ...
}
Definir uma propriedade de veículo
O seguinte é um exemplo mostrando como ligar e desligar o AC frontal.
public class CarActuator … {
    …
    private void changeFrontAC(boolean turnOn) {
        List<CarPropertyConfig> configs = mCarPropertyManager
                .getPropertyList(new ArraySet<>(Arrays.asList(
                    VehiclePropertyIds.HVAC_AC_ON)));
        if (configs == null || configs.size() != 1) {
            mTTS.speak("I'm sorry, but I can't control the AC of your vehicle");
            return;
        }
        // Find the front area Ids for the AC property.
        int[] areaIds = configs.get(0).getAreaIds();
        List<Integer> areasToChange = new ArrayList<>();
        for (int areaId : areaIds) {
            if ((areaId & (VehicleAreaSeat.SEAT_ROW_1_CENTER
                        | VehicleAreaSeat.SEAT_ROW_1_LEFT
                        | VehicleAreaSeat.SEAT_ROW_1_RIGHT)) == 0) {
                continue;
            }
            boolean isACInAreaAlreadyOn = mCarPropertyManager
                    .getBooleanProperty(VehiclePropertyIds.HVAC_AC_ON, areaId);
            if ((!isACInAreaAlreadyOn && turnOn) || (isACInAreaAlreadyOn && !turnOn)) {
                areasToChange.add(areaId);
            }
        }
        if (areasToChange.isEmpty()) {
            mTTS.speak(String.format("The AC is already %s", turnOn ? "on" : "off"));
            return;
        }
        for (int areaId : areasToChange) {
            mCarPropertyManager.setBooleanProperty(
                VehiclePropertyIds.HVAC_AC_ON, areaId, turnOn);
        }
        mTTS.speak(String.format("Okay, I'm turning your front AC %s",
            turnOn ? "on" : "off"));
    }
    …
}
Cumprindo Comandos de Comunicação
Manipulando Comandos de Mensagens
Os VIAs devem lidar com as mensagens recebidas seguindo o fluxo "tocar para ler" descrito em Toque para ler do Voice Assistant , que pode, opcionalmente, lidar com o envio de respostas de volta ao remetente da mensagem recebida. Além disso, os VIAs podem usar o SmsManager (parte do pacote android.telephony ) para compor e enviar mensagens SMS diretamente do carro ou via Bluetooth.
Manipulando Comandos de Chamada
De maneira semelhante, os VIAs podem usar o TelephonyManager para fazer chamadas telefônicas e ligar para o número do correio de voz do usuário. Nesses casos, os VIAs irão interagir diretamente com a pilha de telefonia ou com o aplicativo Car Dialer. Em qualquer caso, o aplicativo Car Dialer deve ser aquele que exibe a interface do usuário relacionada à chamada de voz para o usuário.
Cumprindo outros comandos
Para uma lista de outros possíveis pontos de integração entre o VIA e o sistema, confira a lista de Android Intents conhecidas. Muitos comandos de usuário podem ser resolvidos no lado do servidor (por exemplo, lendo e-mails de usuários e eventos de calendário) e não exigem nenhuma interação com o sistema além da própria interação de voz.
Ações imersivas (exibição de conteúdo visual)
Quando melhora as ações ou a compreensão do usuário, um VIA pode fornecer conteúdo visual complementar na tela do carro. Para minimizar a distração do motorista, mantenha esse conteúdo simples, breve e acionável. Para obter detalhes sobre as diretrizes de UI/UX sobre ações imersivas, consulte Preloaded Assistants: UX Guidance .
Para permitir a personalização e consistência com o restante do design da unidade principal (HU), os VIAs devem usar os componentes Car UI Library para a maioria dos elementos da interface do usuário. Para obter detalhes, consulte Personalização .