Zasięg między urządzeniami

Android 16 wprowadza moduł Ranging, który zapewnia ujednolicony i standardowy interfejs do precyzyjnego określania odległości między urządzeniami. Za pomocą tego interfejsu API możesz mierzyć odległość i pozycję urządzeń w pobliżu bez konieczności obsługiwania poszczególnych technologii pomiaru odległości.

Moduł Ranging obsługuje te technologie:

Możliwości i dostępność pomiaru odległości

Klasa RangingManager udostępnia aplikacjom informacje o technologiach pomiaru odległości obsługiwanych przez urządzenie lokalne, a także o dostępności i możliwościach każdej z nich. Aplikacje mogą zarejestrować się w Callback, aby otrzymywać aktualizacje dotyczące zmian w dostępności lub możliwości dowolnych obsługiwanych technologii.

Role urządzenia

Urządzenie biorące udział w sesji pomiaru odległości musi być inicjatorem lub odpowiadającym. Urządzenie inicjujące rozpoczyna sesję pomiaru odległości z 1 lub większą liczbą urządzeń odpowiadających. Urządzenie odpowiadające odpowiada na żądania pomiaru odległości tylko jednego inicjatora naraz. Rolę danego urządzenia w sesji pomiaru odległości możesz określić za pomocą klasy RangingPreference.

Typy sesji pomiarowych

Podczas rozpoczynania sesji pomiaru odległości między urządzeniami często konieczne jest ustanowienie transportu danych poza pasmem (OOB) w celu wymiany parametrów sesji.

Moduł Ranging może obsługiwać negocjacje OOB, ale obsługuje też niestandardowe implementacje OOB.

Rysunek 1. Przepływ OOB dla typów sesji.

Domyślna implementacja OOB

W tym typie sesji (RANGING_SESSION_OOB) moduł Ranging obsługuje negocjacje OOB w celu rozpoczęcia sesji pomiaru odległości. Wybiera odpowiednie parametry na podstawie preferencji dotyczących pomiaru odległości podanych przez aplikację i korzysta z odpowiednich technologii w zależności od tego, co obsługują oba urządzenia. Ten typ sesji korzysta ze standardowego OOB specification.

Moduł Ranging określa tylko format danych OOB i sekwencję, które mają być używane do interakcji z urządzeniem równorzędnym. Nie obsługuje wykrywania urządzeń w pobliżu ani nawiązywania połączenia.

Niestandardowa implementacja OOB

W tym typie sesji (RANGING_SESSION_RAW) aplikacja pomija proces OOB modułu Ranging i samodzielnie obsługuje negocjacje i parametry OOB. Oznacza to, że aplikacja musi określić, jakie technologie obsługuje urządzenie w pobliżu, wynegocjować parametry pomiaru odległości i rozpocząć sesję pomiaru.

Ustawienia pomiaru odległości

Użyj obiektu RangingPreference, aby określić wybrane parametry sesji pomiarowej. między innymi na następujące działania:

  • Rola urządzenia Określa, czy urządzenie będzie inicjatorem czy odbiorcą.
  • Konfiguracja pomiaru odległości Obiekt RangingConfig określa typ sesji pomiaru odległości i inne parametry potrzebne do jej rozpoczęcia.
  • Konfiguracja sesji Obiekt SessionConfig określa parametry, które mają być stosowane w sesji pomiaru odległości, takie jak limit pomiaru, fuzja czujników, konfiguracja geofencingu i inne.

Uprawnienia do pomiaru odległości

Moduł pomiaru odległości wymaga nowego, ujednoliconego uprawnienia (android.permission.RANGING), aby mieć dostęp do wszystkich obecnych i przyszłych technologii pomiaru odległości. To uprawnienie znajduje się na liście NEARBY_DEVICES_PERMISSIONS.

<uses-permission android:name="android.permission.RANGING" />

Ograniczenia

