Localização de Wi-Fi: alcance com RTT

Você pode usar o recurso de localização de Wi-Fi fornecido pela API Wi-Fi RTT (Round-Trip-Time) para medir a distância dos pontos de acesso e dos dispositivos Wi-Fi Aware próximos e compatíveis com RTT.

Ao medir a distância de até três ou mais pontos de acesso, será possível usar um algoritmo de multilateração para estimar a posição do dispositivo que melhor se encaixa nessas medidas. Normalmente, o resultado é preciso a uma distância de 1 a 2 metros.

Com esse nível de precisão, é possível criar serviços aprimorados baseados na localização, como a navegação interna, o controle de voz sem ambiguidades (por exemplo, "acenda esta luz") e informações baseadas na localização (por exemplo, "este produto tem ofertas especiais?").

O dispositivo que faz a solicitação não precisa se conectar aos pontos de acesso para medir a distância com o Wi-Fi RTT. Para manter a privacidade, somente o dispositivo solicitante pode para determinar a distância até o ponto de acesso; os pontos de acesso não têm essas informações. As operações de Wi-Fi RTT são ilimitadas para aplicativos em primeiro plano, mas não para os em segundo plano.

O RTT do Wi-Fi e os recursos de Medição de tempo fino (FTM, na sigla em inglês) relacionados são especificados pela norma IEEE 802.11-2016. O Wi-Fi RTT exige o uso da medição de tempo precisa fornecida pelo FTM, já que ele calcula a distância medindo o tempo que um pacote leva para fazer uma viagem de ida e volta entre dois dispositivos e depois multiplica esse tempo pela velocidade da luz.

O Android 15 (nível 35 da API) introduziu suporte para o IEEE 802.11az de determinação de alcance não baseada em gatilho (NTB, na sigla em inglês).

Diferenças de implementação baseadas na versão Android

O Wi-Fi RTT foi introduzido no Android 9 (API de nível 28). Para usar esse protocolo para determinar a posição de um dispositivo usando multilateration com dispositivos que executam o Android 9, você precisará ter acesso aos dados de localização do ponto de acesso (AP, na sigla em inglês) predeterminados no seu aplicativo. Você pode decidir a melhor forma de armazenar e recuperar esses dados.

Em dispositivos que executam Android 10 (API de nível 29) e versões mais recentes, os dados da localização do ponto de acesso podem ser representados por objetos ResponderLocation, que incluem latitude, longitude e altitude. Para os pontos de acesso do Wi-Fi RTT compatíveis com informações de configuração da localização/relatório cívico de localização (dados de LCI/LCR), o protocolo retornará um objeto ResponderLocation durante o processo de alcance.

Esse recurso permite que os aplicativos consultem diretamente os pontos de acesso para solicitar a posição deles, em vez de precisar armazenar essas informações antecipadamente. Dessa forma, seu aplicativo poderá encontrar pontos de acesso e determinar as posições relacionadas, mesmo que esses pontos sejam desconhecidos. Por exemplo, quando um usuário entra em um novo prédio.

O suporte ao alcance NTB IEEE 802.11az está disponível em dispositivos com o Android 15 (nível 35 da API) e mais recentes. Isso significa que, se o dispositivo oferecer suporte a IEEE 802.11az, Modo iniciador do NTB (indicado por WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR), seu app pode encontrar APs compatíveis com IEEE 802.11mc e IEEE 802.11az com um único de intervalo de endereços IP. A API RangingResult foi estendida para fornecer informações sobre os valores mínimo e máximo que podem ser usados para o intervalo entre o alcance de medições, deixando o intervalo exato no controle do aplicativo.

