[Android] WiFiのアクセスポイントまでの距離を計測する

スポンサーリンク

はじめに

検証用に社長に作ってって言われたから、雑に作った。本当にいろいろ雑だからいろいろと気にしちゃいけない。あと、見せちゃいけなさそうな部分は意図的にコード消してる。

流れ的にはWiFi情報を取得してWiFI情報の電波強度?をモニョモニョ計算するって感じ。流れというかそのままだけどw

WiFi情報を取得するサービスを作成

WifiScanService.kt

//
const val ACTION_WIFI_SCAN_ACTION= "WIFI.SCAN.ACTION"
const val EXTRA_WIFI_SCAN= "extra_wifi_scan"

class WifiScanService : Service() {


private val handler: Handler = Handler()
private lateinit var runnable: Runnable

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

runnable = Runnable{

val wm = applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager
wm?.startScan()

val scanResults = wm?.scanResults?.filter{
true
}
val broadcastIntent = Intent(ACTION_WIFI_SCAN_ACTION)
broadcastIntent.putParcelableArrayListExtra(EXTRA_WIFI_SCAN, ArrayList(scanResults))

LocalBroadcastManager.getInstance(this).sendBroadcast(broadcastIntent)

handler.postDelayed(runnable, 5000)
}
handler.post(runnable)
return Service.START_NOT_STICKY
}

override fun onBind(intent: Intent?): IBinder? {
// バインドさせない
return null
}

override fun onDestroy() {
super.onDestroy()
handler.removeCallbacks(runnable)
}

}

サービスから情報を受け取るレシーバーを作成

WifiScanReceiver.kt

//
class WifiScanReceiver : BroadcastReceiver() {

var listener: OnWifiScanListener? = null

interface OnWifiScanListener {
fun onWifiScan(scanResults: List<ScanResult>?)
}

override fun onReceive(context: Context, intent: Intent) {
val scanResults = intent.getParcelableArrayListExtra<ScanResult>(EXTRA_WIFI_SCAN)
listener?.onWifiScan(scanResults)

}
}

WiFi情報とアクセスポイントまでの距離を持ってるクラス作成

WiFiApData.kt

//
class WifiApData(val scanResult: ScanResult) {
var distance: Double = 0.0
}

距離を計算するクラス作成

//
class WifiApDistanceCalculatorModel {

fun getWifiApDates(scanResults: List<ScanResult>?): List<WifiApData> {

val wifiApDates: MutableList<WifiApData> = mutableListOf()
scanResults?.forEach{
val wifiApData = WifiApData(it)
wifiApData.distance = calculateDistance(it.level.toDouble(), it.frequency.toDouble())
wifiApDates.add(wifiApData)
}

return wifiApDates.sortedBy{ it.distance }
}

private fun calculateDistance(levelInDb: Double, freqInMHz: Double): Double {
val exp = (27.55 - 20 * Math.log10(freqInMHz) + Math.abs(levelInDb)) / 20.0
return Math.pow(10.0, exp)
}
}

Activity

//
@RuntimePermissions
class MainActivity : AppCompatActivity(), WifiScanReceiver.OnWifiScanListener {

protected val wifiApDistanceCalculatorModel: WifiApDistanceCalculatorModel = WifiApDistanceCalculatorModel()
private lateinit var wifiScanReceiver: WifiScanReceiver

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

wifiScanReceiver = WifiScanReceiver()
wifiScanReceiver.listener = this

startWiFiScanServiceWithPermissionCheck()
}

@NeedsPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
fun startWiFiScanService() {
startService(Intent(this, WifiScanService::class.java))
}

@OnPermissionDenied(android.Manifest.permission.ACCESS_COARSE_LOCATION)
fun showDeniedForWiFiScanService() {
Toast.makeText(this, "非許可", Toast.LENGTH_SHORT).show()
}

@OnNeverAskAgain(android.Manifest.permission.ACCESS_COARSE_LOCATION)
fun showNeverAskWiFiScanService() {
Toast.makeText(this, "今後表示しない", Toast.LENGTH_SHORT).show()
}

override fun onResume() {
super.onResume()
LocalBroadcastManager.getInstance(this)
.registerReceiver(wifiScanReceiver, IntentFilter(ACTION_WIFI_SCAN_ACTION))

}

override fun onPause() {
super.onPause()
LocalBroadcastManager.getInstance(this).unregisterReceiver(wifiScanReceiver)

}

override fun onDestroy() {
super.onDestroy()
stopService(Intent(this, WifiScanService::class.java))
}

override fun onWifiScan(scanResults: List<ScanResult>?) {
val list = wifiApDistanceCalculatorModel.getWifiApDates(scanResults)
    // いろいろモニョモニョする。

}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
onRequestPermissionsResult(requestCode, grantResults)

}
}

結果

精度はそこそこなような気がする。APに近づくとちゃんと距離は短くなるし。この動画は端末動かしてないけどw

おわりに

5系だとWiFi情報取得するたびに情報が書き換わってるんだけど、6系以上だとOSがキャッシュしているのか5~10秒ほど同じ値をOSが返してくる。これの対処方法が全くわかってない。情報あったら誰か教えてほしい(´・ω・`)

そもそも9系以上だとWiFiの取得制限がものすごく厳しくなるから、このアプリは使い物にならなくなるけど、、、。

https://amzn.to/2LIG1XC
タイトルとURLをコピーしました