Moduł pomiaru odległości może ograniczać pomiar z kilku powodów, w tym:

  • Aplikacje innych firm mogą wykonywać pomiary w tle tylko za pomocą technologii UWB i tylko na obsługiwanych urządzeniach. Określanie odległości w tle za pomocą innych technologii jest niedozwolone.
  • Określanie odległości jest niedozwolone, gdy osiągnięto maksymalną liczbę równoczesnych sesji określania odległości na urządzenie.
  • Zakres może być ograniczony ze względu na stan systemu, np. baterię, wydajność lub pamięć.

Moduł pomiaru odległości ma też te znane ograniczenia:

  • Moduł pomiaru odległości obsługuje tylko przesyłanie danych pomiaru odległości do urządzeń równorzędnych w przypadku ultraszerokopasmowego. W przypadku innych technologii moduł pomiaru odległości dostarcza dane o odległości tylko do urządzenia inicjującego.
  • Moduł pomiaru odległości obsługuje tylko dynamiczne dodawanie urządzeń w trybie pomiaru odległości w formacie surowym i tylko w przypadku technologii UWB.
  • Moduł Ranging nie obsługuje sesji ultraszerokopasmowych typu „jeden do wielu” w przypadku domyślnych implementacji OOB. Jeśli przekażesz kilka uchwytów urządzeń, moduł utworzy sesję 1:1 dla każdego urządzenia równorzędnego, które obsługuje technologię UWB.

Przeprowadzanie sesji pomiarowej

Aby przeprowadzić sesję pomiaru odległości za pomocą modułu Ranging, wykonaj te czynności:

  1. Sprawdź, czy wszystkie urządzenia działają na Androidzie 16 lub nowszym.
  2. Poproś o android.permission.RANGING uprawnienia w pliku manifestu aplikacji.
  3. Ocena możliwości i dostępności technologii pomiaru odległości.
  4. Wykrywanie urządzenia równorzędnego do pomiarów odległości.
  5. Nawiąż połączenie w celu wymiany danych poza pasmem, korzystając z jednego z typów sesji opisanych w sekcji Typy sesji pomiarowych.
  6. Rozpocznij pomiar odległości i ciągle zbieraj dane o odległości.
  7. Zakończ sesję pomiaru odległości.

Poniższy przykładowy kod pokazuje te kroki w przypadku roli inicjatora i roli odpowiadającego.

Kotlin

class RangingApp {

    // Starts a ranging session on the initiator side.
    fun startRangingInitiator(
        context: Context,
        deviceHandle: DeviceHandle,
        executor: Executor,
        callback: RangingSessionCallback
    ) {

        // Get the RangingManager which is the entry point for ranging module.
        val manager = context.getSystemService(RangingManager::class.java)

        // Create a new RangingSession using the provided executor and callback.
        val session = manager.createRangingSession(executor, callback)

        // Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
        // the initiator role.
        val config = OobInitiatorRangingConfig.Builder()
            .setFastestRangingInterval(Duration.ofMillis(100))
            .setSlowestRangingInterval(Duration.ofMillis(5000))
            .setRangingMode(RANGING_MODE_AUTO)
            .setSecurityLevel(SECURITY_LEVEL_BASIC)
            .addDeviceHandle(deviceHandle)
            .build()

        // Create a RangingPreference, which specifies the role (initiator) and
        // configuration for the ranging session.
        val preference =
            RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build()

        // Start ranging session.
        session.start(preference)

        // If successful, the ranging data will be sent through callback#onResults

        // Stop ranging session
        session.stop()
    }

