Bluetooth

O Android oferece uma implementação completa do Bluetooth com suporte a muitos perfis comuns de Bluetooth no carro. Também há muitos aprimoramentos que melhoram 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 e as listas de prioridade do usuário atual para cada conexão de perfil com o IVI. Os dispositivos são conectados aos perfis em uma ordem de prioridade definida. O momento de 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 necessário.

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 que é ativada por padrão. Essa política precisa ser desativada no dispositivo para que não entre em conflito com a política automotiva pretendida no CarBluetoothService. Embora a sobreposição de produto do carro cuide disso, você pode desativar a política do smartphone em uma sobreposição de recurso definindo enable_phone_policy como false em MAXIMUM_CONNECTED_DEVICES em /packages/apps/Bluetooth/res/values/config.xml.

Usar a política padrão de automóveis

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

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

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

Se a política padrão de automóveis não for suficiente para suas necessidades, ela também poderá ser desativada em favor da sua 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 de automóveis padrão

Primeiro, para usar uma política personalizada, a política automotiva padrão precisa ser desativada definindo useDefaultBluetoothConnectionPolicy como false em uma sobreposiçã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 persistido 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 a política personalizada, você pode determinar quais eventos indicam os melhores horários 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 passa a conectar dispositivos com base nas listas de prioridade definidas para cada perfil de Bluetooth.

Um exemplo de quando fazer isso é quando 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. É possível alternar o adaptador Bluetooth pela 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 conferir 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, a verificação de qualquer comportamento de conexão personalizada exige o controle dos eventos escolhidos para acionar as conexões do dispositivo.

Perfis Bluetooth automotivos

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

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

Perfil de viva-voz

O perfil viva-voz (HFP, na sigla em inglês) do Bluetooth permite que o veículo faça e receba chamadas telefônicas por um dispositivo remoto conectado. Cada conexão de dispositivo registra uma conta de smartphone separada com o TelecomManager, que anuncia todas as contas de smartphone disponíveis para os apps de IVI.

O IVI pode se conectar a vários dispositivos por 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 smartphone correspondente cria um objeto HfpClientConnection. O app Discador interage com o objeto HfpClientConnection para gerenciar recursos de chamada, como aceitar uma chamada ou desligar.

O app de discagem padrão não oferece suporte a vários dispositivos HFP conectados simultaneamente. Para implementar o HFP em vários dispositivos, é necessária a personalização para que os usuários selecionem qual conta de dispositivo usar ao fazer uma chamada. O app chama telecomManager.placeCall com a conta correta. É necessário verificar se outras funcionalidades para vários dispositivos também funcionam corretamente.

Verificar HFP com vários dispositivos

Para verificar se a conectividade com vários dispositivos funciona corretamente pelo 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. Faça uma chamada diretamente do telefone e faça uma chamada 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 do IVI.
  4. Usando o mesmo smartphone, receba uma chamada diretamente no smartphone e receba uma chamada usando o IVI.
    1. Nas duas vezes, verifique se o áudio do streaming é pausado e se o áudio do smartphone é reproduzido nos alto-falantes conectados do IVI.
  5. Repita as etapas 3 e 4 com o outro smartphone conectado.

Chamadas de emergência

A capacidade de fazer chamadas 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 pelo IVI, incluindo:

  • Solução de chamada de emergência autônoma
  • Solução de chamada de emergência integrada ao IVI
  • Usar um smartphone Bluetooth conectado quando nenhum sistema integrado estiver disponível

Conectar uma chamada de emergência

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

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

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

Ligar para emergências antes do Android 10 envolvia discar diretamente de um telefone e invocar equipamentos especiais, se disponíveis (por exemplo, acionamento automático após a detecção de perigo ou uma ação do usuário). No Android 10 e versões mais recentes, o discador no carro pode ligar diretamente para um número de emergência, desde que este MAXIMUM_CONNECTED_DEVICES esteja 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 chamadas de emergência dessa maneira, 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 Bluetooth (PBAP) faz o download de contatos e históricos de chamadas de um dispositivo remoto conectado. O PBAP mantém uma lista de contatos agregada e pesquisável que é atualizada pela máquina de estado do cliente do PBAP. Cada dispositivo conectado interage com uma máquina de estado de cliente PBAP separada, resultando em contatos associados ao dispositivo correto ao fazer uma chamada.

O PBAP é unidirecional e, portanto, exige que o IVI instancie conexões com qualquer MAXIMUM_CONNECTED_DEVICES em PbapClientService define o número máximo de conexões simultâneas de dispositivos PBPA permitidas com o IVI. O cliente do PBAP armazena os contatos de cada dispositivo conectado no provedor de contatos, que pode ser acessado por um app para extrair a lista de contatos 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 do 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 do 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 de distribuição de áudio avançado (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 própria pilha, e não no Java. No momento, 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 (AVRCP) do Bluetooth permite que o veículo controle e navegue por players de mídia em um dispositivo remoto conectado. Como o IVI desempenha o papel 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 por meio do AVRCP, o app de mídia no smartphone precisa fornecer um MediaBrowserService e permitir o acesso de com.android.bluetooth a esse serviço. Como criar um serviço de navegador de mídia explica como fazer isso em detalhes.