Comunicazione a banda ultralarga (UWB)

La comunicazione a banda ultralarga è una tecnologia radio incentrata sul rilevamento preciso della distanza (misurando la posizione con una precisione di 10 cm) tra i dispositivi. Questa tecnologia radio può utilizzare una densità di energia a bassa densità per le misurazioni a corto raggio e fornire segnali ad alta larghezza di banda su un'ampia porzione dello spettro radio. La larghezza di banda UWB è superiore a 500 MHz (o supera il 20% della larghezza di banda frazionata).

Titolare/Iniziatore vs. Controllante/Risponditore

La comunicazione UWB avviene tra due dispositivi, di cui uno è un Controller e l'altro è una Controllante. Il controller determina il canale complesso (UwbComplexChannel) che i due dispositivi condivideranno e che è l'iniziatore, mentre il Responsabile del controllo è il responsabile.

Un Titolare può gestire più Titolari del controllo, ma un Titolare può abbonarsi a un solo Titolare. Sono supportate entrambe le configurazioni Controller/Iniziatore e Controllatore/Risponditore.

Intervallo di parametri

Per iniziare l'intervallo, il Titolare e il Controllante devono identificarsi a vicenda e comunicare i vari parametri. Questo scambio viene lasciato alle applicazioni per implementare utilizzando un meccanismo sicuro fuori banda (OOB) di loro scelta, come Bluetooth Low Energy (BLE).

I parametri di gamma includono, tra gli altri, indirizzo locale, canale complesso e chiave di sessione. Tieni presente che questi parametri potrebbero ruotare o cambiare in altro modo al termine della sessione di intervallo e devono essere ricomunicati per riavviare la regolazione.

Intervallo sfondo

Un'app in esecuzione in background può avviare una sessione di rilevamento UWB, se il dispositivo la supporta. Per verificare le funzionalità del tuo dispositivo, visita la pagina RangingCapabilities.

L'app non riceve report sul rilevamento quando viene eseguita in background; riceve report sulla distanza quando viene spostata in primo piano.

Configurazioni STS

L'app o il servizio esegue il provisioning di una chiave di sessione per ogni sessione utilizzando una sequenza di timestamp criptato (STS). Il servizio STS di cui è stato eseguito il provisioning è più sicuro di una configurazione STS statica. Il servizio STS di cui è stato eseguito il provisioning è supportato su tutti i dispositivi abilitati per UWB con Android 14 o versioni successive.

Categoria di minaccia STS statico STS simulato
Aria: osservatore passivo Mitigato Mitigato
Air: amplificazione del segnale Mitigato Mitigato
Air: attacco replica/relay Rischio Mitigato

Per STS di cui è stato eseguito il provisioning:

  1. Utilizza l'elemento uwbConfigType in RangingParameters che supporta STS di cui è stato eseguito il provisioning.

  2. Fornisci la chiave da 16 byte nel campo sessionKeyInfo.

Per STS statico:

  1. In RangingParameters, utilizza uwbConfigType che supporta STS statico.

  2. Fornisci la chiave a 8 byte nel campo sessionKeyInfo.

Passi

Per utilizzare l'API UWB:

  1. Assicurati che i dispositivi Android utilizzino Android 12 o versioni successive e che supportino la tecnologia UWB tramite PackageManager#hasSystemFeature("android.hardware.uwb").
  2. In caso di dispositivi IoT, assicurati che siano conformi a FiRa MAC 1.3.
  3. Scopri i dispositivi peer che supportano la tecnologia UWB utilizzando un meccanismo OOB di tua scelta, come BluetoothLeScanner.
  4. Scambia i parametri utilizzando un meccanismo OOB sicuro di tua scelta, come BluetoothGatt.
  5. Se l'utente vuole interrompere la sessione, annulla l'ambito della sessione.

Limitazioni all'utilizzo

All'uso dell'API UWB si applicano le seguenti restrizioni:

  1. L'app che avvia nuove sessioni di intervallo UWB deve essere un'app o un servizio in primo piano, a meno che l'intervallo in background non sia supportato, come illustrato in precedenza.
  2. Quando l'app passa in background (mentre la sessione è in corso), potrebbe non ricevere più i report sulla distanza. Tuttavia, la sessione UWB continuerà a essere mantenuta nei livelli inferiori. Quando l'app tornerà in primo piano, i report sulla distanza riprenderanno.

Esempi di codice

App di esempio

Per un esempio end-to-end su come utilizzare la libreria UWB Jetpack, consulta la nostra applicazione di esempio su GitHub. Questa app di esempio tratta della convalida della compatibilità UWB su un dispositivo Android, dell'attivazione del processo di rilevamento tramite un meccanismo OOB e della configurazione della tecnologia UWB tra due dispositivi compatibili con UWB. L'esempio tratta anche i casi d'uso relativi al controllo dei dispositivi e alla condivisione di contenuti multimediali.

Intervallo UWB

Questo esempio di codice avvia e termina la tecnologia UWB per un Controllante:

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

Supporto per RxJava3

È ora disponibile il supporto per Rxjava3 per raggiungere l'interoperabilità con i client Java. Questa libreria offre un modo per ottenere risultati di intervallo come flusso Observable o Flowable e per recuperare UwbClientSessionScope come oggetto singolo.

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

Supporto dell'ecosistema

Di seguito sono riportati i dispositivi dei partner e gli SDK di terze parti supportati.

Dispositivi mobili abilitati per UWB

A partire da marzo 2024, i seguenti dispositivi supportano la libreria Android UWB Jetpack:

Fornitore Modello 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, 5

SDK di terze parti

A partire da aprile 2023, queste soluzioni dei partner sono compatibili con la libreria Jetpack attuale.

Problema noto: ordine dei byte invertito per i campi di indirizzi MAC e ID fornitore STS statici

Su Android 13 e versioni precedenti, lo stack UWB di Android inverte erroneamente l'ordine dei byte per i seguenti campi:

  • Indirizzo MAC del dispositivo
  • Indirizzo MAC di destinazione
  • ID fornitore STS statico

L'inversione dell'ordine dei byte si verifica perché lo stack di Android tratta questi campi come valori, non come array. Stiamo collaborando con FiRa per aggiornare la specifica UCI (CR-1112) in modo da indicare esplicitamente che questi campi devono essere trattati come array.

Questo problema verrà risolto tramite l'aggiornamento di GMS Core nella release 2320XXXX. Per essere conformi ai dispositivi Android da quel momento in poi, i fornitori di IoT devono modificare la tua implementazione per evitare di invertire l'ordine in byte di questi campi.