    // Starts a ranging session on the responder side.
    fun startRangingResponder(
        context: Context,
        deviceHandle: DeviceHandle,
        executor: Executor,
        callback: RangingSessionCallback
    ) {

        // Get the RangingManager which is the entry point for ranging module.
        val manager = context.getSystemService(RangingManager::class.java)

        // Create a new RangingSession using the provided executor and callback.
        val session = manager.createRangingSession(executor, callback)

        // Create an OobResponderRangingConfig, which specifies the ranging parameters for
        // the responder role.
        val config = OobResponderRangingConfig.Builder(deviceHandle).build()

        // Create a RangingPreference, which specifies the role (responder) and
        // configuration for the ranging session.
        val preference =
            RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build()

        // Start the ranging session.
        session.start(preference)

        // Stop the ranging session
        session.stop()
    }
}

Java

public class RangingApp {

    // Starts a ranging session on the initiator side.
    void startRangingInitiator(Context context, DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {

        // Get the RangingManager which is the entry point for ranging module.
        RangingManager manager = context.getSystemService(RangingManager.class);

        // Create a new RangingSession using the provided executor and callback.
        RangingSession session = manager.createRangingSession(executor, callback);

        // Create an OobInitiatorRangingConfig, which specifies the ranging parameters for
        // the initiator role.
        OobInitiatorRangingConfig config = new OobInitiatorRangingConfig.Builder()
                .setFastestRangingInterval(Duration.ofMillis(100))
                .setSlowestRangingInterval(Duration.ofMillis(5000))
                .setRangingMode(RANGING_MODE_AUTO)
                .setSecurityLevel(SECURITY_LEVEL_BASIC)
                .addDeviceHandle(deviceHandle)
                .build();

        // Create a RangingPreference, which specifies the role (initiator) and
        // configuration for the ranging session.
        RangingPreference preference =
                new RangingPreference.Builder(DEVICE_ROLE_INITIATOR, config).build();

        // Start ranging session.
        session.start(preference);

        // If successful, the ranging data will be sent through callback#onResults

        // Stop ranging session
        session.stop();

    }

    // Starts a ranging session on the responder side.
    void startRangingResponder(Context context,  DeviceHandle deviceHandle, Executor executor, RangingSessionCallback callback) {

        // Get the RangingManager which is the entry point for ranging module.
        RangingManager manager = context.getSystemService(RangingManager.class);

        // Create a new RangingSession using the provided executor and callback.
        RangingSession session = manager.createRangingSession(executor, callback);

        // Create an OobResponderRangingConfig, which specifies the ranging parameters for
        // the responder role.
        OobResponderRangingConfig config = new OobResponderRangingConfig.Builder(  deviceHandle).build();

        // Create a RangingPreference, which specifies the role (responder) and
        // configuration for the ranging session.
        RangingPreference preference =
                new RangingPreference.Builder(DEVICE_ROLE_RESPONDER, config).build();

        // Start the ranging session.
        session.start(preference);

        // Stop the ranging session
        session.stop();
    }
}

Współdziałanie UWB z urządzeniami z iOS

Moduł Ranging obsługuje współdziałanie z urządzeniami z iOS za pomocą łącza ultraszerokopasmowego (UWB). Aby określić odległość za pomocą urządzenia z iOS, musisz użyć niestandardowej implementacji OOB i skonfigurować sesję określania odległości za pomocą określonych parametrów, które są zgodne z protokołem akcesoriów Apple Nearby Interaction. W celu uzyskania dodatkowych informacji zapoznaj się z przykładową aplikacją.

Podczas tworzenia elementu RangingPreference użyj elementów RawRangingDeviceUwbRangingParams, aby określić konfigurację. Te parametry są kluczowe dla interoperacyjności z iOS:

