Ultrabreitband-Kommunikation (UWB)

Bei der Ultrabreitbandkommunikation handelt es sich um eine Funktechnologie, die auf eine präzise Entfernungsbestimmung zwischen Geräten ausgerichtet ist. Der Standort wird dabei mit einer Genauigkeit von 10 cm gemessen. Diese Funktechnologie kann eine niedrige Energiedichte für Kurzstreckenmessungen verwenden und Signale mit hoher Bandbreite über einen großen Teil des Funkspektrums übertragen. Die UWB-Bandbreite ist größer als 500 MHz (oder übersteigt 20% der Bandbreite).

Verantwortlicher/Initiator im Vergleich zu Kontrollempfänger/Teilnehmer

Die UWB-Kommunikation findet zwischen zwei Geräten statt, wobei eines ein Controller und das andere ein Controlee ist. Der Controller bestimmt den komplexen Kanal (UwbComplexChannel), den die beiden Geräte gemeinsam nutzen, und ist der Initiator, während der Controller der Sender ist, der die Anfrage sendet.

Ein Controller kann mehrere Controlees verarbeiten, aber ein Controlee kann nur einen einzelnen Controller abonnieren. Es werden sowohl Controller-/Initiator- als auch Controlee-/Antwortkonfigurationen unterstützt.

Bereichsparameter

Damit die Rangordnung beginnen kann, müssen sich der Controller und der Controller gegenseitig identifizieren und verschiedene Parameter kommunizieren. Dieser Austausch ist den Anwendungen überlassen, die mit einem sicheren Out-of-Band-Mechanismus (OOB) ihrer Wahl implementiert werden, z. B. Bluetooth Low Energy (BLE).

Zu den Bereichsparametern gehören unter anderem eine lokale Adresse, ein komplexer Kanal und ein Sitzungsschlüssel. Diese Parameter können sich nach Ende der Entfernungssitzung rotieren oder sich anderweitig ändern. Sie müssen noch einmal kommuniziert werden, um die Entfernungsbestimmung neu zu starten.

Hintergrund-Randing

Eine im Hintergrund ausgeführte App kann eine UWB-Bereichsauswahl-Sitzung starten, wenn das Gerät dies unterstützt. Informationen zum Prüfen der Gerätefunktionen finden Sie unter RangingCapabilities.

Die App empfängt keine Entfernungsberichte, wenn sie im Hintergrund ausgeführt wird. Sie erhält nur solche Berichte, wenn sie in den Vordergrund wechselt.

STS-Konfigurationen

Die Anwendung oder der Dienst stellt für jede Sitzung einen Sitzungsschlüssel mit einer verschlüsselten Zeitstempelsequenz (STS) bereit. Bereitgestelltes STS ist sicherer als eine statische STS-Konfiguration. Bereitgestelltes STS wird auf allen UWB-fähigen Geräten mit Android 14 oder höher unterstützt.

Bedrohungskategorie Statisches STS Bereitgestelltes STS
Luft: Passiver Beobachter Mitigated (gemindert) Mitigated (gemindert)
Air: Signalverstärkung Mitigated (gemindert) Mitigated (gemindert)
Luft: Wiederholungs-/Staffelangriff Anfällig Mitigated (gemindert)

Für bereitgestellte STS:

  1. Verwenden Sie die uwbConfigType in RangingParameters, die bereitgestelltes STS unterstützt.

  2. Geben Sie den 16-Byte-Schlüssel im Feld sessionKeyInfo an.

Für statische STS:

  1. Verwenden Sie die uwbConfigType in RangingParameters, die statisches STS unterstützt.

  2. Geben Sie den 8-Byte-Schlüssel im Feld sessionKeyInfo an.

Schritte

