Ubicación Wi-Fi: rangos con RTT

Puedes utilizar la función de ubicación Wi-Fi que proporciona la API de Wi-Fi RTT (tiempo de ida y vuelta) para medir la distancia a los puntos de acceso Wi-Fi con capacidad RTT cercanos y a los dispositivos pares Wi-Fi Aware.

Si mides la distancia a tres o más puntos de acceso, puedes usar un algoritmo de multilateración para calcular la posición del dispositivo que mejor se adecue a esas medidas. Por lo general, la diferencia en la precisión es de 1 a 2 metros.

Gracias a esta precisión, puedes desarrollar servicios basados en la ubicación detallados, como la navegación interior, el control por voz sin ambigüedades (por ejemplo, "Enciende esta luz") e información basada en la ubicación (por ejemplo, "¿Hay ofertas especiales para este producto?").

El dispositivo solicitante no necesita conectarse a los puntos de acceso para medir la distancia con Wi-Fi RTT. Para mantener la privacidad, solo el dispositivo solicitante puede para determinar la distancia hasta el punto de acceso; los puntos de acceso no tienen esta información. Las operaciones de Wi-Fi RTT son ilimitadas para las apps en primer plano, pero son limitadas para las que se ejecutan en segundo plano.

Wi-Fi RTT y las funciones relacionadas de medición del tiempo (FTM) según la especificación del estándar IEEE 802.11-2016. Wi-Fi RTT requiere la medición precisa del tiempo proporcionada por FTM, ya que calcula la distancia entre dos dispositivos midiendo el tiempo que tarda un paquete en ir y volver entre ellos, y multiplicando ese tiempo por la velocidad de la luz.

Android 15 (nivel de API 35) introdujo la compatibilidad con el rango basado en no activadores (NTB) IEEE 802.11az.

Diferencias de implementación basadas en la versión de Android

Wi-Fi RTT se introdujo en Android 9 (API nivel 28). Cuando usas este protocolo para determinar la posición de un dispositivo mediante la multilateración en dispositivos que ejecutan Android 9, debes tener acceso a datos de ubicaciones de puntos de acceso (PA) predeterminados en tu app. Tú decides cómo almacenar y recuperar estos datos.

En los dispositivos con Android 10 (API nivel 29) y versiones posteriores, los datos de ubicación de PA se pueden representar como objetos ResponderLocation, lo que incluye latitud, longitud y altitud. En el caso de los PA de Wi-Fi RTT que admiten datos Location Configuration Information/Location Civic Report (LCI/LCR), el protocolo mostrará un objeto ResponderLocation durante el proceso de creación de rangos.

Esta función permite a las apps consultar a los PA para solicitarles su posición de forma directa en lugar de tener que almacenar esa información de manera anticipada. De esta forma, tu app puede encontrar PA y determinar sus posiciones incluso si antes no se conocían esos PA, como cuando un usuario entra en un nuevo edificio.

La compatibilidad con el rango de NTB IEEE 802.11az está disponible en dispositivos que ejecutan Android 15 (nivel de API 35) y versiones posteriores. Por lo tanto, si el dispositivo es compatible con el estándar Modo iniciador NTB (indicado por WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR), tu app puede encontrar AP compatibles con IEEE 802.11mc y IEEE 802.11az con un solo rango de solicitudes. Se extendió la API de RangingResult para proporcionar información. acerca del valor mínimo y máximo que se puede utilizar para el intervalo entre diferentes mediciones, dejando el intervalo exacto en el control de tu app.