  • Identyfikator konfiguracji: użyj UwbRangingParams.CONFIG_UNICAST_DS_TWR.
  • Informacje o kluczu sesji: podaj tablicę bajtów zawierającą identyfikator dostawcy i statyczny wektor inicjujący STS.
  • Złożony kanał: ustaw numer kanału i indeks preambuły tak, aby pasowały do konfiguracji urządzenia z iOS.

Poniższy fragment kodu pokazuje, jak utworzyć RangingPreference na potrzeby określania odległości od urządzenia inicjującego za pomocą urządzenia odpowiadającego z iOS:

Kotlin

// Create UwbRangingParams with iOS-specific configuration
val uwbRangingParams = UwbRangingParams.Builder(
    sessionId,
    UwbRangingParams.CONFIG_UNICAST_DS_TWR,
    sourceAddress,
    destinationAddress
)
    .setComplexChannel(
        UwbComplexChannel.Builder()
            .setChannel(channelNumber)
            .setPreambleIndex(preambleIndex)
            .build()
    )
    .setRangingUpdateRate(updateRate)
    .setSessionKeyInfo(sessionKeyInfo) // Vendor ID + STS IV
    .setSlotDuration(slotDuration)
    .build()

// Create RawRangingDevice
val rawRangingDevice = RawRangingDevice.Builder()
    .setRangingDevice(RangingDevice.Builder().build())
    .setUwbRangingParams(uwbRangingParams)
    .build()

// Create SessionConfig
val sessionConfig = SessionConfig.Builder()
    .setAngleOfArrivalNeeded(true)
    .setDataNotificationConfig(DataNotificationConfig.Builder()
        .setNotificationConfigType(DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE)
        .build())
    .build()

// Create RangingPreference for the initiator
val preference = RangingPreference.Builder(
    RangingPreference.DEVICE_ROLE_INITIATOR,
    RawInitiatorRangingConfig.Builder()
        .addRawRangingDevice(rawRangingDevice)
        .build()
)
    .setSessionConfig(sessionConfig)
    .build()

Java

// Create UwbRangingParams with iOS-specific configuration
UwbRangingParams uwbRangingParams = new UwbRangingParams.Builder(
        sessionId,
        UwbRangingParams.CONFIG_UNICAST_DS_TWR,
        sourceAddress,
        destinationAddress)
        .setComplexChannel(new UwbComplexChannel.Builder()
                .setChannel(channelNumber)
                .setPreambleIndex(preambleIndex)
                .build())
        .setRangingUpdateRate(updateRate)
        .setSessionKeyInfo(sessionKeyInfo) // Vendor ID + STS IV
        .setSlotDuration(slotDuration)
        .build();

// Create RawRangingDevice
RawRangingDevice rawRangingDevice = new RawRangingDevice.Builder()
        .setRangingDevice(new RangingDevice.Builder().build())
        .setUwbRangingParams(uwbRangingParams)
        .build();

// Create SessionConfig
SessionConfig sessionConfig = new SessionConfig.Builder()
        .setAngleOfArrivalNeeded(true)
        .setDataNotificationConfig(new DataNotificationConfig.Builder()
                .setNotificationConfigType(DataNotificationConfig.NOTIFICATION_CONFIG_ENABLE)
                .build())
        .build();

// Create RangingPreference for the initiator
RangingPreference preference = new RangingPreference.Builder(
        RangingPreference.DEVICE_ROLE_INITIATOR,
        new RawInitiatorRangingConfig.Builder()
                .addRawRangingDevice(rawRangingDevice)
                .build())
        .setSessionConfig(sessionConfig)
        .build();

UWB Downlink-TDoA API

Informacje o interfejsie UWB DL-TDoA API znajdziesz w artykule Nowe funkcje Androida 17.

Przykładowa aplikacja

Kompletny przykład użycia modułu Ranging znajdziesz w przykładowej aplikacji w AOSP. Ta przykładowa aplikacja obejmuje wszystkie technologie pomiaru odległości obsługiwane przez moduł Ranging i zawiera przepływy dla obu obsługiwanych typów sesji.

Współdziałanie UWB z urządzeniami z iOS

Przykładowa aplikacja na Androida obsługuje rozpoczynanie sesji pomiaru odległości UWB za pomocą przykładowej aplikacji na iOS.

Rysunek 2. korzystanie z UWB na urządzeniach z Androidem i iOS;