Requisitos

  • O hardware do dispositivo que faz a solicitação de alcance precisa implementar o padrão de FTM 802.11-2016 ou 802.11az (alcance não baseado em gatilho).
  • O dispositivo que faz a solicitação de alcance precisa executar o Android 9 (API de nível 28) ou versão mais recente. O alcance sem gatilho IEEE 802.11az é ativado em dispositivos com o Android 15 (nível 35 da API) e versões mais recentes.
  • O dispositivo que faz a solicitação de alcance precisa ter a busca por Wi-Fi e os serviços de localização ativados (em Configurações > Localização).
  • Se o app que faz a solicitação de alcance segmentar Android 13 (nível 33 da API) ou versões mais recentes, ele precisa ter a NEARBY_WIFI_DEVICES permissão. Se um aplicativo é direcionado a uma versão anterior do Android, ele precisa têm os ACCESS_FINE_LOCATION no lugar da permissão.
  • O aplicativo deve consultar o alcance de pontos de acesso enquanto o aplicativo está visível ou em um serviço em primeiro plano. O aplicativo não pode acessar as informações de localização em segundo plano.
  • O ponto de acesso precisa implementar o padrão de FTM IEEE 802.11-2016 ou o padrão IEEE 802.11az (alcance não baseado em gatilho).

Configurar

Se você quiser configurar o aplicativo para usar o Wi-Fi RTT, siga estas etapas:

1. Solicite permissões

Solicite as seguintes permissões no manifesto do 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" />

As permissões NEARBY_WIFI_DEVICES e ACCESS_FINE_LOCATION são perigosas. Por isso, você precisa solicitá-las no tempo de execução toda vez que o usuário quiser realizar uma operação de verificação de RTT. Seu app precisará solicitar a permissão se ela ainda não tiver sido concedida. Para mais informações sobre permissões do tempo de execução, consulte Solicitar permissões do app.

2. Verifique se o dispositivo é compatível com Wi-Fi RTT

Para verificar se o dispositivo é compatível com Wi-Fi RTT, use a API PackageManager:

Kotlin

context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)

Java

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

3. Verifique se o Wi-Fi RTT está disponível

O Wi-Fi RTT pode estar presente no dispositivo, mas não estar disponível porque o usuário desativou o Wi-Fi. Dependendo dos recursos de hardware e firmware, alguns dispositivos podem não ser compatíveis com o Wi-Fi RTT se o SoftAP ou o tethering estiverem em uso. Para verificar se o Wi-Fi RTT está disponível, chame isAvailable().

A disponibilidade do Wi-Fi RTT pode mudar a qualquer momento. Seu aplicativo deve registrar um BroadcastReceiver para receber ACTION_WIFI_RTT_STATE_CHANGED, que é enviado quando a disponibilidade muda. Ao receber o intent de transmissão, seu aplicativo deverá verificar o estado atual da disponibilidade e ajustar o próprio comportamento de acordo com essa informação.

Por exemplo:

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 mais informações, consulte Visão geral de transmissões.

Criar uma solicitação de alcance

Uma solicitação de alcance (RangingRequest) é criado especificando uma lista de APs ou pontos Wi-Fi Aware aos quais um intervalo é solicitado. É possível especificar vários pontos de acesso ou pontos do Wi-Fi Aware em uma única solicitação. As distâncias para todos os dispositivos são medidas e retornadas.

Por exemplo, uma solicitação pode usar addAccessPoint() para especificar um ponto de acesso para o qual medir a distância:

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

Um ponto de acesso é identificado pelo objeto ScanResult, que pode ser recebido chamando WifiManager.getScanResults(). Você pode usar addAccessPoints(List<ScanResult>) para adicionar vários pontos de acesso em um lote.

Objetos ScanResult podem conter IEEE 802.11mc (is80211mcResponder()) e Compatível com alcance não baseado em gatilho (is80211azNtbResponder()) IEEE 802.11az APs. Os dispositivos compatíveis com o intervalo NTB IEEE 802.11az executam 802.11mc ou 802.11az variando dependendo da capacidade do AP, deixando o padrão 802.11az quando o AP oferece suporte a ambos. Os dispositivos que não oferecem suporte ao IEEE 802.11az realizam todo o alcance usando o protocolo IEEE 802.11mc.

Da mesma forma, uma solicitação de alcance pode adicionar um ponto do Wi-Fi Aware usando o endereço MAC ou o PeerHandle, com os métodos addWifiAwarePeer(MacAddress peer) e addWifiAwarePeer(PeerHandle peer), respectivamente. Para mais informações sobre como descobrir pontos do Wi-Fi Aware, consulte a documentação do Wi-Fi Aware.

Solicitar o alcance

Um app envia uma solicitação de alcance usando o método WifiRttManager.startRanging() e fornecendo as seguintes informações: um RangingRequest para especificar a operação, um Executor para especificar o contexto do callback e um RangingResultCallback para receber os resultados.

