Wi-Fi 위치: RTT를 사용한 범위 설정

Wi-Fi RTT(Round-Trip-Time) API가 제공하는 Wi-Fi 위치 기능을 사용하여 주변의 RTT 지원 Wi-Fi 액세스 포인트 및 동종 앱 Wi-Fi Aware 기기와의 거리를 측정할 수 있습니다.

기기에서 3개 이상의 액세스 지점에 대한 거리를 측정하는 경우, 다변측정(MLAT) 알고리즘을 사용하여 해당 측정에 가장 적합한 기기 위치를 측정할 수 있습니다. 일반적으로 결과의 정확도는 1~2m 이내입니다.

이 정도의 정확도에서는 세밀한 위치 기반 서비스를 개발할 수 있습니다. 예를 들어 실내 탐색, 명확한 음성 제어(예: '조명 켜기'), 위치 기반 정보(예: '이 제품 관한 특별 이벤트가 있는지 여부')가 있습니다.

요청하는 기기는 Wi-Fi RTT와의 거리를 측정하기 위해 액세스 포인트에 연결하지 않아도 됩니다. 개인정보 보호를 위해 요청하는 기기에서만 액세스 포인트에 대한 거리를 측정할 수 있으며, 액세스 포인트에는 이 정보가 없습니다. Wi-Fi RTT 작업은 포그라운드 앱에 관한 제한이 없지만 백그라운드 앱 사용이 제한됩니다.

Wi-Fi RTT 및 관련 FTM(Fine-Time-Measurement) 기능은 IEEE 802.11mc 표준에서 지정합니다. Wi-Fi RTT는 FTM에서 제공하는 정확한 시간 측정이 필요합니다. 패킷이 두 기기를 왕복하는 시간을 측정하고 그 시간에 광속을 곱하여 두 기기 간의 거리를 계산하기 때문입니다.

Android 버전에 따른 구현의 차이

Wi-Fi RTT는 Android 9(API 수준 28)에 도입되었습니다. 이 프로토콜을 사용하여 Android 9를 실행하는 기기로 다변 측정하고 기기의 위치를 알아낼 경우, 앱에서 사전에 결정된 액세스 포인트(AP) 데이터에 액세스해야 합니다. 개발자는 이 데이터를 저장하고 검색하는 방법을 결정합니다.

Android 10(API 수준 29) 이상을 실행하는 기기에서 AP 위치 데이터는 ResponderLocation 객체로 표시될 수 있으며 여기에는 위도, 경도, 고도가 포함됩니다. 위치 구성 정보/위치 시민 보고(LCI/LCR 데이터)를 지원하는 Wi-Fi RTT AP의 경우, 범위 설정 프로세스에서 프로토콜이 ResponderLocation 객체를 반환합니다.

이 기능을 사용하면 앱이 미리 정보를 저장할 필요 없이 AP를 쿼리하여 위치 정보를 직접 요청할 수 있습니다. 그러므로 사용자가 새로운 건물에 들어갔을 때처럼 AP의 위치에 관해 몰랐더라도 앱이 AP를 찾고 그 위치를 알아낼 수 있습니다.

요구사항

  • 범위 설정 요청을 하는 기기의 하드웨어는 802.11mc FTM 표준을 구현해야 합니다.
  • 범위 설정 요청을 하는 기기는 Android 9(API 수준 28) 이상을 실행해야 합니다.
  • 범위 설정 요청을 하는 기기는 위치 서비스가 활성화되어 있고 Wi-Fi 검색을 켜야 합니다.(Settings > Location)
  • 범위 설정을 요청하는 앱은 ACCESS_FINE_LOCATION 권한이 있어야 합니다.
  • 앱은 표시되는 동안 또는 포그라운드 서비스 상태에서 액세스 포인트 범위를 쿼리해야 합니다. 앱은 백그라운드에서 위치 정보에 액세스할 수 없습니다.
  • 액세스 포인트는 IEEE 802.11mc FTM 표준을 구현해야 합니다.

설정

앱이 Wi-Fi RTT를 사용하도록 설정하려면 다음 단계를 따라 하세요.

1. 권한 요청

앱 매니페스트에서 다음 권한을 요청합니다.

<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" />

ACCESS_FINE_LOCATION 권한은 위험한 권한이므로 사용자가 RTT 스캔 작업을 하기 원할 때마다 런타임에서 요청해야 합니다. 앱이 아직 사용자의 권한을 받지 않았다면 이를 요청해야 합니다. 런타임 권한에 관한 자세한 내용은 앱 권한 요청을 참조하세요.

2. 기기가 Wi-Fi RTT를 지원하는지 확인

기기가 Wi-Fi RTT를 지원하는지 확인하려면 다음과 같은 PackageManager API를 사용하세요.

Kotlin

context.packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)

자바

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

3. Wi-Fi RTT를 사용할 수 있는지 확인

Wi-Fi RTT가 기기에 있을 수는 있으나 사용자가 Wi-Fi를 비활성화했기 때문에 사용하지 못하는 상태일 수 있습니다. 하드웨어와 펌웨어 기능에 따라 SoftAP 또는 테더링을 사용하고 있을 경우 일부 기기는 Wi-Fi RTT를 지원하지 않을 수 있습니다. Wi-Fi RTT를 현재 사용할 수 있는지 확인하려면 isAvailable()을 호출하세요.