Requisitos

  • El hardware del dispositivo que realiza la solicitud de rango debe implementar la estándar FTM 802.11-2016 o estándar 802.11az (rango no basado en disparadores).
  • El dispositivo que realiza esa solicitud debe ejecutar Android 9 (API nivel 28) o una versión posterior. El rango no basado en activadores de IEEE 802.11az está habilitado en los dispositivos con Android 15 (nivel de API 35) y versiones posteriores.
  • El dispositivo que realiza la solicitud de rango debe tener habilitados los servicios de ubicación y la búsqueda de Wi-Fi (en Configuración > Ubicación).
  • Si la app que realiza la solicitud de rango se orienta a Android 13 (nivel de API 33) o versiones posteriores, debe tener el permiso NEARBY_WIFI_DEVICES. Si dicha app se orienta a una versión anterior de Android, debe tener el ACCESS_FINE_LOCATION permiso en su lugar.
  • La app debe consultar el rango de puntos de acceso mientras está visible o en un servicio en primer plano. La app no puede acceder a información de ubicación en segundo plano.
  • El punto de acceso debe implementar el estándar FTM IEEE 802.11-2016 o el estándar IEEE 802.11az (detección de rango no basada en activadores).

Configuración

A fin de configurar tu app para que utilice Wi-Fi RTT, sigue estos pasos.

1. Solicita permisos

Solicita los siguientes permisos en el manifiesto de tu app:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- If your app targets Android 13 (API level 33)
     or higher, you must declare the NEARBY_WIFI_DEVICES permission. -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
                 <!-- If your app derives location information from Wi-Fi APIs,
                      don't include the "usesPermissionFlags" attribute. -->
                 android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
                 <!-- If any feature in your app relies on precise location
                      information, don't include the "maxSdkVersion"
                      attribute. -->
                 android:maxSdkVersion="32" />

Los permisos NEARBY_WIFI_DEVICES y ACCESS_FINE_LOCATION son peligrosos, por lo que debes solicitarlos durante el tiempo de ejecución cada vez que el usuario quiera realizar una operación de análisis RTT. Tu app deberá solicitar el permiso del usuario si aún no lo recibió. Para obtener más información sobre los permisos durante el tiempo de ejecución, consulta Cómo solicitar permisos de apps.

2. Comprueba si el dispositivo es compatible con Wi-Fi RTT

Para comprobar si el dispositivo es compatible con Wi-Fi RTT, utiliza la API de PackageManager:

Kotlin

context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)

Java

context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT);

3. Comprueba si hay Wi-Fi RTT disponible

Es posible que el dispositivo cuente con Wi-Fi RTT, pero puede que no esté disponible tiene inhabilitada la conexión Wi-Fi. Según las capacidades de hardware y firmware, algunas Es posible que los dispositivos no admitan Wi-Fi RTT si se usa SoftAP o una conexión mediante dispositivo móvil. Para comprobar si Wi-Fi RTT está disponible, llama isAvailable()

La disponibilidad de Wi-Fi RTT puede cambiar en cualquier momento. Tu app debe registrar un BroadcastReceiver para recibir ACTION_WIFI_RTT_STATE_CHANGED, que se envía cuando cambia la disponibilidad. Cuando tu app recibe el intent de transmisión, debe comprobar el estado actual de disponibilidad y ajustar su comportamiento en consecuencia.

Por ejemplo:

Kotlin

val filter = IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED)
val myReceiver = object: BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (wifiRttManager.isAvailable) {
            …
        } else {
            …
        }
    }
}
context.registerReceiver(myReceiver, filter)

Java

IntentFilter filter =
    new IntentFilter(WifiRttManager.ACTION_WIFI_RTT_STATE_CHANGED);
BroadcastReceiver myReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (wifiRttManager.isAvailable()) {
            …
        } else {
            …
        }
    }
};
context.registerReceiver(myReceiver, filter);

Para obtener más información, consulta Transmisiones.

Cómo crear una solicitud de rango

Una solicitud de rango (RangingRequest) se creó especificando una lista de pares de Wi-Fi Aware con los que un rango una solicitud. Se pueden especificar múltiples puntos de acceso o pares Wi-Fi Aware en una sola solicitud de rango; se miden y se muestran las distancias a todos los dispositivos.

Por ejemplo, una solicitud puede utilizar el método addAccessPoint() para especificar un punto de acceso con el cual medir la distancia:

Kotlin