Exemplo:

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) { … }
});

A operação de alcance é executada de forma assíncrona, e os resultados são retornados em um dos callbacks de RangingResultCallback:

  • Se a operação de alcance falhar, o callback onRangingFailure será acionado com um código de status descrito em RangingResultCallback. Esse erro ocorrerá caso o serviço não possa executar uma operação de alcance no momento. Por exemplo, o Wi-Fi está desativado, o aplicativo ultrapassou o limite de solicitações de alcance ou devido a um problema de permissão.
  • Quando a operação de alcance for concluída, o callback onRangingResults será acionado com uma lista de resultados que corresponde à lista de solicitações, um resultado para cada solicitação. A ordem dos resultados não corresponderá necessariamente à das solicitações. A operação de alcance talvez seja concluída, mas cada resultado ainda poderá indicar uma falha nessa medição específica.

Interpretar os resultados de alcance

Cada um dos resultados retornados pelo callback onRangingResults é especificado por um objeto RangingResult. Em cada solicitação, faça o seguinte:

1. Identifique a solicitação

Identifique a solicitação com base nas informações fornecidas ao criar o RangingRequest: na maioria das vezes, é um endereço MAC fornecido no ScanResult que identifica um ponto de acesso. O endereço MAC pode ser obtido a partir do resultado de alcance usando o getMacAddress() .

A lista de resultados de alcance pode estar em ordem diferente dos pontos (pontos de acesso) especificados na solicitação. Por isso, use o endereço MAC para identificar o ponto, não a ordem dos resultados.

2. Determine se cada medição foi concluída

Para determinar se uma medição foi bem-sucedida, use o getStatus() . Qualquer valor que não seja STATUS_SUCCESS indica uma falha. Uma falha significa que todos os outros campos desse resultado (exceto a identificação da solicitação acima) são inválidos, e o método get* correspondente vai falhar com uma exceção IllegalStateException.

3. Veja os resultados para cada medição concluída

Para cada medição concluída (RangingResult), é possível recuperar o resultado com os respectivos métodos get:

  • Confira a distância em mm e o desvio padrão da medição:

    getDistanceMm()

    getDistanceStdDevMm()

  • Veja o RSSI dos pacotes utilizados para as medições:

    getRssi()

  • Confira o tempo em milissegundos da mediação (indicando o tempo desde a inicialização):

    getRangingTimestampMillis()

  • Saiba o número de tentativas de medição e quantos processos foram concluídos (e em quais ocorrências a medição da distância se baseia):

    getNumAttemptedMeasurements()

    getNumSuccessfulMeasurements()

  • Tempo mínimo e máximo que um dispositivo cliente precisa esperar entre as medições de NTB 11az:

    getMinTimeBetweenNtbMeasurementsMicros() e getMaxTimeBetweenNtbMeasurementsMicros() retornam o tempo mínimo e máximo. Se a próxima medição de alcance for solicitado antes que o tempo mínimo tenha decorrido, a API retornará o resultado de alcance armazenado em cache. Se a próxima medição de alcance for solicitada após o tempo máximo decorrido, a API encerra o não acionador de alcance e negocia uma nova sessão com o responsável estação Evite solicitar uma nova sessão de alcance, porque isso adiciona sobre o intervalo de tempo de medição. Para aproveitar ao máximo a eficiência de medição sem gatilho do 802.11az, acione a próxima solicitação de medição entre o tempo de medição mínimo e máximo especificado na medição RangingResult anterior.

  • Repetições de campo de treinamento longo (LTF, na sigla em inglês) que as estações de acionadores e de resposta usaram no preâmbulo para o resultado de NTB do IEEE 802.11az:

    get80211azResponderTxLtfRepetitionsCount()

    get80211azInitiatorTxLtfRepetitionsCount()

  • Número de streams de tempo espacial (STS) de transmissão e recebimento que a estação iniciadora usou para o resultado de NTB do IEEE 802.11az:

    get80211azNumberOfTxSpatialStreams()

    get80211azNumberOfRxSpatialStreams()

Dispositivos Android compatíveis com Wi-Fi RTT

