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 Fine-Time-Measurement (FTM) são especificados pelo padrão IEEE 802.11mc. 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.
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.
Requisitos
- O hardware do dispositivo que faz a solicitação de alcance precisa implementar o padrão de FTM 802.11mc.
- 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 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).
- O aplicativo que faz a solicitação de alcance precisa 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.11mc.
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" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
A permissão ACCESS_FINE_LOCATION
é perigosa. Por isso, você precisa solicitá-la no tempo de execução toda vez que o usuário quiser realizar uma operação de verificação de RTT. Seu aplicativo precisará solicitar a permissão do usuário caso ela ainda não tenha sido concedida. Para saber mais 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 no momento, caso o Wi-Fi seja desativado pelo usuário. Dependendo dos recursos de hardware e firmware alguns dispositivos podem não ser compatíveis com Wi-Fi RTT se o SoftAP ou o tethering estiverem em uso. Para verificar se o Wi-Fi RTT está disponível no momento, chame isAvailable().
A disponibilidade do Wi-Fi RTT pode mudar a qualquer momento. Seu aplicativo deve fazer registro de um BroadcastReceiver para receber ACTION_WIFI_RTT_STATE_CHANGED, que é enviado quando há mudanças na disponibilidade. 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 com a especificação de uma lista de pontos de acesso ou pontos do Wi-Fi Aware. É 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();
É possível identificar um ponto de acesso pelo objeto ScanResult, que pode ser obtido com a chamada de WifiManager.getScanResults(). Você pode usar addAccessPoints(List
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 relacionada.
Solicitar o alcance
Um aplicativo 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.
Por 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 falhar, o callback onRangingFailure será acionado com o 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 por 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 pelo 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 indicará que houve 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*
gerará um erro com uma exceção IllegalStateException.
3. Veja os resultados para cada medição concluída
Para cada medição concluída, você poderá 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):
Dispositivos Android compatíveis com Wi-Fi RTT
As tabelas abaixo listam alguns smartphones e pontos de acesso compatíveis com WiFi-RTT. Elas não abrangem todos os dispositivos compatíveis. Entre em contato conosco para listar seus produtos compatíveis com RTT aqui.
Smartphones
Fabricante e Modelo | Versão do Android |
---|---|
Xiaomi Redmi Note 5 Pro | 9.0+ |
LG V30 | 9.0+ |
Samsung Note 10+ | 9.0+ |
Samsung A9 Pro | 9.0+ |
Google Pixel 4 | 9.0+ |
Google Pixel 3 | 9.0+ |
Google Pixel 2 | 9.0+ |
Google Pixel 1 | 9.0+ |
Pontos de acesso
Fabricante e Modelo | Data de suporte |
---|---|
Compulab WILD AP | Compatível |
Google Wi-Fi | Compatível |
Roteador Google Nest Wifi | Maio de 2020 |
Ponto Google Nest Wifi | Maio de 2020 |