Bluetooth

Android proporciona una implementación completa de Bluetooth con compatibilidad con muchos perfiles de Bluetooth comunes en el vehículo. También hay muchas mejoras que mejoran el rendimiento y la experiencia con otros dispositivos y servicios.

Administración de conexiones Bluetooth

En Android, CarBluetoothService mantiene los dispositivos Bluetooth y las listas de prioridad del usuario actual para cada conexión de perfil al IVI. Los dispositivos se conectan a los perfiles en un orden de prioridad definido. El momento de habilitar, inhabilitar y conectar dispositivos a un perfil se basa en una política de conexión predeterminada que se puede anular con el uso de una superposición de recursos, si se desea.

Cómo configurar la administración de conexiones para vehículos

Inhabilita la política de teléfono predeterminada

La pila de Bluetooth de Android mantiene una política de conexión para teléfonos que está habilitada de forma predeterminada. Esta política debe estar inhabilitada en el dispositivo para que no entre en conflicto con la política de Automotive prevista en CarBluetoothService. Si bien la superposición de productos para vehículos debería encargarse de esto, puedes inhabilitar la política de teléfonos en una superposición de recursos configurando enable_phone_policy como false en MAXIMUM_CONNECTED_DEVICES en /packages/apps/Bluetooth/res/values/config.xml.

Usa la política predeterminada de Automotive

CarBluetoothService mantiene los permisos de perfil predeterminados. La lista de dispositivos conocidos y sus prioridades de reconexión de perfiles se encuentra en service/src/com/android/car/BluetoothProfileDeviceManager.java.

Además, la política de administración de conexiones Bluetooth se puede encontrar en service/src/com/android/car/BluetoothDeviceConnectionPolicy.java. De forma predeterminada, esta política define instancias en las que Bluetooth debe conectarse a dispositivos vinculados y desconectarse de ellos. También administra casos específicos de vehículos para cuándo se debe encender y apagar el adaptador.

Crea tu propia política de administración de conexiones de Automotive personalizada

Si la política predeterminada de Automotive no es suficiente para tus necesidades, también se puede inhabilitar en favor de tu propia política personalizada. Tu política personalizada, como mínimo, es responsable de determinar cuándo habilitar y deshabilitar el adaptador Bluetooth, así como cuándo conectar dispositivos. Es posible usar una variedad de eventos para habilitar o inhabilitar el adaptador Bluetooth y para iniciar conexiones de dispositivos, incluidos los eventos debido a cambios en propiedades específicas del automóvil.

Inhabilita la política predeterminada de Automotive

En primer lugar, para usar una política personalizada, se debe inhabilitar la política predeterminada de Automotive. Para ello, se debe establecer useDefaultBluetoothConnectionPolicy en false en una superposición de recursos. Este recurso se define originalmente como parte de MAXIMUM_CONNECTED_DEVICES en packages/services/Car/service/res/values/config.xml.

Habilita y desactiva el adaptador Bluetooth

Una de las funciones principales de tu política es encender y apagar el adaptador Bluetooth en los momentos adecuados. Puedes usar las APIs del framework BluetoothAdapter.enable() y BluetoothAdapter.disable() para habilitar y desactivar el adaptador. Estas llamadas deben respetar el estado persistente que el usuario seleccionó a través de Configuración o cualquier otro medio. Una forma de hacerlo es la siguiente:

/**
 * 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);
}

Cómo determinar cuándo activar y desactivar el adaptador Bluetooth

Con tu política personalizada, puedes determinar qué eventos indican los mejores momentos para habilitar y inhabilitar el adaptador. Una de esas formas es usar los estados de energía MAXIMUM_CONNECTED_DEVICES en 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;
        }
    }
};

Cómo determinar cuándo conectar dispositivos

De manera similar, cuando determinas los eventos que deben activar las conexiones de dispositivos para comenzar, CarBluetoothManager proporciona la llamada a la API de connectDevices() que continúa conectando dispositivos según las listas de prioridad definidas para cada perfil de Bluetooth.

Un ejemplo de cuándo podrías querer hacer esto es cada vez que se enciende el adaptador Bluetooth:

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

Verifica la administración de conexiones de Automotive

La forma más sencilla de verificar el comportamiento de tu política de conexión es habilitar Bluetooth en tu IVI y validar que se conecte automáticamente a los dispositivos correctos en el orden adecuado. Puedes activar o desactivar el adaptador Bluetooth a través de la IU de configuración o con los siguientes 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

Además, el resultado del siguiente comando se puede usar para ver la información de depuración relacionada con las conexiones Bluetooth:

adb shell dumpsys car_service

Por último, si compilaste tu propia política de Automotive, verificar cualquier comportamiento de conexión personalizada requiere controlar los eventos que elegiste para activar las conexiones del dispositivo.

Perfiles de Bluetooth para la industria automotriz

En Android, el IVI puede admitir varios dispositivos conectados simultáneamente a través de Bluetooth. Los servicios de telefonía Bluetooth multidispositivo permiten a los usuarios conectar dispositivos independientes de forma simultánea, como un teléfono personal y uno de trabajo, y realizar llamadas con manos libres desde cualquiera de ellos.

Cada perfil Bluetooth individual aplica los límites de conexión, por lo general, dentro de la implementación del servicio de perfil. De forma predeterminada, CarBluetoothService no realiza ningún otro juicio sobre la cantidad máxima de dispositivos conectados permitidos.

Perfil manos libres

El perfil de manos libres Bluetooth (HFP) permite que el vehículo realice y reciba llamadas telefónicas a través de un dispositivo remoto conectado. Cada conexión de dispositivo registra una cuenta de teléfono independiente con TelecomManager, que anuncia las cuentas de teléfono disponibles a las apps de IVI.

El IVI puede conectarse a varios dispositivos a través de HFP. MAX_STATE_MACHINES_POSSIBLE MAXIMUM_CONNECTED_DEVICES en HeadsetClientService define la cantidad máxima de conexiones HFP simultáneas.

Cuando un usuario realiza o recibe una llamada telefónica desde un dispositivo, la cuenta de teléfono correspondiente crea un objeto HfpClientConnection. La app de Teléfono interactúa con el objeto HfpClientConnection para administrar las funciones de llamada, como aceptar una llamada o finalizarla.

Ten en cuenta que la app de Teléfono predeterminada no admite varios dispositivos HFP conectados de forma simultánea. Para implementar HFP multidispositivo, se requiere la personalización para permitir que los usuarios seleccionen qué cuenta de dispositivo usar cuando realicen una llamada. Luego, la app llama a telecomManager.placeCall con la cuenta correcta. Debes verificar que otras funciones multidispositivo también funcionen según lo previsto.

Verifica el HFP multidispositivo

Para verificar que la conectividad multidispositivo funcione correctamente a través de Bluetooth, haz lo siguiente:

  1. Con Bluetooth, conecta un dispositivo al IVI y transmite audio desde él.
  2. Conecta dos teléfonos al IVI a través de Bluetooth.
  3. Elige un teléfono. Realiza una llamada saliente directamente desde el teléfono y con el IVI.
    1. En ambas ocasiones, verifica que se pause el audio transmitido y que el audio del teléfono se reproduzca en las bocinas conectadas a la IVI.
  4. Con el mismo teléfono, recibe una llamada entrante directamente en el teléfono y recibe una llamada entrante con el IVI.
    1. En ambas ocasiones, verifica que se pause el audio de transmisión y que el audio del teléfono se reproduzca en las bocinas conectadas a la IVI.
  5. Repite los pasos 3 y 4 con el otro teléfono conectado.

Llamadas de emergencia

La capacidad de realizar llamadas de emergencia es un aspecto importante de las funciones de telefonía y Bluetooth en el automóvil. Hay varias formas de iniciar una llamada de emergencia desde el IVI, como las siguientes:

  • Solución de llamada de emergencia independiente
  • Solución de llamada de emergencia integrada en el IVI
  • Depender de un teléfono Bluetooth conectado cuando no hay un sistema integrado disponible

Cómo conectar una llamada de emergencia

Si bien el equipo de eCall es fundamental para la seguridad, actualmente no está integrado en Android. Es posible usar ConnectionService para exponer funciones de llamadas de emergencia a través de Android, lo que también tiene el beneficio de presentar opciones de accesibilidad para las llamadas de emergencia. Para obtener más información, consulta Cómo compilar una app de llamadas.

Este es un ejemplo de cómo establecer un ConnectionService de emergencia:

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

Cómo habilitar el Bluetooth para las llamadas de emergencia

Antes de Android 10, las llamadas de emergencia implicaban marcar directamente desde un teléfono e invocar equipo especial si estaba disponible (por ejemplo, activación automática cuando se detectaba un peligro o una acción del usuario). En Android 10 y versiones posteriores, el Dialer en el vehículo puede llamar directamente a un número de emergencia, siempre que este MAXIMUM_CONNECTED_DEVICES en 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>

Si se implementan las llamadas de emergencia de esta manera, otras apps, como el reconocimiento de voz, también pueden llamar a un número de emergencia.

Perfil de acceso a la agenda telefónica

El perfil de acceso a la agenda telefónica (PBAP) de Bluetooth descarga contactos y registros de llamadas desde un dispositivo remoto conectado. PBAP mantiene una lista agregada y que se puede buscar de los contactos que actualiza la máquina de estado del cliente de PBAP. Cada dispositivo conectado interactúa con una máquina de estados de cliente de PBAP independiente, lo que hace que los contactos se asocien con el dispositivo correcto cuando se realiza una llamada.

PBAP es unidireccional y, por lo tanto, requiere que el IVI cree instancias de conexiones a cualquier MAXIMUM_CONNECTED_DEVICES en PbapClientService define la cantidad máxima de conexiones simultáneas de dispositivos PBAP permitidas con el IVI. El cliente de PBAP almacena los contactos de cada dispositivo conectado en el Proveedor de contactos, al que puede acceder una app para derivar la agenda telefónica de cada dispositivo.

Además, el IVI y el dispositivo móvil deben autorizar la conexión del perfil para que se establezca una conexión. Cuando se desconecta un cliente de PBAP, la base de datos interna quita todos los contactos y el historial de llamadas asociados con el dispositivo conectado anteriormente.

Perfil de acceso a mensajes

El perfil de acceso a mensajes (MAP) de Bluetooth permite que el vehículo envíe y reciba mensajes SMS a través de un dispositivo remoto conectado. Actualmente, los mensajes no se almacenan de forma local en el IVI. En cambio, cada vez que el dispositivo remoto conectado recibe un mensaje, el IVI lo recibe y analiza, y transmite su contenido en una instancia de Intent, que una app puede recibir.

Para conectarse a un dispositivo móvil con el fin de enviar y recibir mensajes, el IVI debe iniciar la conexión MAP. MAXIMUM_CONNECTED_DEVICES en MapClientService define la cantidad máxima de conexiones simultáneas de dispositivos MAP permitidas con el IVI. El IVI y el dispositivo móvil deben autorizar cada conexión antes de que se puedan transferir los mensajes.

Perfil de distribución de audio avanzado

El perfil de distribución de audio avanzado (A2DP) de Bluetooth permite que el vehículo reciba transmisiones de audio desde un dispositivo remoto conectado.

A diferencia de otros perfiles, la cantidad máxima de dispositivos A2DP conectados se aplica en la pila nativa y no en Java. Actualmente, el valor está codificado en 1 con la variable kDefaultMaxConnectedAudioDevices en packages/modules/Bluetooth/system/btif/src/btif_av.cc.

Perfil de control remoto de audio y video

El perfil de control remoto de audio/video (AVRCP) de Bluetooth permite que el vehículo controle y explore reproductores multimedia en un dispositivo remoto conectado. Dado que el IVI desempeña el rol de un controlador de AVRCP, cualquier control activado que afecte la reproducción de audio depende de una conexión A2DP al dispositivo de destino.

Para que el IVI pueda explorar un reproductor multimedia específico en un teléfono Android a través de AVRCP, la app de música del teléfono debe proporcionar un MediaBrowserService y permitir que com.android.bluetooth acceda a ese servicio. En Cómo crear un servicio de navegador multimedia, se explica cómo hacerlo en detalle.