Bluetooth

O Android oferece uma implementação completa do Bluetooth com suporte para muitos perfis comuns de Bluetooth no carro. Há também muitas melhorias que aprimoram o desempenho e a experiência com outros dispositivos e serviços.

Gerenciamento de conexão Bluetooth

No Android, o CarBluetoothService mantém os dispositivos Bluetooth do usuário atual e as listas de prioridade para cada conexão de perfil com o IVI. Os dispositivos são conectados aos perfis em uma ordem de prioridade definida. Quando ativar, desativar e conectar dispositivos a um perfil é determinado por uma política de conexão padrão que pode ser substituída com o uso de uma sobreposição de recursos, se desejado.

Configurar o gerenciamento de conexão automotiva

Desativar a política de telefone padrão

A pilha Bluetooth do Android mantém uma política de conexão para smartphones ativada por padrão. Essa política precisa ser desativada no dispositivo para não entrar em conflito com a política automotiva pretendida em CarBluetoothService. Embora a sobreposição do produto para carro cuide disso para você, é possível desativar a política de smartphone em uma sobreposição de recursos definindo enable_phone_policy como false em MAXIMUM_CONNECTED_DEVICES em /packages/apps/Bluetooth/res/values/config.xml.

Usar a política automotiva padrão

O CarBluetoothService mantém as permissões de perfil padrão. A lista de dispositivos conhecidos e as prioridades de reconexão de perfil estão em service/src/com/android/car/BluetoothProfileDeviceManager.java.

A política de gerenciamento de conexão Bluetooth também pode ser encontrada em service/src/com/android/car/BluetoothDeviceConnectionPolicy.java. Por padrão, essa política define instâncias em que o Bluetooth deve se conectar e desconectar de dispositivos pareados. Ele também gerencia casos específicos do carro para quando o adaptador deve ser ligado e desligado.

Criar sua própria política personalizada de gerenciamento de conexão automotiva

Se a política automotiva padrão não for suficiente para suas necessidades, ela também poderá ser desativada em favor da sua própria política personalizada. Sua política personalizada é responsável, no mínimo, por determinar quando ativar e desativar o adaptador Bluetooth, bem como quando conectar dispositivos. É possível usar vários eventos para ativar/desativar o adaptador Bluetooth e iniciar conexões de dispositivos, incluindo eventos devido a mudanças em propriedades específicas do carro.

Desativar a política automotiva padrão

Primeiro, para usar uma política personalizada, a política automotiva padrão precisa ser desativada definindo useDefaultBluetoothConnectionPolicy como false em uma substituição de recursos. Esse recurso foi originalmente definido como parte de MAXIMUM_CONNECTED_DEVICES em packages/services/Car/service/res/values/config.xml.

Ativar e desativar o adaptador Bluetooth

Uma das principais funções da sua política é ativar e desativar o adaptador Bluetooth nos momentos adequados. É possível usar as APIs do framework BluetoothAdapter.enable() e BluetoothAdapter.disable() para ativar e desativar o adaptador. Essas chamadas precisam respeitar o estado persistente que o usuário selecionou nas configurações ou por qualquer outro meio. Uma maneira de fazer isso é a seguinte:

/**
 * Turn on the Bluetooth adapter.
 */
private void enableBluetooth() {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        return;
    }
    bluetoothAdapter.enable();
}

/**
 * Turn off the Bluetooth adapter.
 */
private void disableBluetooth() {
    BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter == null) {
        return;
    }
    // Will shut down _without_ persisting the off state as the desired state
    // of the Bluetooth adapter for next start up. This does nothing if the adapter
    // is already off, keeping the existing saved desired state for next reboot.
    bluetoothAdapter.disable(false);
}

Determinar quando ativar e desativar o adaptador Bluetooth

Com sua política personalizada, você pode determinar quais eventos indicam os melhores momentos para ativar e desativar o adaptador. Uma maneira de fazer isso é usando os estados de energia MAXIMUM_CONNECTED_DEVICES em CarPowerManager:

private final CarPowerStateListenerWithCompletion mCarPowerStateListener =
        new CarPowerStateListenerWithCompletion() {
    @Override
    public void onStateChanged(int state, CompletableFuture<Void> future) {
        if (state == CarPowerManager.CarPowerStateListener.ON) {
            if (isBluetoothPersistedOn()) {
                enableBluetooth();
            }
            return;
        }

        // "Shutdown Prepare" is when the user perceives the car as off
        // This is a good time to turn off Bluetooth
        if (state == CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE) {
            disableBluetooth();

            // Let CarPowerManagerService know we're ready to shut down
            if (future != null) {
                future.complete(null);
            }
            return;
        }
    }
};

Determinar quando conectar dispositivos

Da mesma forma, quando você determina os eventos que devem acionar as conexões de dispositivos para começar, o CarBluetoothManager fornece a chamada de API connectDevices() que procede para conectar dispositivos com base nas listas de prioridade definidas para cada perfil Bluetooth.