So verwenden Sie die UWB-API:

  1. Prüfen Sie mit PackageManager#hasSystemFeature("android.hardware.uwb"), ob Android-Geräte unter Android 12 oder höher ausgeführt werden und UWB unterstützen.
  2. Achten Sie im Falle von IoT-Geräten darauf, dass diese FiRa MAC 1.3-konform sind.
  3. UWB-fähige Peer-Geräte werden mit einem OOB-Mechanismus Ihrer Wahl ermittelt, z. B. BluetoothLeScanner.
  4. Tauschen Sie Bereichsparameter mit einem sicheren OOB-Mechanismus Ihrer Wahl aus, z. B. BluetoothGatt.
  5. Wenn der Nutzer die Sitzung beenden möchte, brechen Sie den Vorgang ab.

Nutzungsbeschränkungen

Für die Nutzung der UWB API gelten die folgenden Einschränkungen:

  1. Die Anwendung, die neue UWB-Bereichsbestimmungssitzungen initiiert, muss eine Anwendung oder ein Dienst im Vordergrund sein, es sei denn, die Entfernungsbestimmung im Hintergrund wird wie oben dargestellt unterstützt.
  2. Wenn die App während einer laufenden Sitzung in den Hintergrund wechselt, erhält sie möglicherweise keine Entfernungsberichte mehr. Die UWB-Sitzung wird jedoch weiterhin auf den unteren Ebenen verwaltet. Wenn die App wieder in den Vordergrund wechselt, werden die reichenden Berichte fortgesetzt.

Codebeispiele

Beispiel-App

Ein End-to-End-Beispiel zur Verwendung der UWB Jetpack-Bibliothek finden Sie in unserer Beispielanwendung auf GitHub. Diese Beispiel-App behandelt die Validierung der UWB-Kompatibilität auf einem Android-Gerät, die Aktivierung der Erkennung über einen OOB-Mechanismus und die Einrichtung von UWB für zwei UWB-fähige Geräte. Das Beispiel deckt auch Anwendungsfälle für die Gerätesteuerung und die Medienfreigabe ab.

UWB-Bereich

In diesem Codebeispiel wird UWB für einen Controlee initiiert und beendet:

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

RxJava3-Unterstützung

Rxjava3-Unterstützung ist jetzt verfügbar, um die Interoperabilität mit Java-Clients zu erreichen. Mit dieser Bibliothek können Sie Bereichsergebnisse als beobachtbaren oder fließenden Stream abrufen und den UwbClientSessionScope als einzelnes Objekt abrufen.

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

Ökosystem-Unterstützung

Im Folgenden finden Sie die unterstützten Partnergeräte und SDKs von Drittanbietern.

UWB-fähige Mobilgeräte

Seit März 2024 unterstützen folgende Geräte die Android UWB Jetpack-Bibliothek:

Anbieter Gerätemodell
Google Pixel 6 Pro, 7 Pro, 8 Pro, Fold, Tablet
Samsung Galaxy Note 20, S21+, S22+, S23+, S24+ Z Fold 2, 3, 4, 5

Drittanbieter-SDKs

Seit April 2023 sind diese Partnerlösungen mit der aktuellen Jetpack-Bibliothek kompatibel.

Bekanntes Problem: Bytereihenfolge für MAC-Adresse und statische STS-Anbieter-ID-Felder umgekehrt

Unter Android 13 und niedriger kehrt der Android UWB-Stack die Bytereihenfolge für die folgenden Felder fälschlicherweise um:

  • MAC-Adresse des Geräts
  • MAC-Zieladresse
  • Anbieter-ID für statische STS

Die Umkehrung der Bytereihenfolge tritt auf, weil der Android-Stack diese Felder als Werte und nicht als Arrays behandelt. Wir arbeiten mit FiRa zusammen, um die UCI-Spezifikation (CR-1112) zu aktualisieren, um explizit anzugeben, dass diese Felder als Arrays behandelt werden sollen.

Dieses Problem wird im 2320XXXX-Release über das GMS Core-Update behoben. Um ab diesem Zeitpunkt mit Android-Geräten kompatibel zu sein, müssen IoT-Anbieter Ihre Implementierung ändern, um eine Umkehrung der Byte-Reihenfolge dieser Felder zu vermeiden.