Comunicação de banda ultralarga (UWB)

A comunicação de banda ultralarga é uma tecnologia de rádio focada em alcance preciso (medição do local com precisão de 10 cm) entre dispositivos. Essa tecnologia de rádio pode usar uma densidade de baixa energia para medições de curto alcance e realizar sinalização de alta largura de banda em uma grande parte do espectro do rádio. A largura de banda da UWB é maior que 500 MHz (ou excede 20% da largura de banda fracionária).

Controlador/iniciador x controlado/resposta automática

A comunicação UWB ocorre entre dois dispositivos, em que um é um controlador e o outro é um controlee. O controlador determina o canal complexo (UwbComplexChannel) que os dois dispositivos vão compartilhar e é o iniciador, enquanto o controle é o respondedor.

Um controlador pode processar vários controles, mas um controle só pode se inscrever em um único controlador. As configurações de controlador/iniciador e de controle/respondedor são aceitas.

Parâmetros de alcance

O controlador e o controle precisam se identificar e comunicar os parâmetros de alcance para iniciar o processo. Essa troca é deixada para os aplicativos implementarem usando um mecanismo seguro fora da banda (OOB, na sigla em inglês) de escolha, como Bluetooth de baixa energia (BLE).

Os parâmetros de alcance incluem endereço local, canal complexo e chave de sessão, entre outros. Observe que esses parâmetros podem girar ou mudar depois que a sessão de medição de distância terminar e precisar ser comunicada novamente para reiniciar a medição.

Detecção de distância em segundo plano

Um app em execução em segundo plano pode iniciar uma sessão de medição de UWB se o dispositivo oferecer suporte a ela. Para verificar os recursos do seu dispositivo, consulte RangingCapabilities.

O app não recebe relatórios de alcance quando é executado em segundo plano. Ele recebe relatórios de alcance quando passa para o primeiro plano.

Configurações de STS

O app ou serviço provisiona uma chave de sessão para cada sessão usando uma sequência de carimbo de data/hora codificada (STS, na sigla em inglês). O STS provisionado é mais seguro do que uma configuração STS estática. O STS provisionado tem suporte em todos os dispositivos com UWB e Android 14 ou mais recente.

Categoria de ameaça STS estático STS provisionado
Ar: observador passivo Mitigada Mitigada
Ar: amplificação de sinal Mitigada Mitigada
Air: ataque de repetição/retransmissão Suscetível Mitigada

Para STS provisionadas:

  1. Use o uwbConfigType em RangingParameters que oferece suporte ao STS provisionado.

  2. Forneça a chave de 16 bytes no campo sessionKeyInfo.

Para STS estáticas:

  1. Use o uwbConfigType em RangingParameters que oferece suporte a STS estático.

  2. Forneça a chave de 8 bytes no campo sessionKeyInfo.

Etapas

Para usar a API UWB, siga estas etapas:

  1. Confira se os dispositivos Android estão executando o Android 12 ou mais recente e se eles têm suporte para UWB usando PackageManager#hasSystemFeature("android.hardware.uwb").
  2. Se o intervalo for contra dispositivos IoT, verifique se eles são compatíveis com o FiRa MAC 1.3.
  3. Descubra dispositivos peer compatíveis com UWB usando um mecanismo OOB de sua escolha, como BluetoothLeScanner.
  4. Troque os parâmetros de medição usando um mecanismo OOB seguro de sua escolha, como BluetoothGatt.
  5. Se o usuário quiser interromper a sessão, cancele o escopo dela.

Restrições de uso

As seguintes restrições se aplicam ao uso da API UWB:

  1. O app que inicia novas sessões de medição de UWB precisa ser um app ou serviço em primeiro plano, a menos que a medição em segundo plano tenha suporte, conforme ilustrado anteriormente.
  2. Quando o app é movido para segundo plano (enquanto a sessão está em andamento), ele pode não receber mais relatórios de variação. No entanto, a sessão UWB continuará sendo mantida nas camadas inferiores. Quando o app volta para o primeiro plano, os relatórios de alcance são retomados.

Exemplos de código

App de exemplo

Para conferir um exemplo completo de como usar a biblioteca UWB Jetpack, consulte nosso aplicativo de exemplo no GitHub. Este app de exemplo abrange a validação da compatibilidade com UWB em um dispositivo Android, a ativação do processo de descoberta usando um mecanismo OOB e a configuração do alcance UWB entre dois dispositivos com suporte a UWB. O exemplo também abrange casos de uso de controle de dispositivo e compartilhamento de mídia.

Ranging UWB

Este exemplo de código inicia e encerra a medição de distância UWB para um Controlee:

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

Suporte ao RxJava3

O suporte ao Rxjava3 agora está disponível para ajudar a alcançar a interoperabilidade com clientes Java. Essa biblioteca oferece uma maneira de receber resultados de alcance como um stream Observable ou Flowable e de extrair o UwbClientSessionScope como um 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();

Suporte ao ecossistema

Confira os dispositivos de parceiros e SDKs de terceiros compatíveis.

Dispositivos móveis com UWB

A partir de janeiro de 2025, estes dispositivos oferecem suporte à biblioteca do Android Jetpack UWB:

Fornecedor Modelo do dispositivo
Google Pixel Pro (6 Pro e versões mais recentes), Fold e Tablet
Motorola Edge 50 Ultra
Samsung Galaxy Note 20, Galaxy Plus e Ultra (S21 e versões mais recentes), Galaxy Z Fold (Fold2 e versões mais recentes)

Observação: a medição de UWB em segundo plano tem suporte em todos os dispositivos, exceto:

  • Pixel 6 Pro e Pixel 7 Pro.
  • Smartphones Samsung com o Android 13 ou versões anteriores.
  • Smartphones Samsung chineses com Android 14 ou versões anteriores.

SDKs de terceiros

Desde abril de 2023, essas soluções de parceiros são compatíveis com a biblioteca atual do Jetpack.

Problema conhecido: a ordem de bytes foi invertida para o endereço MAC e os campos de ID do fornecedor STS estático.

No Android 13 e versões anteriores, a pilha UWB do Android inverte incorretamente a ordem de bytes para os seguintes campos:

  • Endereço MAC do dispositivo
  • Endereço MAC de destino
  • ID do fornecedor da STS estática

A inversão da ordem de bytes ocorre porque a pilha do Android trata esses campos como valores, não matrizes. Estamos trabalhando com a FiRa para atualizar a especificação do UCI (CR-1112) para declarar explicitamente que esses campos devem ser tratados como matrizes.

Esse problema será corrigido com a atualização do GMS Core na versão 2320XXXX. Para serem compatíveis com dispositivos Android a partir desse ponto, os fornecedores de IoT precisam modificar a implementação para evitar a inversão da ordem de bytes desses campos.