Um exemplo de quando convém fazer isso é sempre que o adaptador Bluetooth é ativado:

private class BluetoothBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
            if (state == BluetoothAdapter.STATE_ON) {
                // mContext should be your app's context
                Car car = Car.createCar(mContext);
                CarBluetoothManager carBluetoothManager =
                        (CarBluetoothManager) car.getCarManager(Car.BLUETOOTH_SERVICE);
                carBluetoothManager.connectDevices();
            }
        }
    }
}

Verificar o gerenciamento de conexão automotiva

A maneira mais fácil de verificar o comportamento da sua política de conexão é ativar o Bluetooth no IVI e validar se ele se conecta automaticamente aos dispositivos corretos na ordem adequada. Você pode ativar ou desativar o adaptador Bluetooth na interface de configurações ou com os seguintes comandos adb:

adb shell su u$(adb shell am get-current-user)_system svc bluetooth disable
adb shell su u$(adb shell am get-current-user)_system svc bluetooth enable

Além disso, a saída do comando a seguir pode ser usada para ver informações de depuração relacionadas a conexões Bluetooth:

adb shell dumpsys car_service

Por fim, se você criou sua própria política automotiva, para verificar qualquer comportamento de conexão personalizada, é necessário controlar os eventos que você escolheu para acionar as conexões de dispositivos.

Perfis Bluetooth automotivos

No Android, o IVI pode oferecer suporte a vários dispositivos conectados simultaneamente por Bluetooth. Os serviços de telefonia Bluetooth para vários dispositivos permitem que os usuários conectem dispositivos separados simultaneamente, como um smartphone pessoal e um de trabalho, e façam chamadas em viva-voz em qualquer um dos dispositivos.

Os limites de conexão são aplicados por cada perfil Bluetooth individual, geralmente na implementação do próprio serviço de perfil. Por padrão, o CarBluetoothService não faz mais julgamentos sobre o número máximo de dispositivos conectados permitidos.

Perfil viva-voz

O perfil viva-voz Bluetooth (HFP) permite que o veículo faça e receba ligações por um dispositivo remoto conectado. Cada conexão de dispositivo registra uma conta de telefone separada com o TelecomManager, que anuncia todas as contas de telefone disponíveis para os apps de IVI.

O IVI pode se conectar a vários dispositivos via HFP. MAX_STATE_MACHINES_POSSIBLE MAXIMUM_CONNECTED_DEVICES em HeadsetClientService define o número máximo de conexões HFP simultâneas.

Quando um usuário faz ou recebe uma ligação de um dispositivo, a conta de telefone correspondente cria um objeto HfpClientConnection. O app Discador interage com o objeto HfpClientConnection para gerenciar recursos de chamada, como aceitar ou desligar.

O app Discador padrão não é compatível com vários dispositivos HFP conectados simultaneamente. Para implementar o HFP em vários dispositivos, é necessário fazer uma personalização para permitir que os usuários selecionem qual conta de dispositivo usar ao fazer uma chamada. Em seguida, o app chama telecomManager.placeCall com a conta correta. Verifique se outras funcionalidades de vários dispositivos também funcionam como esperado.

Verificar HFP compatível com vários dispositivos

Para verificar se a conectividade com vários dispositivos funciona corretamente por Bluetooth:

  1. Usando o Bluetooth, conecte um dispositivo ao IVI e transmita áudio dele.
  2. Conecte dois smartphones ao IVI por Bluetooth.
  3. Escolha um smartphone. Fazer uma ligação diretamente do smartphone e fazer uma ligação usando o IVI.
    1. Nas duas vezes, verifique se o áudio transmitido por streaming é pausado e se o áudio do smartphone é reproduzido nos alto-falantes conectados ao IVI.
  4. Usando o mesmo smartphone, receba uma ligação diretamente no dispositivo e receba uma ligação usando o IVI.
    1. Nas duas vezes, verifique se o áudio de streaming é pausado e se o áudio do smartphone é reproduzido nos alto-falantes conectados ao IVI.
  5. Repita as etapas 3 e 4 com o outro smartphone conectado.

Chamadas de emergência

A capacidade de fazer ligações de emergência é um aspecto importante das funções de telefonia e Bluetooth no carro. Há várias maneiras de iniciar uma chamada de emergência no IVI, incluindo:

  • Solução independente de eCall
  • Solução de eCall integrada ao IVI
  • Usar um smartphone conectado por Bluetooth quando nenhum sistema integrado está disponível

Fazer uma ligação de emergência

Embora o equipamento eCall seja essencial para a segurança, ele não está integrado ao Android no momento. É possível usar o ConnectionService para expor recursos de chamada de emergência no Android, o que também tem o benefício de apresentar opções de acessibilidade para chamadas de emergência. Para saber mais, consulte Como criar um app de chamadas.