val req: RangingRequest = RangingRequest.Builder().run {
    addAccessPoint(ap1ScanResult)
    addAccessPoint(ap2ScanResult)
    build()
}

Java

RangingRequest.Builder builder = new RangingRequest.Builder();
builder.addAccessPoint(ap1ScanResult);
builder.addAccessPoint(ap2ScanResult);

RangingRequest req = builder.build();

Un punto de acceso se identifica por su objeto ScanResult, que se puede obtener llamando a WifiManager.getScanResults(). Puedes usar addAccessPoints(List<ScanResult>) para agregar varios puntos de acceso en un lote.

Los objetos ScanResult pueden contener IEEE 802.11mc (is80211mcResponder()) y Compatible con el rango no basado en activadores (is80211azNtbResponder()) en IEEE 802.11az AP Los dispositivos que admiten el rango de NTB IEEE 802.11az realizan el rango de 802.11mc o 802.11az según la capacidad del AP, y de forma predeterminada, 802.11az cuando el AP admite ambos. Los dispositivos que no admiten el estándar IEEE 802.11az realizan todas con el protocolo IEEE 802.11mc.

De forma similar, una solicitud de rango puede agregar una app similar con reconocimiento de Wi-Fi usando su dirección MAC o su PeerHandle, con el addWifiAwarePeer(MacAddress peer) y addWifiAwarePeer(PeerHandle peer) de forma manual, respectivamente. Para obtener más información sobre cómo descubrir los pares Wi-Fi Aware, consulta la documentación de Wi-Fi Aware.

Cómo solicitar rangos

Una aplicación emite una solicitud de rango utilizando la WifiRttManager.startRanging() y proporciona lo siguiente: RangingRequest para especificar una operación, un Executor para especificar el contexto de devolución de llamada RangingResultCallback para recibir los resultados.

Por ejemplo:

Kotlin

val mgr = context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE) as WifiRttManager
val request: RangingRequest = myRequest
mgr.startRanging(request, executor, object : RangingResultCallback() {

    override fun onRangingResults(results: List<RangingResult>) { … }

    override fun onRangingFailure(code: Int) { … }
})

Java

WifiRttManager mgr =
      (WifiRttManager) Context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE);

RangingRequest request ...;
mgr.startRanging(request, executor, new RangingResultCallback() {

  @Override
  public void onRangingFailure(int code) { … }

  @Override
  public void onRangingResults(List<RangingResult> results) { … }
});

La operación de rango se realiza de forma asíncrona y los resultados se muestran en una de las devoluciones de llamada de RangingResultCallback:

  • Si falla toda la operación de rango, se activa la devolución de llamada onRangingFailure con un código de estado descrito en RangingResultCallback. Este tipo de falla puede producirse si el servicio no puede ejecutar una operación de rango en ese momento, por ejemplo, porque la conexión Wi-Fi está inhabilitada, porque la aplicación solicitó demasiadas operaciones de rango y está limitada, o por una cuestión de permisos.
  • Cuando finaliza la operación de rango, el onRangingResults se activa la devolución de llamada con una lista de resultados que coincide con solicitudes, un resultado para cada solicitud. El orden de los resultados no coincide necesariamente con el de las solicitudes. Ten en cuenta que la operación de rango puede completarse, pero cada resultado puede indicar una falla de esa medición específica.

Cómo interpretar los resultados de rango

Cada uno de los resultados que muestra la devolución de llamada onRangingResults se especifica con un objeto RangingResult. En cada solicitud, haz lo siguiente.

1. Identifica la solicitud

Identifica la solicitud según la información proporcionada al crear la RangingRequest: la mayoría de las veces, es una dirección MAC proporcionada en el archivo ScanResult que identifica un acceso punto. La dirección MAC puede obtenerse a partir del resultado del análisis utilizando el método getMacAddress().

La lista de resultados de rango puede estar en un orden diferente al de los pares (puntos de acceso) especificados en la solicitud de rango, por lo que debes utilizar la dirección MAC para identificar el par, no el orden de los resultados.

