Comandos de preenchimento

Esta página descreve como executar comandos com interação por voz.

Executar comandos de mídia

O comando relacionado à mídia pode ser dividido em três grupos diferentes:

  • Fontes de mídia externas (como Spotify instalado no AAOS)
  • Fontes de mídia de back-end (como músicas transmitidas por VIA)
  • Fontes de mídia locais (como rádio do carro).

Processar comandos de fonte de mídia externa

Fontes de mídia externas são definidas como apps Android com suporte a MediaSessionCompat e MediaBrowseCompat APIs (consulte Criar apps de mídia para carros para uma explicação detalhada sobre o uso dessas APIs).

Importante: para que um app assistente se conecte ao MediaBrowseService de todos os apps de mídia instalados neste ele precisa:

  1. Ser instalado como assinado pelo sistema (consulte Diretrizes de desenvolvimento de aplicativos de mídia para AAOS e o exemplo de código PackageValidator).
  2. Manter android.permission.MEDIA_CONTENT_CONTROL com privilégios de sistema (consulte Conceder permissões com privilégios de sistema).

Além de MediaBrowserCompat e MediaControllerCompat, O AAOS oferece o seguinte:

  • CarMediaService fornece informações centralizadas sobre a fonte de mídia selecionada no momento. Isso é também é usado para retomar uma fonte de mídia que estava em reprodução após o desligamento e a reinicialização do carro.
  • O car-media-common oferece métodos convenientes para listar, conectar e interagir. com apps de música.

Abaixo estão as diretrizes específicas para a implementação de interações por voz comuns comandos

Conferir uma lista das fontes de mídia instaladas

As fontes de mídia podem ser detectadas usando PackageManager, e filtre por serviços que correspondem a MediaBrowserService.SERVICE_INTERFACE. Em alguns carros, pode haver algumas implementações especiais de serviço de navegador de mídia, que deve ser excluído. Aqui está 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;
}

As fontes de mídia podem ser instaladas ou desinstaladas a qualquer momento. Em Para manter uma lista precisa, é recomendável implementar um BroadcastReceiver para as ações de intent ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REPLACED, e ACTION_PACKAGE_REMOVED.

Conectar à fonte de mídia em reprodução

CarMediaService fornece métodos para obter a fonte de mídia selecionada no momento e quando essa mídia mudanças na fonte. Essas mudanças podem acontecer porque o usuário interagiu com o na interface do usuário ou devido ao uso de botões físicos no carro. Por outro lado, a biblioteca car-media-common oferece maneiras convenientes de se conectar a uma determinada mídia fonte. Veja um snippet simplificado sobre como se conectar ao app de música:

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 em reprodução

Com um MediaBrowserCompat conectado é fácil enviar informações de transporte controlar comandos ao app de destino. Este é um exemplo exemplo:

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;
   
}

   

}

Gerenciar comandos de fontes de mídia local (rádio, CD player, Bluetooth, USB)

As fontes de mídia locais expõem suas funcionalidades ao sistema usando a mesma APIs MediaSession e MediaBrowse detalhadas acima. Para acomodar as particularidades para cada tipo de hardware, esses serviços MediaBrowse usam convenções específicas para organizar informações e comandos de mídia.

Gerenciar rádio

O Radio MediaBrowseService pode ser identificado pelo objeto ACTION_PLAY_BROADCASTRADIO filtro de intent. O usuário deve seguir os controles de mídia e a navegação de mídia descrita em Implementar rádio. O AAOS oferece car-broadcastradio-support biblioteca contendo constantes e métodos para ajudar os OEMs a criar MediaBrowseService implementações para seus próprios serviços de rádio que seguem o protocolo definido, e oferece suporte para apps que consomem sua árvore de navegação (por exemplo, VIAs).

Gerenciar a entrada auxiliar, o áudio CD e a mídia USB

Não há implementação padrão dessas fontes de mídia como parte do AOSP. A abordagem sugerida é:

Gerenciar o Bluetooth

O conteúdo de mídia Bluetooth é exposto por meio do perfil Bluetooth do AVRCP. Em para facilitar o acesso a essa funcionalidade, o AAOS inclui um implementação MediaBrowserService e MediaSession que abstrai o detalhes de comunicação (consulte packages/apps/Bluetooth).

