Use a funcionalidade de localização por Wi-Fi fornecida pela API Wi-Fi RTT (tempo de retorno) para medir a distância até pontos de acesso Wi-Fi compatíveis com RTT e dispositivos Wi-Fi Aware próximos.
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 essa precisão, é possível desenvolver serviços com base na localização detalhados, como navegação em ambientes fechados, controle de voz sem ambiguidade (por exemplo, "Acenda esta luz") e informações com base na localização (por exemplo, "Há ofertas especiais para este produto?").
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, apenas o dispositivo solicitante pode 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 Wi-Fi RTT e os recursos relacionados de medição de tempo de alta precisão (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 medição de distância não baseada em acionador (NTB, na sigla em inglês) IEEE 802.11az.
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 com o Android 10 (nível 29 da API) e versões mais recentes, os dados de local do AP podem ser
representados como objetos ResponderLocation, que incluem latitude, longitude
e altitude. Para APs de RTT do Wi-Fi que oferecem suporte a informações de configuração de local
ou relatório cívico de local (dados LCI ou LCR), o protocolo vai retornar um
objeto ResponderLocation durante o processo de medição.
Os apps podem consultar os APs diretamente para saber a posição deles, em vez de armazená-la com antecedência. Seu app pode encontrar APs e determinar as posições deles, mesmo que fossem desconhecidos antes, como quando um usuário entra em um novo prédio.
O suporte à medição de distância NTB IEEE 802.11az 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 iniciador NTB
do IEEE 802.11az (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 intervalo.
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 as medições
de alcance, deixando o intervalo exato sob o controle do seu app.
Requisitos
- O hardware do dispositivo que faz a solicitação de medição precisa implementar o padrão FTM 802.11-2016 ou 802.11az (medição não baseada em acionador).
- O dispositivo que faz a solicitação de alcance precisa executar o Android 9 (API de nível 28) ou versão mais recente. A medição de distância não baseada em acionador IEEE 802.11az está ativada 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 medição de distância for destinado ao
Android 13 (nível 33 da API) ou versões mais recentes, ele precisará ter a permissão
NEARBY_WIFI_DEVICES. Se esse app for destinado a uma versão anterior do Android, ele precisará ter a permissãoACCESS_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 app não pode acessar informações de localização em segundo plano.
- O ponto de acesso precisa implementar o padrão IEEE 802.11-2016 FTM ou o padrão IEEE 802.11az (intervalo não baseado em acionador).
Configuração
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, então você precisa solicitá-las no momento da execução sempre 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 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 o 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 RTT de Wi-Fi pode existir no dispositivo, mas pode 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 oferecer suporte ao Wi-Fi RTT se o SoftAP ou o tethering estiverem em uso. Para verificar
se o RTT do Wi-Fi 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. Quando o app receber a intent de transmissão, ele
precisará verificar o estado atual de disponibilidade e ajustar o comportamento
de acordo.
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 medição (RangingRequest) é criada especificando uma lista de APs ou
pares do Wi-Fi Aware para os quais uma medição é solicitada. Vários pontos de acesso ou dispositivos
com Wi-Fi Aware podem ser especificados em uma única solicitação de medição. As distâncias de 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 para 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
obtido chamando WifiManager.getScanResults(). Use
addAccessPoints(List<ScanResult>) para adicionar vários pontos de acesso em um lote.
Os objetos ScanResult podem conter APs compatíveis com IEEE 802.11mc (is80211mcResponder()) e
IEEE 802.11az com base em medição sem acionador (is80211azNtbResponder()). Os dispositivos que oferecem suporte à medição de distância NTB IEEE 802.11az realizam a medição de distância 802.11mc ou
802.11az, dependendo da capacidade do AP, usando 802.11az como padrão quando
o AP oferece suporte a ambos. Os dispositivos que não são compatíveis com o IEEE 802.11az realizam todas as
medições usando o protocolo IEEE 802.11mc.
Da mesma forma, uma solicitação de medição pode adicionar um par 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 dispositivos semelhantes com Wi-Fi Aware, consulte a
documentação do Wi-Fi Aware.
Solicitar o alcance
Um app emite uma solicitação de medição usando o método WifiRttManager.startRanging()
e fornecendo o seguinte: um RangingRequest para especificar a
operação, um Executor para especificar o contexto de 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 medição é realizada de forma assíncrona, e os resultados são
retornados em um dos callbacks RangingResultCallback:
- Se toda a operação de medição falhar, o callback
onRangingFailureserá acionado com um código de status descrito emRangingResultCallback. Essa falha pode acontecer se o serviço não puder executar uma operação de medição de distância no momento, por exemplo, porque o Wi-Fi está desativado, porque o aplicativo solicitou muitas operações de medição de distância e está limitado ou devido a um problema de permissão. - Quando a operação de medição de distância é concluída, o callback
onRangingResultsé acionado com uma lista de resultados que corresponde à lista de solicitações, um resultado para cada solicitação. A ordem dos resultados não corresponde necessariamente à ordem das solicitações. Uma operação de medição pode ser concluída, mas cada resultado ainda pode indicar uma falha dessa 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, geralmente um endereço MAC fornecido no ScanResult
que identifica um ponto de acesso. O endereço MAC pode ser recebido do resultado de medição de distância usando o método getMacAddress().
A lista de resultados de medição pode estar em uma ordem diferente dos pares (pontos de acesso) especificados na solicitação de medição. Portanto, use o endereço MAC para identificar o par, 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 método getStatus(). Qualquer outro 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
na etapa anterior) são inválidos, e o método get* correspondente falha
com uma exceção IllegalStateException.
3. Veja os resultados para cada medição concluída
Para cada medição bem-sucedida (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:
Veja o RSSI dos pacotes utilizados para as medições:
Confira o tempo em milissegundos da mediação (indicando o tempo desde a inicialização):
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):
Tempo mínimo e máximo que um dispositivo cliente precisa esperar entre as medições de NTB do 11az:
getMinTimeBetweenNtbMeasurementsMicros()egetMaxTimeBetweenNtbMeasurementsMicros()retornam o horário 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, a API vai encerrar a sessão de alcance sem acionamento e negociar uma nova sessão com a estação de resposta. Evite solicitar uma nova sessão de medição, porque isso adiciona sobrecarga ao tempo de medição. Para aproveitar ao máximo a eficiência de medição sem acionamento do 802.11az, acione a próxima solicitação de medição entre o tempo mínimo e máximo especificado na mediçãoRangingResultanterior.Repetições de campo de treinamento longo (LTF, na sigla em inglês) que as estações de resposta e de inicialização usaram no preâmbulo para o resultado do NTB IEEE 802.11az:
Número de fluxos de tempo espacial (STS, na sigla em inglês) de transmissão e recepção que a estação iniciadora usou para o resultado do NTB do IEEE 802.11az:
Dispositivos Android compatíveis com Wi-Fi RTT
As tabelas a seguir listam alguns smartphones, pontos de acesso e dispositivos de varejo, armazenamento e centro de distribuição compatíveis com o Wi-Fi 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 | Protocolo |
|---|---|---|
| Nest Wifi Pro (Wi-Fi 6E) | Compatível | mc |
| Compulab WILD AP | Compatível | mc |
| Google Wi-Fi | Compatível | mc |
| Roteador Wi-Fi Google Nest | Compatível | mc |
| Ponto Google Nest Wifi | Compatível | mc |
| Aruba AP-635 | Compatível | mc |
| Cisco 9130 | Compatível | mc |
| Cisco 9136 | Compatível | mc |
| Cisco 9166 | Compatível | mc |
| Cisco 9164 | Compatível | mc |
| Cisco CW9172I | Compatível | mc/az |
| Cisco CW9172H | Compatível | mc/az |
| Cisco CW9176I | Compatível | mc/az |
| Cisco CW9178I | Compatível | mc/az |
| Aruba AP-505 | Compatível | mc |
| Aruba AP-515 | Compatível | mc |
| Aruba AP-575 | Compatível | mc |
| Aruba AP-518 | Compatível | mc |
| Aruba AP-505H | Compatível | mc |
| Aruba AP-565 | Compatível | mc |
| Aruba AP-535 | Compatível | mc |
| Aruba AP567 | Compatível | mc |
| Aruba AP577 | Compatível | mc |
| Aruba AP555 | Compatível | mc |
| Aruba AP635 | Compatível | mc |
| Aruba AP655 | Compatível | mc |
| Aruba AP615 | Compatível | mc |
| Aruba AP734 | Compatível | mc/az |
| Aruba AP735 | Compatível | mc/az |
| Aruba AP754 | Compatível | mc/az |
| Aruba AP755 | Compatível | mc/az |
Smartphones
| Fabricante e modelo | Versão do Android |
|---|---|
| Google Pixel 9 Pro XL | 14+ |
| Google Pixel 9 | 14+ |
| Google Pixel 9 Pro | 14+ |
| Google Pixel 9 Pro XL | 14+ |
| Google Pixel 7a | 14+ |
| Google Pixel 7 | 14+ |
| Google Pixel 8 | 14+ |
| Google Pixel 8 Pro | 14+ |
| Google Pixel 8a | 14+ |
| Samsung SM-S918B | 14+ |
| Samsung SM-A515F | 14+ |
| Google Pixel 9 Pro | 14+ |
| Samsung SM-A546E | 14+ |
| Samsung SM-S928B | 14+ |
| Samsung SM-A217F | 14+ |
| Samsung SM-A715F | 14+ |
| Samsung SM-A528B | 14+ |
| Samsung SM-A135F | 14+ |
| Samsung SM-S911B | 14+ |
| Xiaomi 21091116AI | 14+ |
| Google Pixel 9 | 14+ |
| Samsung SM-A127F | 14+ |
| Google Pixel 7 Pro | 14+ |
| Samsung SM-A556E | 14+ |
| 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, armazenamento e centro de distribuição
| 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+ |