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 determinar a distância até o ponto de acesso. Os pontos de acesso não têm essa informação. As operações de Wi-Fi RTT são ilimitadas para aplicativos em primeiro plano, mas não para os em segundo plano.

O Wi-Fi RTT e os recursos de medição de tempo preciso (FTM, na sigla em inglês) são especificados pelo padrão 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 IEEE 802.11az NTB está disponível em dispositivos com o Android 15 (nível 35 da API) e versões mais recentes. Isso significa que, se o dispositivo for compatível com o modo de iniciador IEEE 802.11az NTB (indicado por WifiRttManager.CHARACTERISTICS_KEY_BOOLEAN_NTB_INITIATOR), o app poderá encontrar APs compatíveis com IEEE 802.11mc e IEEE 802.11az com uma única solicitação de alcance. A API RangingResult foi ampliada para fornecer informações sobre o valor mínimo e máximo que pode ser usado para o intervalo entre medições de alcance, deixando o intervalo exato sob o controle do app.

Requisitos

  • O hardware do dispositivo que faz a solicitação de alcance precisa implementar o padrão de FTM 802.11-2016 ou o padrão 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 está fazendo a solicitação de medição de distância for direcionado ao Android 13 (nível 33 da API) ou mais recente, ele precisará ter a permissão NEARBY_WIFI_DEVICES. Se o app for destinado a uma versão anterior do Android, ele precisará ter a permissão ACCESS_FINE_LOCATION.
  • 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 do usuário caso ela ainda não tenha 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 app precisa 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) é criada especificando uma lista de pontos de acesso ou pontos do Wi-Fi Aware para os quais um alcance é 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 o método addAccessPoint() para especificar um ponto de acesso e fazer a medição da distância correspondente:

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.

Os objetos ScanResult podem conter APs com suporte para IEEE 802.11mc (is80211mcResponder()) e IEEE 802.11az (is80211azNtbResponder()) de medição de distância sem gatilho. Os dispositivos com suporte para o alcance NTB IEEE 802.11az executam o alcance 802.11mc ou 802.11az, dependendo da capacidade do AP, com 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 saber mais 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 método 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 concluída, use o método getStatus(). Qualquer valor diferente de 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 valores de 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 solicitada antes do tempo mínimo, a API vai retornar o resultado de alcance armazenado em cache. Se a próxima medição de alcance for solicitada após o tempo máximo ter decorrido, a API encerrará a sessão de alcance não acionado e negociará uma nova sessão de alcance com a estação que responder. Evite solicitar uma nova sessão de medição, porque isso aumenta a sobrecarga do 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 mínimo e máximo de medição especificado na medição RangingResult anterior.

  • Repetições de campo de treinamento longo (LTF, na sigla em inglês) que as estações de acionador 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 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
Aruba AP-505H Compatível
Aruba AP-565 Compatível
Aruba AP-535 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+ 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 de varejo, centro de distribuição e armazém

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