Wi-Fi RTT의 사용 가능 여부는 언제든지 변경될 수 있습니다. 앱은 BroadcastReceiver를 등록하여 사용 가능 여부가 변경될 때 전송되는 ACTION_WIFI_RTT_STATE_CHANGED를 수신할 수 있습니다. 앱이 이 브로드캐스트 인텐트를 수신하면 사용 가능 여부의 현재 상태를 확인하고 그에 맞게 동작을 수정해야 합니다.

예:

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)

자바

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

자세한 내용은 브로드캐스트를 참조하세요.

범위 설정 요청 만들기

범위를 요청하는 AP 또는 Wi-Fi Aware 동종 앱의 목록을 지정하여 범위 설정 요청(RangingRequest)을 생성합니다. 한 번의 범위 설정 요청에서 여러 개의 액세스 포인트 또는 Wi-Fi Aware 동종 앱을 지정할 수 있습니다. 이 경우, 모든 기기와의 거리를 측정해서 반환합니다.

예를 들어 요청에서 addAccessPoint() 메서드를 사용하여 거리를 측정할 액세스 포인트를 지정할 수 있습니다.

Kotlin

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

자바

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

RangingRequest req = builder.build();

액세스 포인트는 ScanResult 객체로 식별되고, 이는 WifiManager.getScanResults()를 호출하면 얻을 수 있습니다. addAccessPoints(List)를 사용하여 여러 액세스 포인트를 일괄 추가할 수 있습니다.

마찬가지로 범위 설정 요청은 MAC 주소나 PeerHandle, addWifiAwarePeer(MacAddress peer)addWifiAwarePeer(PeerHandle peer) 메서드를 각각 사용하여 Wi-Fi Aware 동종 앱을 추가할 수 있습니다. Wi-Fi Aware 동종 앱 검색에 관한 자세한 내용은 Wi-Fi Aware 도움말을 참조하세요.

범위 설정 요청

앱은 WifiRttManager.startRanging() 메서드를 사용하고 다음을 사용하여 범위 설정 요청을 보냅니다. RangingRequest 로는 작업을 지정하고, Executor로는 콜백 내용을 지정하며, RangingResultCallback으로는 결과를 수신합니다.

예:

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

자바

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

범위 설정 작업은 비동기식으로 실행되며 범위 설정 결과는 RangingResultCallback의 콜백 중 하나로 반환됩니다.

  • 전체 범위 설정 작업이 실패하면 RangingResultCallback에서 설명한 상태 코드와 함께 onRangingFailure 콜백이 트리거됩니다. 서비스가 그 시점에 범위 설정 작업을 실행할 수 없을 경우 이런 실패가 발생할 수 있습니다. 예를 들어 Wi-Fi가 비활성화되었거나, 애플리케이션이 너무 많은 범위 설정 작업을 요청해서 사용이 제한되었거나, 권한에 문제가 있는 것이 원인일 수 있습니다.
  • 범위 설정 작업이 완료되면 요청의 목록과 일치하는 결과 목록(요청당 1개)과 함께 onRangingResults 콜백이 트리거됩니다. 결과의 순서는 요청의 순서와 반드시 일치하지는 않습니다. 범위 설정 작업이 완료되더라도 각 결과에서 특정 측정이 실패한 것으로 나타날 수 있습니다.

범위 설정 결과 해석

onRangingResults 콜백이 반환하는 각각의 결과는 RangingResult 객체로 지정됩니다. 각 요청에 관해 다음을 실행합니다.

1. 요청 식별

RangingRequest를 생성할 때 제공된 정보에 기초하여 요청을 식별합니다. 일반적으로 액세스 포인트를 식별하는 ScanResult에 제공된 MAC 주소입니다. MAC 주소는 getMacAddress() 메서드를 사용하여 범위 설정 결과에서 얻을 수 있습니다.

범위 설정 결과의 목록은 범위 설정 요청에서 지정한 동종 앱(액세스 포인트)의 순서와 다를 수 있으므로 MAC 주소를 사용하여 결과의 순서가 아니라 동종 앱을 식별해야 합니다.

2. 각 측정이 성공했는지 확인

측정이 성공했는지 확인하려면 getStatus() 메서드를 사용합니다. STATUS_SUCCESS를 제외한 모든 값은 실패를 나타냅니다. 실패는 이 결과를 제외한 다른 모든 필드(위의 요청 식별 제외)가 무효이고 이 get* 메서드가 IllegalStateException 예외와 함께 실패한다는 것을 의미합니다.

3. 각 성공적인 측정에 관한 결과 가져오기

각 성공적인 측정에 관해 각 get 메서드로 결과 값을 검색할 수 있습니다.

Wi-Fi RTT를 지원하는 Android 기기

아래 표에서 WiFi-RTT를 지원하는 몇 가지 전화번호액세스 포인트를 참조하세요. 많은 정보가 포함되어 있지 않습니다. Google에 문의하여 RTT 사용이 가능한 제품의 목록을 알아보세요.

전화

제조업체 및 모델 Android 버전
Xiaomi Redmi Note 5 Pro 9.0+
LG V30 9.0+
삼성 노트 10+ 9.0+
삼성 A9 프로 9.0+
Google Pixel 4 9.0+
Google Pixel 3 9.0+
Google Pixel 2 9.0+
Google Pixel 1 9.0+

액세스 포인트

제조업체 및 모델 지원 날짜
Compulab WILD AP 지원됨
Google Wi-Fi 지원됨
Google Nest Wi-Fi 라우터 2020년 5월
Google Nest Wi-Fi 포인트 2020년 5월