As tabelas a seguir listam alguns smartphones, pontos de acesso e dispositivos de varejo, armazém e centro de distribuição compatíveis com o WiFi-RTT. Elas não abrangem todos os dispositivos compatíveis. Entre em contato conosco para listar seus produtos compatíveis com RTT aqui.

Pontos de acesso

Fabricante e Modelo Data de suporte
Nest Wifi Pro (Wi-Fi 6E) Compatível
Compulab WILD AP Compatível
Google Wi-Fi Compatível
Roteador Google Nest Wifi Compatível
Ponto Google Nest Wifi Compatível
Aruba AP-635 (link em espanhol) Compatível
Cisco 9130 Compatível
Cisco 9136 Compatível
Cisco 9166 Compatível
Cisco 9164 Compatível
Aruba AP-505 Compatível
Aruba AP-515 Compatível
Aruba AP-575 Compatível
Aruba AP-518 Compatível
AP-505H de Aruba Compatível
Aruba AP-565 Compatível
AP-535 de Aruba Compatível

Smartphones

Fabricante e Modelo Versão do Android
Pixel 6 9.0+
Pixel 6 Pro 9.0+
Pixel 5 9.0+
Pixel 5a 9.0+
Pixel 5a (5G) 9.0+
Xiaomi Mi 10 Pro 9.0+
Xiaomi Mi 10 9.0+
Xiaomi Redmi Mi 9T Pro 9.0+
Xiaomi Mi 9T 9.0+
Xiaomi Mi 9 9.0+
Xiaomi Mi Note 10 9.0+
Xiaomi Mi Note 10 Lite 9.0+
Xiaomi RedMi Note 9S 9.0+
Xiaomi Redmi Note 9 Pro 9.0+
Xiaomi Redmi Note 8T 9.0+
Xiaomi RedMi Note 8 9.0+
Xiaomi Redmi K30 Pro 9.0+
Xiaomi Redmi K20 Pro 9.0+
Xiaomi RedMi K20 9.0+
Xiaomi Redmi Note 5 Pro 9.0+
Xiaomi Mi CC9 Pro 9.0+
LG G8X ThinQ 9.0+
LG V50S ThinQ 9.0+
LG V60 ThinQ 9.0+
LG V30 9.0+
Samsung Galaxy Note 10+ 5G 9.0+
Samsung Galaxy S20+ 5G 9.0+
Samsung Galaxy S20+ 9.0+
Samsung Galaxy S20 5G 9.0+
Samsung Galaxy S20 Ultra 5G 9.0+
Samsung Galaxy S20 9.0+
Samsung Galaxy Note 10 ou mais recente 9.0+
Samsung Galaxy Note 10 5G 9.0+
Samsung Galaxy Note 10 9.0+
Samsung A9 Pro 9.0+
Google Pixel 4 XL 9.0+
Google Pixel 4 9.0+
Google Pixel 4a 9.0+
Google Pixel 3 XL 9.0+
Google Pixel 3 9.0+
Google Pixel 3a XL 9.0+
Google Pixel 3a 9.0+
Google Pixel 2 XL 9.0+
Google Pixel 2 9.0+
Google Pixel 1 XL 9.0+
Google Pixel 1 9.0+
Poco x2 9.0+
Sharp Aquos R3 SH-04L 9.0+

Dispositivos para centros de distribuição, armazenamento e varejo

Fabricante e Modelo Versão do Android
Zebra PS20 10.0+
Zebra TC52/TC52HC 10.0 ou superior
Zebra TC57 10.0+
Zebra TC72 10.0 ou superior
Zebra TC77 10.0 ou superior
Zebra MC93 10.0+
Zebra TC8300 10.0 ou superior
Zebra VC8300 10.0 ou superior
Zebra EC30 10.0 ou superior
Zebra ET51 10.0 ou superior
Zebra ET56 10.0 ou superior
Zebra L10 10.0 ou superior
Zebra CC600/CC6000 10.0 ou superior
Zebra MC3300x 10.0 ou superior
Zebra MC330x 10.0+
Zebra TC52x 10.0+
Zebra TC57x 10.0 ou superior
Zebra EC50 (LAN e HC) 10.0 ou superior
Zebra EC55 (WAN) 10.0 ou superior
Zebra WT6300 10.0+
Skorpio X5 10.0+