A respectiva estrutura de árvore de navegador de mídia é definida em BrowseTree. . Os comandos de controle de reprodução podem ser entregues de forma semelhante a qualquer outro aplicativo, usando a implementação MediaSession.

Processar comandos de streaming de mídia

Para implementar o streaming de mídia do lado do servidor, o VIA precisa se tornar ele mesmo uma fonte de mídia, implementando MediaBrowse e API MediaSession. Consulte Criar apps de mídia para carros. Com a implementação dessas APIs, um app de controle de voz poderia (entre outras coisas):

  • Participe da seleção da fonte de mídia sem problemas
  • Ser retomado automaticamente após a reinicialização do carro
  • Fornecer controle de reprodução e navegação usando a interface do Media Center
  • Receber eventos de botão de mídia de hardware padrã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 Mapas para intents do Android Automotive. Para integrações com outros apps, entre em contato diretamente com os desenvolvedores. Antes do lançamento uma intent a qualquer aplicativo (incluindo o Google Maps), verifique se ela pode ser resolvido (consulte Intent solicitações). Isso cria a oportunidade de informar o usuário caso o app de destino não está disponível.

Atender aos comandos do veículo

O acesso às propriedades do veículo para leitura e gravação é fornecido pelo CarPropertyManager (em inglês). Explicação sobre os tipos de propriedades do veículo, a implementação delas e outros detalhes em Propriedade personalizadas. Para uma descrição precisa das propriedades compatíveis Android, é melhor consultar diretamente hardware/interfaces/automotive/vehicle/2.0/types.hal. O objeto VehicleProperty um tipo enumerado definido nele contém propriedades padrão e específicas do fornecedor, dados tipos, modo de alteração, unidades e definição de acesso de leitura/gravação.

Para acessar essas mesmas constantes a partir de Java, você pode usar VehiclePropertyIds e suas classes complementares. Propriedades diferentes têm permissões do Android distintas controlando as próprias acesso. Essas permissões são declaradas no bloco CarService manifesto do app, e o mapeamento entre as propriedades e as permissões descritas em VehiclePropertyIds Javadoc e aplicado em PropertyHalServiceIds.

Ler uma propriedade de um veículo

Confira abaixo 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 do veículo

Confira abaixo um exemplo que mostra como ligar e desligar o ar-condicionado 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"));
   
}

   

}

Atender aos comandos de comunicação

Gerenciar comandos de mensagens

Os VIAs precisam gerenciar as mensagens recebidas após o "toque para ler" fluxo descrito no Assistente de voz Toque para ler, que pode gerenciar o envio de respostas de volta ao remetente da mensagem recebida. Além disso, os VIAs podem usar SmsManager. (parte do android.telephony para escrever e enviar mensagens SMS diretamente do carro ou por Bluetooth.

Processar comandos de chamada

Os VIAs também podem usar TelephonyManager. para fazer chamadas telefônicas e ligar para o número do correio de voz do usuário. Nesses casos, Os VIAs vão interagir com a pilha de telefonia diretamente ou com o Telefone do Carro app. De qualquer forma, o app Telefone do carro deve ser o que mostra interface relacionada a chamadas de voz para o usuário.

Executar outros comandos

Para obter uma lista de outros possíveis pontos de integração entre o VIA e o sistema, verifique a lista de intents do Android conhecidas. Muitas os comandos de usuário podem ser resolvidos no lado do servidor (por exemplo, ler e-mails de usuários e eventos da agenda) e não exigem nenhuma interação com o sistema além da interação por voz.

Ações imersivas (exibir conteúdo visual)

Quando melhora as ações ou o entendimento do usuário, um VIA pode oferecer 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 detalhes sobre as diretrizes de interface/UX sobre ações imersivas, consulte Assistentes pré-carregados: orientações sobre a UX.

Para permitir a personalização e a consistência com o restante do design da unidade principal (HU), os VIAs devem usar Carro Componentes da biblioteca de interface para a maioria dos elementos da interface. Para mais detalhes, consulte Personalização.