설정 > 개발자 옵션 > 가상 위치 앱 선택 > 가상 위치 앱으로 SynRTK 선택


| 필드 | 타입 | 값 | 설명 |
|---|---|---|---|
| latitude | double | 위도 | |
| longitude | double | 경도 | |
| altitude | double | 고도 (m) | 해수면 고도 (MSL) |
| accuracy | float | 수평 정확도 (m) | HRMS |
| (Horizontal Root Mean Square): | |||
| 수신기에서 측정한 위치가 수평 방향(위도 및 경도, 즉 2D 평면)으로 실제 위치(True Position)에서 평균적으로 얼마나 벗어나 있는지를 나타내는 통계적 오차 지표 | |||
| speed | float | Gnss Status (Fix 상태) | |
| 0.0f → No Fix | |||
| 1.0f → 3DFix | |||
| 2.0f → DGNSS | |||
| 3.0f → Unknown | |||
| 4.0f → RTK Fixed | |||
| 5.0f → RTK Float | 4.0f 즉 RTK Fixed 상태이면, | ||
| 위/경도가 2 ~ 3 cm 오차의 | |||
| RTK 정확도 위치임 | |||
| bearing | float | 0.0 으로 고정 | |
| time | long | 밀리초 (시스템 시간) | |
| elapsedRealtimeNanos | long | 나노초 (시스템 시간) |
package com.synerex.samplebroadcastreceiver
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
// Mock Location 으로 데이터를 수신하는 액티비티.
// Mock Location 으로 수신되는 Location 의 extras 에는
// Broadcast(position) 로 수신하던 것과 동일한 key/value 가 들어 있어
// MainActivity 에서 보여주던 Position 정보를 그대로 표시한다.
class MockLocationActivity : AppCompatActivity() {
private var text_data: TextView? = null
private var locationManager: LocationManager? = null
private val locationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
text_data?.text =
"time: ${location.time}\n" +
"latitude: ${location.latitude}\n" +
"longitude: ${location.longitude}\n" +
"altitude: ${location.altitude}\n" +
"accuracy: ${location.accuracy}\n" +
"gnss_status: ${location.speed} (${fixTypeText(location.speed)})\n" +
"bearing: ${location.bearing}\n" +
"elapsedRealtimeNanos: ${location.elapsedRealtimeNanos}\n"
}
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}
// location.speed 값에 대응하는 Fix 상태 텍스트
private fun fixTypeText(speed: Float): String {
return when (speed) {
0.0f -> "No Fix"
1.0f -> "3DFix"
2.0f -> "DGNSS"
3.0f -> "Unknown"
4.0f -> "RTK Fixed"
5.0f -> "RTK Float"
else -> "Unknown" // -1.0f 포함, 정의되지 않은 값
}
}
private val locationPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { granted ->
if (granted) {
startMockLocationUpdates()
} else {
Toast.makeText(this, "위치 권한이 필요합니다.", Toast.LENGTH_SHORT).show()
finish()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mock_location)
text_data = findViewById(R.id.text_data)
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
// 뒤로 가기(닫기) 버튼 → 액티비티 종료 후 MainActivity 로 복귀 (좌/우 상단)
val closeClickListener = android.view.View.OnClickListener { finish() }
findViewById<Button>(R.id.button_close).setOnClickListener(closeClickListener)
findViewById<Button>(R.id.button_close_left).setOnClickListener(closeClickListener)
}
override fun onResume() {
super.onResume()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
startMockLocationUpdates()
} else {
locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
}
}
override fun onPause() {
super.onPause()
stopMockLocationUpdates()
}
private fun startMockLocationUpdates() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return
}
try {
locationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0L, 0f, locationListener
)
} catch (e: SecurityException) {
e.printStackTrace()
} catch (e: IllegalArgumentException) {
Toast.makeText(this, "GPS provider 를 사용할 수 없습니다.", Toast.LENGTH_SHORT).show()
}
}
private fun stopMockLocationUpdates() {
locationManager?.removeUpdates(locationListener)
}
}