Confira um exemplo de como estabelecer um ConnectionService de emergência:

public class YourEmergencyConnectionService extends ConnectionService {

    @Override
    public Connection onCreateOutgoingConnection(
            PhoneAccountHandle connectionManagerAccount,
            ConnectionRequest request) {
        // Your equipment specific procedure to make ecall
        // ...
    }

    private void onYourEcallEquipmentReady() {

        PhoneAccountHandle handle =
            new PhoneAccountHandle(new ComponentName(context, YourEmergencyConnectionService),
                    YourEmergencyConnectionId);
        PhoneAccount account =
            new PhoneAccount.Builder(handle, eCallOnlyAccount)
            .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
            .setCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS
                    | PhoneAccount.CAPABILITY_MULTI_USER)
            .build():
        mTelecomManager.registerPhoneAccount(account);
        mTelecomManager.enablePhoneAccount(account.getAccountHandle(), true);
    }
}

Ativar o Bluetooth para chamadas de emergência

Antes do Android 10, para ligar para emergências, era necessário discar diretamente de um smartphone e usar equipamentos especiais, se disponíveis (por exemplo, acionamento automático ao detectar perigo ou uma ação do usuário). No Android 10 e versões mais recentes, o Telefone no carro pode ligar diretamente para um número de emergência, desde que este MAXIMUM_CONNECTED_DEVICES em apps/Bluetooth/res/values/config.xml:

<!-- For supporting emergency call through the hfp client connection service --> <bool name=”hfp_client_connection_service_support_emergency_call”>true</bool>

Ao implementar as ligações de emergência dessa forma, outros apps, como o reconhecimento de voz, também podem ligar para um número de emergência.

Perfil de acesso à agenda telefônica

O perfil de acesso à agenda telefônica (PBAP) do Bluetooth baixa contatos e históricos de chamadas de um dispositivo remoto conectado. O PBAP mantém uma lista agregada e pesquisável de contatos atualizada pela máquina de estado do cliente PBAP. Cada dispositivo conectado interage com uma máquina de estado do cliente PBAP separada, resultando na associação dos contatos ao dispositivo adequado ao fazer uma chamada.

O PBAP é unidirecional e, portanto, exige que o IVI crie instâncias de conexões com qualquer MAXIMUM_CONNECTED_DEVICES em PbapClientService define o número máximo de conexões simultâneas de dispositivos PBAP permitidas com o IVI. O cliente PBAP armazena os contatos de cada dispositivo conectado no provedor de contatos, que pode ser acessado por um app para derivar a agenda telefônica de cada dispositivo.

Além disso, a conexão de perfil precisa ser autorizada pelo IVI e pelo dispositivo móvel para que uma conexão seja estabelecida. Quando um cliente PBAP se desconecta, o banco de dados interno remove todos os contatos e o histórico de chamadas associados ao dispositivo conectado anteriormente.

Perfil de acesso a mensagens

O perfil de acesso a mensagens (MAP, na sigla em inglês) do Bluetooth permite que o veículo envie e receba mensagens SMS por um dispositivo remoto conectado. No momento, as mensagens não são armazenadas localmente no IVI. Em vez disso, sempre que o dispositivo remoto conectado recebe uma mensagem, o IVI recebe e analisa a mensagem e transmite o conteúdo dela em uma instância de Intent, que pode ser recebida por um app.

Para se conectar a um dispositivo móvel com o objetivo de enviar e receber mensagens, o IVI precisa iniciar a conexão MAP. MAXIMUM_CONNECTED_DEVICES em MapClientService define o número máximo de conexões simultâneas de dispositivos MAP permitidas com o IVI. Cada conexão precisa ser autorizada pelo IVI e pelo dispositivo móvel antes que as mensagens possam ser transferidas.

Advanced Audio Distribution Profile

O perfil avançado de distribuição de áudio (A2DP) do Bluetooth permite que o veículo receba streams de áudio de um dispositivo remoto conectado.

Ao contrário de outros perfis, o número máximo de dispositivos A2DP conectados é aplicado na pilha nativa e não em Java. O valor está codificado como 1 usando a variável kDefaultMaxConnectedAudioDevices em packages/modules/Bluetooth/system/btif/src/btif_av.cc.

Perfil de controle remoto de áudio/vídeo

O perfil de controle remoto de áudio/vídeo Bluetooth (AVRCP) permite que o veículo controle e navegue pelos players de mídia em um dispositivo remoto conectado. Como o IVI desempenha a função de um controlador AVRCP, todos os controles acionados que afetam a reprodução de áudio dependem de uma conexão A2DP com o dispositivo de destino.

Para que um player de mídia específico em um smartphone Android possa ser navegado pelo IVI via AVRCP, o app de mídia no smartphone precisa fornecer um MediaBrowserService e permitir o acesso com.android.bluetooth a esse serviço. Como criar um serviço de navegador de mídia explica como fazer isso em detalhes.