Realtime gps optimized for efficiency

This commit is contained in:
wengki81 2025-06-18 14:46:26 +08:00
parent 8bcd143854
commit 10c64ce5d1
2 changed files with 61 additions and 47 deletions

View File

@ -284,6 +284,7 @@ class DumonGeolocation : Plugin() {
if (emitIntervalMs != targetInterval) { if (emitIntervalMs != targetInterval) {
emitIntervalMs = targetInterval emitIntervalMs = targetInterval
gpsManager?.setPollingInterval(targetInterval)
Log.d("DUMON_GEOLOCATION", "Auto-set emitIntervalMs = $emitIntervalMs ms") Log.d("DUMON_GEOLOCATION", "Auto-set emitIntervalMs = $emitIntervalMs ms")
} }

View File

@ -9,6 +9,8 @@ import android.location.LocationListener
import android.location.LocationManager import android.location.LocationManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.format.DateFormat import android.text.format.DateFormat
import android.util.Log import android.util.Log
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
@ -20,6 +22,9 @@ class GpsStatusManager(
) { ) {
private val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager private val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
private val handler = Handler(Looper.getMainLooper())
private var pollingIntervalMs: Long = 1000L // default 1 second
private var isPolling = false
private val gnssStatusCallback = object : GnssStatus.Callback() { private val gnssStatusCallback = object : GnssStatus.Callback() {
override fun onSatelliteStatusChanged(status: GnssStatus) { override fun onSatelliteStatusChanged(status: GnssStatus) {
@ -43,7 +48,8 @@ class GpsStatusManager(
} }
} }
private val locationListener = object : LocationListener { private fun pollOnceAndEmit() {
val oneShotListener = object : LocationListener {
override fun onLocationChanged(location: Location) { override fun onLocationChanged(location: Location) {
val providerTag = when (location.provider) { val providerTag = when (location.provider) {
LocationManager.GPS_PROVIDER -> "[GPS]" LocationManager.GPS_PROVIDER -> "[GPS]"
@ -62,20 +68,43 @@ class GpsStatusManager(
Log.d("GPS_LOCATION", info) Log.d("GPS_LOCATION", info)
onLocationUpdate(location, isMocked) onLocationUpdate(location, isMocked)
locationManager.removeUpdates(this)
} }
@Deprecated("Deprecated in Java")
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {} override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
override fun onProviderEnabled(provider: String) {} override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {} override fun onProviderDisabled(provider: String) {}
} }
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
0L,
0f,
oneShotListener
)
} else {
Log.e("GPS_STATUS", "Missing location permission")
}
}
private val pollingRunnable = object : Runnable {
override fun run() {
if (!isPolling) return
pollOnceAndEmit()
handler.postDelayed(this, pollingIntervalMs)
}
}
fun setPollingInterval(intervalMs: Long) {
this.pollingIntervalMs = intervalMs
}
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun start() { fun start() {
try { try {
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.e("GPS_STATUS", "Missing location permissions") Log.e("GPS_STATUS", "Missing location permissions")
return return
} }
@ -88,48 +117,32 @@ class GpsStatusManager(
} }
locationManager.registerGnssStatusCallback(gnssStatusCallback, null) locationManager.registerGnssStatusCallback(gnssStatusCallback, null)
isPolling = true
handler.post(pollingRunnable)
locationManager.requestLocationUpdates( // Fallback lokasi terakhir
LocationManager.GPS_PROVIDER,
0L,
0f,
locationListener
)
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
3000L,
10f,
locationListener
)
Log.d("GPS_STATUS", "GPS + Network location tracking started")
// 🔥 Fallback: coba ambil lokasi terakhir
val lastKnown = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) val lastKnown = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
?: locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) ?: locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
lastKnown?.let { location -> lastKnown?.let { location ->
if (location.latitude != 0.0 && location.longitude != 0.0) { if (location.latitude != 0.0 && location.longitude != 0.0) {
val isMocked = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val isMocked = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) location.isMock else location.isFromMockProvider
location.isMock
} else {
location.isFromMockProvider
}
Log.d("GPS_STATUS", "Using last known location as fallback") Log.d("GPS_STATUS", "Using last known location as fallback")
onLocationUpdate(location, isMocked) onLocationUpdate(location, isMocked)
} }
} }
Log.d("GPS_STATUS", "One-shot GPS polling started")
} catch (e: SecurityException) { } catch (e: SecurityException) {
Log.e("GPS_STATUS", "SecurityException", e) Log.e("GPS_STATUS", "SecurityException", e)
} }
} }
fun stop() { fun stop() {
isPolling = false
handler.removeCallbacks(pollingRunnable)
locationManager.unregisterGnssStatusCallback(gnssStatusCallback) locationManager.unregisterGnssStatusCallback(gnssStatusCallback)
locationManager.removeUpdates(locationListener) Log.d("GPS_STATUS", "GPS polling stopped")
Log.d("GPS_STATUS", "GPS tracking stopped")
} }
private fun getConstellationName(type: Int): String { private fun getConstellationName(type: Int): String {