Wi-Fi 位置情報: RTT を使用したレンジング(距離測定)

Wi-Fi RTT(ラウンドトリップ時間)API が提供する Wi-Fi 位置情報機能を使用して、付近にある RTT 対応の Wi-Fi アクセス ポイントや Wi-Fi Aware ピア デバイスとの距離を測定できます。

3 つ以上のアクセス ポイントまでの距離を測定する場合は、マルチラテレーション アルゴリズムを使用して、測定に最適なデバイスの位置を推定できます。結果の精度は通常 1~2 メートルの誤差の範囲内です。

この精度を確保できることによって、屋内ナビゲーション、明確な音声操作(例: 「このライトをつけて」)、位置情報をベースとする情報(例: 「このサービスに関してスペシャル オファーはありますか?」)などの精度の高い、位置情報を利用したサービスを開発できます。

リクエスト元のデバイスは、Wi-Fi RTT で距離を測定するためにアクセス ポイントに接続する必要はありません。プライバシーを保護するために、アクセス ポイントまでの距離を判断できるのはリクエスト元のデバイスのみです。アクセス ポイントにはこの情報がありません。Wi-Fi RTT オペレーションでは、フォアグラウンド アプリに対する制限はありませんが、バックグラウンド アプリに対しては制限が課されます。

Wi-Fi RTT と関連する Fine-Time-Measurement(FTM)機能は、IEEE 802.11mc 規格で規定されています。Wi-Fi RTT では、パケットがデバイス間を往復する時間を測定し、測定された時間に光速を乗じることによって 2 つのデバイス間の距離を計算するため、FTM による正確な時間測定が必要です。

Android のバージョンに基づく実装の違い

Wi-Fi RTT は Android 9(API レベル 28)で導入されました。Android 9 搭載デバイスの場合、このプロトコルを使用してマルチラテレーションでデバイスの位置を特定するには、アプリが事前定義されたアクセス ポイント(AP)の位置情報データにアクセスする必要があります。このデータの保存方法や取得方法は任意に決定できます。

Android 10(API レベル 29)以降を搭載するデバイスでは、AP の位置情報データは緯度、経度、高度を含む ResponderLocation オブジェクトとして表すことができます。Location Configuration Information / Location Civic Report(LCI / LCR データ)をサポートする Wi-Fi RTT AP の場合、プロトコルは距離測定プロセス中に ResponderLocation オブジェクトを返します。

この機能を使用すると、アプリは事前にこの情報を保存する代わりに、AP に直接クエリを実行して位置を問い合わせることができます。そのため、ユーザーがある建物に初めて入ったときなど、AP を事前に把握できていない場合でも、アプリは AP を見つけてその位置を特定できます。

要件

  • 距離測定のリクエストを行うデバイスのハードウェアは、802.11mc FTM 規格を実装する必要があります。
  • 距離測定のリクエストを行うデバイスは、Android 9(API レベル 28)以降を搭載している必要があります。
  • 距離測定のリクエストを行うデバイスでは、[設定] > [位置情報] で位置情報サービスを有効にして Wi-Fi スキャンをオンにする必要があります。
  • 距離測定のリクエストを行うアプリには、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)

Java

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

3. Wi-Fi RTT が利用可能かどうかを確認する

デバイスに Wi-Fi RTT があっても、ユーザーが無効にしているために Wi-Fi RTT が現在利用できない場合があります。ハードウェアとファームウェアの機能によっては、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)

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

詳細については、ブロードキャストをご覧ください。

距離測定のリクエストを作成する

距離測定のリクエスト(RangingRequest)は、距離をリクエストする対象の AP または Wi-Fi Aware ピアのリストを指定して作成します。1 つの距離測定リクエストで複数のアクセス ポイントまたは Wi-Fi Aware ピアを指定すると、すべてのデバイスまでの距離が測定され、返されます。

たとえば、次のように、リクエストで addAccessPoint() メソッドを使用して、距離を測定する対象のアクセス ポイントを指定できます。

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

アクセス ポイントは、ScanResult オブジェクトによって識別されます。このオブジェクトは、WifiManager.getScanResults() を呼び出すことで取得できます。addAccessPoints(List) を使用すると、複数のアクセス ポイントを一括で追加できます。

同様に、距離測定のリクエストで MAC アドレスまたは PeerHandle を使用して Wi-Fi Aware ピアを追加する場合は、addWifiAwarePeer(MacAddress peer) メソッドまたは addWifiAwarePeer(PeerHandle peer) メソッドをそれぞれ使用できます。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) { … }
})

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

距離測定オペレーションは非同期で実行され、距離測定の結果は RangingResultCallback のコールバックの 1 つで返されます。

  • 距離測定オペレーション全体が失敗した場合、RangingResultCallback で説明されているステータス コードで onRangingFailure コールバックがトリガーされます。 このような失敗は、Wi-Fi が無効になっている、アプリがリクエストした距離測定オペレーションが多すぎるため制限が課されている、または権限に問題があるなどの理由により、サービスで距離測定オペレーションが実行できない場合に発生します。
  • 距離測定オペレーションが完了すると、onRangingResults コールバックが、リクエストのリストに一致する結果(各リクエストに対して 1 つの結果)のリストでトリガーされます。結果の順序は、リクエストの順序と一致しない場合があります。距離測定オペレーションが完了した場合でも、各結果が依然として特定の測定の失敗を示している可能性がある点に留意してください。

距離測定の結果を解釈する

onRangingResults コールバックによって返される各結果は、RangingResult オブジェクトによって指定されます。各リクエストで、次の操作を行います。

1. リクエストを特定する

RangingRequest の作成時に提供された情報(ほとんどの場合は、ScanResult で提供され、アクセス ポイントを特定する MAC アドレス)に基づいてリクエストを特定します。MAC アドレスは、getMacAddress() メソッドを使用して距離測定の結果から取得できます。

距離測定の結果のリストにおける並び順は、距離測定リクエストで指定されたピア(アクセス ポイント)とは異なる場合があるため、結果の順序ではなく MAC アドレスを使用してピアを特定する必要があります。

2. 各測定が成功したかどうかを判断する

測定が成功したかどうかを判断するには、getStatus() メソッドを使用します。STATUS_SUCCESS 以外の値は失敗を示します。失敗した場合、この結果の他のすべてのフィールド(上記のリクエスト ID を除く)は無効になり、対応する get* メソッドは IllegalStateException 例外で失敗します。

3. 成功した各測定の結果を取得する

成功した測定ごとに、それぞれの get メソッドを使用して結果の値を取得できます。

Wi-Fi-RTT 対応の Android デバイス

以下の表は、Wi-Fi-RTT に対応する一部のスマートフォンアクセス ポイントの一覧です。これらはごく一部を示したものです。こちらに RTT 対応プロダクトを掲載される場合は、お問い合わせいただくことをおすすめします。

スマートフォン

メーカーとモデル 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+

アクセス ポイント

メーカーとモデル サポート日
Compulab WILD AP 対応
Google WiFi 対応
Google Nest Wifi ルーター 2020 年 5 月
Google Nest Wifi 拡張ポイント 2020 年 5 月