Comunicación de banda ultraancha (UWB)

La comunicación de banda ultraancha es una tecnología de radio centrada en el rango preciso (mide la ubicación con una precisión de 10 cm) entre dispositivos. Esta tecnología de radio puede usar una densidad de baja energía para mediciones de corto alcance y realizar señales de alto ancho de banda en una gran parte del espectro de radio. El ancho de banda de UWB es superior a 500 MHz (o excede el 20% del ancho de banda fraccionario).

Responsable del tratamiento de datos en comparación con el usuario de control o la persona que responde

La comunicación con UWB se produce entre dos dispositivos: uno es un controlador y el otro es un controlador. El controlador determina el canal complejo (UwbComplexChannel) que compartirán los dos dispositivos y es el iniciador, mientras que el controlador es el que responde.

Un controlador puede manejar varios Controle, pero un Controlee solo puede suscribirse a un solo controlador. Se admiten las configuraciones de controlador/iniciador y de controlador/responsable.

Parámetros de rango

El controlador y el controlador deben identificarse entre sí y comunicar los parámetros de rango para comenzar a hacerlo. Las aplicaciones deben implementar este intercambio mediante un mecanismo seguro fuera de banda (OOB) de su elección, como Bluetooth de bajo consumo (BLE).

Entre los parámetros de rango, se incluyen la dirección local, el canal complejo y la clave de sesión, entre otros. Ten en cuenta que estos parámetros pueden rotar o cambiar de otra manera una vez que finaliza la sesión de rango, y se deben comunicar para reiniciar el rango.

Rango de fondo

Una app que se ejecuta en segundo plano puede iniciar una sesión de rango de UWB si el dispositivo es compatible. Para verificar las funciones de tu dispositivo, consulta RangingCapabilities.

La app no recibe informes de rango cuando se ejecuta en segundo plano, sino que lo hace cuando pasa al primer plano.

Parámetros de configuración de STS

La app o el servicio aprovisiona una clave de sesión para cada sesión mediante una secuencia de marcas de tiempo desordenadas (STS). El STS aprovisionado es más seguro que una configuración de STS estática. El STS aprovisionado es compatible con todos los dispositivos habilitados para UWB que ejecutan Android 14 o versiones posteriores.

Categoría de amenaza STS estático STS aprovisionado
Air: observador pasivo Mitigado Mitigado
Aire: Amplificación de señal Mitigado Mitigado
Aire: Ataque de repetición/retransmisión Susceptibles Mitigado

Para STS aprovisionado:

  1. Usa uwbConfigType en RangingParameters que admita STS aprovisionado.

  2. Proporciona la clave de 16 bytes en el campo sessionKeyInfo.

Para STS estático:

  1. Usa uwbConfigType en RangingParameters que admita STS estático.

  2. Proporciona la clave de 8 bytes en el campo sessionKeyInfo.

Pasos

Para usar la API de UWB, sigue estos pasos:

  1. Asegúrate de que los dispositivos Android ejecuten Android 12 o versiones posteriores y de que admitan UWB con PackageManager#hasSystemFeature("android.hardware.uwb").
  2. Si se comparan con dispositivos de IoT, asegúrate de que cumplan con FiRa MAC 1.3.
  3. Descubre dispositivos de pares compatibles con UWB a través del mecanismo de OOB que elijas, como BluetoothLeScanner.
  4. Intercambia parámetros de rango mediante el mecanismo de OOB seguro que elijas, como BluetoothGatt.
  5. Si el usuario quiere detener la sesión, cancela su alcance.

Restricciones de uso

Las siguientes restricciones se aplican al uso de la API de UWB:

  1. La app que inicia nuevas sesiones de rango de UWB debe ser una app o un servicio en primer plano, a menos que se admita el rango en segundo plano como se mostró antes.
  2. Cuando la app pasa a segundo plano (mientras la sesión está en curso), es posible que ya no reciba informes de rango. Sin embargo, la sesión de UWB se seguirá manteniendo en las capas inferiores. Cuando la app vuelva a primer plano, se reanudarán los informes de rango.

Muestras de código

App de ejemplo

Para ver un ejemplo de extremo a extremo sobre cómo usar la biblioteca de UWB de Jetpack, consulta nuestra aplicación de ejemplo en GitHub. Esta app de ejemplo abarca la validación de la compatibilidad con UWB en un dispositivo Android, la habilitación del proceso de descubrimiento mediante un mecanismo de OOB y la configuración de UWB entre dos dispositivos compatibles con UWB. En esta muestra, también se abordan casos de uso de control de dispositivos y uso compartido de contenido multimedia.

Rango de UWB

Esta muestra de código inicia y finaliza el rango de UWB para un usuario de control:

// The coroutineScope responsible for handling uwb ranging.
// This will be initialized when startRanging is called.
var job: Job?

