#はじめに
GPSで緯度と経度をGNSSで受信した衛星の情報を取得します。
API Level 24 (Android 7.0)以降が対象です。
#準備
build.gradle(app)に下記の1行を追加します。
implementation 'com.google.android.gms:play-services-location:15.0.1'
マニフェストファイルには以下のパーミッションを追加します。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
#ユーザーに許可をもらう
GPSやGNSSの情報を取得するにはユーザーに取得する旨を通知して許可をもらう必要があります。
ユーザーへの許可は
val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
ActivityCompat.requestPermissions(this,permissions,1000)
という処理を行うと許可をもらう画面になります。
ただしこのとき、処理が止まっているわけではありません。
許可された場合(されない場合も)はMainActivityのoverride fun onRequestPermissionsResultリスナーに処理が渡されるので、これを元に適切に処理します。
なお1000という数値はonRequestPermissionsResult内で他の処理と区別するために使います。
override fun onRequestPermissionsResult(requestCode : Int,permissions : Array<String>,grantResults: IntArray){
if (requestCode == 1000 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
}
}
さっきの1000がここで出てきます。
PERMISSION_GRANTEDは許可が取れたことを示しています。
#ソースの説明
MainActivityのソースは極力減らしています。
LocationManagerが相当古いSDKなのかLocationManager::class.kotlinJvmJavaという見たことも無い変換で渡すことになりました。
位置情報が得られた場合はonLocationリスナーが、衛星情報が得られた場合はonSatellitリスナーが処理されます。
onLocationはlocationResult.lastLocation.latitudeに経度、locationResult.lastLocation.longitudeに緯度が入っています。
onSatellitはstatus.satelliteCountに得られた衛星の数が入ります。
status,get_xxxのメソッドの引数は衛星のインデックス 0..status.satelliteCount-1 までの数値を渡して情報を取得します。
メソッド名 | 意味 |
---|---|
getSvid(idx) | 衛星の識別番号を取得します。ただしこちらは使われていない様子です。 |
getConstellationType(idx) | こちらが使われている方の識別番号 GPSの場合は1..32の値になります |
getAzimuthDegrees(idx) | 衛星の方位(角度)が0.0..359.9の値で取得出来ます |
getElevationDegrees(idx) | 衛星の高さを取得出来ます。単位は・・・何でしょ? |
getCn0DbHz(idx) | 衛星からの電波の強さを取得します。強さはC/N0比で単位はdBHz です |
usedInFix | 位置情報の取得に使われている衛星の場合trueが返されます |
getCarrierFrequencyHz(idx) | おそらく使われていません |
#ソース
class MainActivity : AppCompatActivity() {
private val gpsService = GpsService(this,this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
gpsService.setListener(gpsListener)
gpsService.permissioRequestCode = 1000
gpsService.start()
}
private val gpsListener = object : GpsServiceInterface{
override fun onLocation(locationResult: LocationResult) {
Toast.makeText(this@MainActivity,
"緯度:${locationResult.lastLocation.latitude}, 経度:${locationResult.lastLocation.longitude}", Toast.LENGTH_LONG).show()
}
override fun onSatellit(status: GnssStatus) {
for (i in 0..status.satelliteCount-1){
Log.d("Sample", status.getSvid(i).toString())
}
}
}
override fun onRequestPermissionsResult(requestCode : Int,permissions : Array<String>,grantResults: IntArray){
if (requestCode == gpsService.permissioRequestCode && grantResults[0] == PackageManager.PERMISSION_GRANTED){
if (gpsService.isGPSPermission()){
gpsService.start()
}
}
}
}
interface GpsServiceInterface : GpsService.Listener {
fun onLocation(locationResult: LocationResult) // 受信イベント
fun onSatellit(status: GnssStatus)
}
class GpsService(private var context: Context,private var activity: MainActivity) {
private var _latitude = 0.0
private var _longitude = 0.0
private lateinit var fusedLocation : FusedLocationProviderClient
private lateinit var locationManager: LocationManager
var permissioRequestCode : Int = 1000
private lateinit var locationCallback: LocationCallback
private lateinit var gnssCallback : GnssStatus.Callback
private var listener: GpsServiceInterface? = null
interface Listener {}
private var enable : Boolean = false
fun setListener(listener: GpsService.Listener?) {
if (listener is GpsServiceInterface) {
this.listener = listener as GpsServiceInterface
}
}
fun start(){
if (enable) return
if (isGPSPermission() == false){
val permissions = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
ActivityCompat.requestPermissions(activity,permissions,permissioRequestCode)
return
}
locationManager = getSystemService<LocationManager>(context, LocationManager::class.kotlinJvmJava) as LocationManager
fusedLocation = FusedLocationProviderClient(context)
val locationRequest = LocationRequest().apply {
interval = 10000
fastestInterval = 5000
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
locationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult?) {
if (locationResult == null) return
listener?.onLocation(locationResult)
}
}
gnssCallback = object: GnssStatus.Callback() {
override fun onSatelliteStatusChanged(status: GnssStatus?) {
super.onSatelliteStatusChanged(status)
if (status == null) return
listener?.onSatellit(status)
}
}
if (ActivityCompat.checkSelfPermission(context,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocation.requestLocationUpdates(locationRequest,locationCallback,Looper.myLooper())
locationManager.registerGnssStatusCallback(gnssCallback)
}
enable = true
}
fun stop(){
if (!enable) return
fusedLocation.removeLocationUpdates(locationCallback)
locationManager.unregisterGnssStatusCallback(gnssCallback)
enable = false
}
fun isGps() : Boolean{
return isGPSPermission() and isGPSEnabled()
}
fun isGPSPermission() : Boolean{
return ActivityCompat.checkSelfPermission(context,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
fun isGPSEnabled(): Boolean {
val locationManager =
context.getSystemService(LOCATION_SERVICE) as LocationManager
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
}
}