2. Determina si se realizó correctamente cada medición

Para determinar si se realizó correctamente una medición, utiliza el método getStatus(). Cualquier valor que no sea STATUS_SUCCESS indica un error. Un error significa que todos los demás campos de este resultado (excepto la identificación de la solicitud anterior) no son válidas, y la correspondiente El método get* fallará y mostrará un Excepción IllegalStateException.

3. Obtén resultados para cada medición que se haya realizado correctamente

Para cada medición exitosa (RangingResult), puedes recuperar el resultado de salida con los respectivos métodos get:

  • Distancia, en mm, y la desviación estándar de la medición:

    getDistanceMm()

    getDistanceStdDevMm()

  • RSSI de los paquetes utilizados para las mediciones:

    getRssi()

  • Tiempo en milisegundos en el que se realizó la medición (indicando el tiempo desde el inicio):

    getRangingTimestampMillis()

  • Cantidad de mediciones que se intentaron y cantidad de mediciones que se realizaron correctamente (y en las que se basan las mediciones de distancia):

    getNumAttemptedMeasurements()

    getNumSuccessfulMeasurements()

  • Tiempo mínimo y máximo que un dispositivo cliente debe esperar entre mediciones de NTB de 11az:

    getMinTimeBetweenNtbMeasurementsMicros() y getMaxTimeBetweenNtbMeasurementsMicros() devuelven el tiempo mínimo y máximo. Si la siguiente medición de rango es solicitado antes de que transcurra el tiempo mínimo, la API devuelve resultado de rango almacenado en caché. Si se solicita la siguiente medición de rango después de ha transcurrido el tiempo máximo, la API cancela el de rango y negocia una nueva con el participante estación. Debes evitar solicitar una nueva sesión de rango, ya que agrega sobrecarga al tiempo de medición del rango. Para aprovechar 802.11az al máximo eficiencia de rango no basada en activadores, activar la siguiente solicitud de rango entre el tiempo de medición mínimo y máximo especificado en la Medición de RangingResult.

  • Repetición de campo de entrenamiento largo (LTF) que establece estaciones de iniciador y responde usada en el preámbulo del resultado de NTB de IEEE 802.11az:

    get80211azResponderTxLtfRepetitionsCount()

    get80211azInitiatorTxLtfRepetitionsCount()

  • Cantidad de transmisiones de tiempo espacial (STS) de transmisión y recepción que el iniciador para el resultado de la norma IEEE 802.11az NTB:

    get80211azNumberOfTxSpatialStreams()

    get80211azNumberOfRxSpatialStreams()

Dispositivos Android que admiten WiFi RTT

En las siguientes tablas, se muestran algunos teléfonos, puntos de acceso y dispositivos de centros de distribución, almacenamiento y venta minorista que admiten WiFi-RTT. Estos datos no son exhaustivos. Te recomendamos comunicarte con nosotros para que tus productos que admiten RTT se muestren aquí.

Puntos de acceso

Fabricante y modelo Fecha en la que se brindó compatibilidad
Nest Wifi Pro (Wi-Fi 6E) Compatible
Compulab WILD AP Compatible
Wi-Fi de Google Compatible
Router Wi-Fi de Google Nest Compatible
Punto de Wi-Fi de Google Nest Compatible
Aruba AP-635 Compatible
Cisco 9130 Compatible
Cisco 9136 Compatible
Cisco 9166 Compatible
Cisco 9164 Compatible
Aruba AP-505 Compatible
Aruba AP-515 Compatible
Aruba AP-575 Compatible
Aruba AP-518 Compatible
Aruba AP-505H Compatible
Aruba AP-565 Compatible
Aruba AP-535 Compatible

Teléfonos