// A code snippet that initiates uwb ranging for a Controlee.
suspend fun startRanging() {

    // Get the ranging parameter of a partnering Controller using an OOB mechanism of choice.
    val partnerAddress : Pair<UwbAddress, UwbComplexChannel> = listenForPartnersAddress()

    // Create the ranging parameters.
    val partnerParameters = RangingParameters(
        uwbConfigType = UwbRangingParameters.UWB_CONFIG_ID_1,
        // SessionKeyInfo is used to encrypt the ranging session.
        sessionKeyInfo = null,
        complexChannel = partnerAddress.second,
        peerDevices = listOf(UwbDevice.createForAddress(partnerAddress.first)),
        updateRateType = UwbRangingParameters.RANGING_UPDATE_RATE_AUTOMATIC
    )

    // Initiate a session that will be valid for a single ranging session.
    val clientSession = uwbManager.clientSessionScope()

    // Share the localAddress of the current session to the partner device.
    broadcastMyParameters(clientSession.localAddress)

    val sessionFlow = clientSession.prepareSession(partnerParameters)

    // Start a coroutine scope that initiates ranging.
    CoroutineScope(Dispatchers.Main.immediate).launch {
        sessionFlow.collect {
            when(it) {
                is RangingResultPosition -> doSomethingWithPosition(it.position)
                is RangingResultPeerDisconnected -> peerDisconnected(it)
            }
        }
    }
}

// A code snippet that cancels uwb ranging.
fun cancelRanging() {

    // Canceling the CoroutineScope will stop the ranging.
    job?.let {
        it.cancel()
    }
}

Compatibilidad con RxJava3

La compatibilidad con Rxjava3 ahora está disponible para ayudar a lograr la interoperabilidad con los clientes de Java. Esta biblioteca proporciona una forma de obtener resultados de rango como una transmisión observable o Flowable y de recuperar el UwbClientSessionScope como un objeto único.

private final UwbManager uwbManager;

// Retrieve uwbManager.clientSessionScope as a Single object
Single<UwbClientSessionScope> clientSessionScopeSingle =
                UwbManagerRx.clientSessionScopeSingle(uwbManager);
UwbClientSessionScope uwbClientSessionScope = clientSessionScopeSingle.blockingGet();

// Retrieve uwbClientSessionScope.prepareSession Flow as an Observable object
Observable<RangingResult> rangingResultObservable =
                UwbClientSessionScopeRx.rangingResultsObservable(clientSessionScope,
                        rangingParameters);

// Consume ranging results from Observable
rangingResultObservable.subscribe(
   rangingResult -> doSomethingWithRangingResult(result), // onNext
   (error) -> doSomethingWithError(error), // onError
   () -> doSomethingOnResultEventsCompleted(), //onCompleted
);
// Unsubscribe
rangingResultObservable.unsubscribe();
   

// Retrieve uwbClientSessionScope.prepareSession Flow as a Flowable object
Flowable<RangingResult> rangingResultFlowable =
                UwbClientSessionScopeRx.rangingResultsFlowable(clientSessionScope,
                        rangingParameters);

// Consume ranging results from Flowable using Disposable
Disposable disposable = rangingResultFlowable
   .delay(1, TimeUnit.SECONDS)
   .subscribeWith(new DisposableSubscriber<RangingResult> () {
      @Override public void onStart() {
          request(1);
      }
      
      @Override public void onNext(RangingResult rangingResult) {
             doSomethingWithRangingResult(rangingResult);
             request(1);
      }


      @Override public void onError(Throwable t) {
             t.printStackTrace();
      }


         @Override public void onComplete() {
            doSomethingOnEventsCompleted();
         }
   });

// Stop subscription
disposable.dispose();

Compatibilidad con el ecosistema

Estos son los dispositivos de socios y SDK de terceros compatibles.

Dispositivos móviles compatibles con UWB

A partir de marzo de 2024, estos dispositivos admiten la biblioteca de Jetpack para UWB de Android:

Proveedor Modelo del dispositivo
Google Pixel 6 Pro, 7 Pro, 8 Pro, Fold, tablet
Samsung Galaxy Note 20, S21+, S22+, S23+, S24+ Z Fold 2, 3, 4 y 5

SDKs de terceros

A partir de abril de 2023, estas soluciones de socios son compatibles con la biblioteca actual de Jetpack.

Problema conocido: Se revirtió el orden de bytes para la dirección MAC y los campos estáticos de ID del proveedor de STS

En Android 13 y versiones anteriores, la pila de UWB de Android revierte de manera incorrecta el orden de bytes para los siguientes campos:

  • Dirección MAC del dispositivo
  • Dirección MAC de destino
  • ID del proveedor de STS estático

La reversión del orden de bytes se produce porque la pila de Android trata estos campos como valores, no como arrays. Estamos trabajando con FiRa para actualizar la especificación de UCI (CR-1112) y establecer de forma explícita que estos campos deben tratarse como arreglos.

Este problema se solucionará a través de la actualización de GMS Core en la versión 2320XXXX. Para cumplir con los dispositivos Android a partir de ese momento, los proveedores de IoT deben modificar tu implementación para evitar revertir el orden de bytes de estos campos.