Fabricante y modelo Versión de Android
Pixel 6 9.0 y versiones posteriores
Pixel 6 Pro 9.0 y versiones posteriores
Pixel 5 9.0 y versiones posteriores
Pixel 5a 9.0 y versiones posteriores
Pixel 5a 5G 9.0 y versiones posteriores
Xiaomi Mi 10 Pro 9.0 y versiones posteriores
Xiaomi Mi 10 9.0 y versiones posteriores
Xiaomi Redmi Mi 9T Pro 9.0 y versiones posteriores
Xiaomi Mi 9T 9.0 y versiones posteriores
Xiaomi Mi 9 9.0 y versiones posteriores
Xiaomi Mi Note 10 9.0 y versiones posteriores
Xiaomi Mi Note 10 Lite 9.0 y versiones posteriores
Xiaomi Redmi Note 9S 9.0 y versiones posteriores
Xiaomi Redmi Note 9 Pro 9.0 y versiones posteriores
Xiaomi Redmi Note 8T 9.0 y versiones posteriores
Xiaomi Redmi Note 8 9.0 y versiones posteriores
Xiaomi Redmi K30 Pro 9.0 y versiones posteriores
Xiaomi Redmi K20 Pro 9.0 y versiones posteriores
Xiaomi Redmi K20 9.0 y versiones posteriores
Xiaomi Redmi Note 5 Pro 9.0 y versiones posteriores
Xiaomi Mi CC9 Pro 9.0 y versiones posteriores
LG G8X ThinQ 9.0 y versiones posteriores
LG V50S ThinQ 9.0 y versiones posteriores
LG V60 ThinQ 9.0 y versiones posteriores
LG V30 9.0 y versiones posteriores
Samsung Galaxy Note 10+ 5G 9.0 y versiones posteriores
Samsung Galaxy S20+ 5G 9.0 y versiones posteriores
Samsung Galaxy S20+ 9.0 y versiones posteriores
Samsung Galaxy S20 con tecnología 5G 9.0 y versiones posteriores
Samsung Galaxy S20 Ultra con tecnología 5G 9.0 y versiones posteriores
Samsung Galaxy S20 9.0 y versiones posteriores
Samsung Galaxy Note 10+ 9.0 y versiones posteriores
Samsung Galaxy Note 10 5G 9.0 y versiones posteriores
Samsung Galaxy Note 10 9.0 y versiones posteriores
Samsung A9 Pro 9.0 y versiones posteriores
Google Pixel 4 XL 9.0 y versiones posteriores
Google Pixel 4 9.0 y versiones posteriores
Google Pixel 4a 9.0 y versiones posteriores
Google Pixel 3 XL 9.0 y versiones posteriores
Google Pixel 3 9.0 y versiones posteriores
Google Pixel 3a XL 9.0 y versiones posteriores
Google Pixel 3a XL 9.0 y versiones posteriores
Google Pixel 2 XL 9.0 y versiones posteriores
Google Pixel 2 9.0 y versiones posteriores
Google Pixel 1 XL 9.0 y versiones posteriores
Google Pixel 1 9.0 y versiones posteriores
Poco X2 9.0 y versiones posteriores
Sharp Aquos R3 SH-04L 9.0 y versiones posteriores

Dispositivos de centros de distribución, almacenamiento y venta minorista

Fabricante y modelo Versión de Android
Zebra PS20 10.0 o posterior
Zebra TC52/TC52HC 10.0 o posterior
Zebra TC57 10.0 o posterior
Zebra TC72 10.0 o posterior
Zebra TC77 10.0 o posterior
Zebra MC93 10.0 o posterior
Zebra TC8300 10.0 o posterior
Zebra VC8300 10.0 o posterior
Zebra EC30 10.0 o posterior
Zebra ET51 10.0 o posterior
Zebra ET56 10.0 o posterior
Zebra L10 10.0 o posterior
Zebra CC600/CC6000 10.0 o posterior
Zebra MC3300x 10.0 o posterior
Zebra MC330x 10.0 o posterior
Zebra TC52x 10.0 o posterior
Zebra TC57x 10.0 o posterior
Zebra EC50 (LAN y HC) 10.0 o posterior
Zebra EC55 (WAN) 10.0 o posterior
Zebra WT6300 10.0 o posterior
Skorpio X5 10.0 o posterior