20260106-01
This commit is contained in:
parent
a392b97e50
commit
244f70b567
@ -40,13 +40,29 @@ import com.dumon.plugin.geolocation.utils.AuthStore
|
||||
@CapacitorPlugin(
|
||||
name = "DumonGeolocation",
|
||||
permissions = [
|
||||
Permission(strings = [
|
||||
Permission(
|
||||
alias = "location",
|
||||
strings = [
|
||||
Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
]
|
||||
),
|
||||
Permission(
|
||||
alias = "wifi",
|
||||
strings = [
|
||||
Manifest.permission.ACCESS_WIFI_STATE,
|
||||
Manifest.permission.CHANGE_WIFI_STATE,
|
||||
Manifest.permission.NEARBY_WIFI_DEVICES
|
||||
])
|
||||
]
|
||||
),
|
||||
Permission(
|
||||
alias = "backgroundLocation",
|
||||
strings = [Manifest.permission.ACCESS_BACKGROUND_LOCATION]
|
||||
),
|
||||
Permission(
|
||||
alias = "notifications",
|
||||
strings = [Manifest.permission.POST_NOTIFICATIONS]
|
||||
)
|
||||
]
|
||||
)
|
||||
class DumonGeolocation : Plugin() {
|
||||
@ -76,6 +92,7 @@ class DumonGeolocation : Plugin() {
|
||||
private var prevTimestamp: Long = 0L
|
||||
// private val significantChangeThreshold = 0.00007 // ~7 meters
|
||||
private var significantChangeThreshold = 7.0 // ~7 meters
|
||||
private var gpsMinDistanceMeters = 7.0
|
||||
private var speedChangeThreshold = 0.5f // m/s
|
||||
private var directionChangeThreshold = 0.17f // ~10 deg
|
||||
|
||||
@ -97,6 +114,10 @@ class DumonGeolocation : Plugin() {
|
||||
private var emitGnssStatus = false
|
||||
private var suppressMockedUpdates = false
|
||||
private var keepScreenOn = false
|
||||
private var lastSingleFixRequestTs: Long = 0L
|
||||
private val minSingleFixIntervalMs: Long = 1000L
|
||||
private var pendingPermissionAlias: String? = null
|
||||
private var pendingBackgroundPermissionAlias: String? = null
|
||||
|
||||
private var currentTrackingMode = GpsTrackingMode.NORMAL
|
||||
|
||||
@ -183,15 +204,19 @@ class DumonGeolocation : Plugin() {
|
||||
|
||||
@PluginMethod
|
||||
fun startPositioning(call: PluginCall) {
|
||||
if (!PermissionUtils.hasLocationAndWifiPermissions(context)) {
|
||||
call.reject("Required permissions not granted")
|
||||
if (!PermissionUtils.hasLocationPermissions(context)) {
|
||||
call.reject("Location permission not granted")
|
||||
return
|
||||
}
|
||||
|
||||
gpsManager?.start()
|
||||
imuManager?.start()
|
||||
if (PermissionUtils.hasWifiScanPermissions(context)) {
|
||||
wifiManager?.setEnableRtt(enableWifiRtt)
|
||||
wifiManager?.startPeriodicScan(wifiScanIntervalMs)
|
||||
} else {
|
||||
LogUtils.w("DUMON_GEOLOCATION", "Wi-Fi scan permissions not granted; skipping Wi-Fi scans")
|
||||
}
|
||||
applyKeepScreenOn(keepScreenOn)
|
||||
call.resolve()
|
||||
}
|
||||
@ -212,6 +237,13 @@ class DumonGeolocation : Plugin() {
|
||||
val hasFine = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
val hasCoarse = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
if (now - lastSingleFixRequestTs < minSingleFixIntervalMs) {
|
||||
call.resolve(buildPositionData())
|
||||
return
|
||||
}
|
||||
lastSingleFixRequestTs = now
|
||||
|
||||
val manager = gpsManager
|
||||
if (manager == null || (!hasFine && !hasCoarse)) {
|
||||
// No manager or no permissions — fallback immediately
|
||||
@ -245,36 +277,10 @@ class DumonGeolocation : Plugin() {
|
||||
|
||||
@PluginMethod
|
||||
fun checkAndRequestPermissions(call: PluginCall) {
|
||||
// requestAllPermissions(call, "checkAndRequestPermissions")
|
||||
val isLocationGranted =
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
val isWifiGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.NEARBY_WIFI_DEVICES) == PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
if (!isLocationGranted || !isWifiGranted) {
|
||||
requestAllPermissions(call, "onPermissionResult")
|
||||
if (!requestNextForegroundPermission(call)) {
|
||||
return
|
||||
}
|
||||
|
||||
val locationStatus = PermissionUtils.getPermissionStatus(
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
)
|
||||
val wifiStatus = PermissionUtils.getPermissionStatus(
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.NEARBY_WIFI_DEVICES)
|
||||
else
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
)
|
||||
|
||||
val result = JSObject().apply {
|
||||
put("location", locationStatus)
|
||||
put("wifi", wifiStatus)
|
||||
}
|
||||
|
||||
call.resolve(result)
|
||||
call.resolve(buildForegroundPermissionResult())
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
@ -343,11 +349,13 @@ class DumonGeolocation : Plugin() {
|
||||
val mode = call.getString("mode") ?: "normal"
|
||||
if (mode == "driving") {
|
||||
gpsManager?.startContinuousMode()
|
||||
gpsManager?.setMinDistanceMeters(0.0)
|
||||
currentTrackingMode = GpsTrackingMode.DRIVING
|
||||
startDrivingEmitLoop()
|
||||
LogUtils.d("DUMON_GEOLOCATION", "Switched to driving mode (continuous GPS)")
|
||||
} else {
|
||||
gpsManager?.startPollingMode()
|
||||
gpsManager?.setMinDistanceMeters(gpsMinDistanceMeters)
|
||||
currentTrackingMode = GpsTrackingMode.NORMAL
|
||||
stopDrivingEmitLoop()
|
||||
LogUtils.d("DUMON_GEOLOCATION", "Switched to normal mode (polling GPS)")
|
||||
@ -357,27 +365,21 @@ class DumonGeolocation : Plugin() {
|
||||
|
||||
@PermissionCallback
|
||||
private fun onPermissionResult(call: PluginCall) {
|
||||
val locationStatus = PermissionUtils.getPermissionStatus(
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
)
|
||||
val wifiStatus = PermissionUtils.getPermissionStatus(
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.NEARBY_WIFI_DEVICES)
|
||||
else
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
)
|
||||
|
||||
val result = JSObject().apply {
|
||||
put("location", locationStatus)
|
||||
put("wifi", wifiStatus)
|
||||
if (!requestNextForegroundPermission(call)) {
|
||||
return
|
||||
}
|
||||
|
||||
call.resolve(result)
|
||||
call.resolve(buildForegroundPermissionResult())
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
fun setOptions(call: PluginCall) {
|
||||
call.getDouble("distanceThresholdMeters")?.let { significantChangeThreshold = it }
|
||||
call.getDouble("distanceThresholdMeters")?.let {
|
||||
significantChangeThreshold = it
|
||||
gpsMinDistanceMeters = it
|
||||
if (currentTrackingMode == GpsTrackingMode.NORMAL) {
|
||||
gpsManager?.setMinDistanceMeters(it)
|
||||
}
|
||||
}
|
||||
call.getDouble("speedChangeThreshold")?.let { speedChangeThreshold = it.toFloat() }
|
||||
call.getDouble("directionChangeThreshold")?.let { directionChangeThreshold = it.toFloat() }
|
||||
call.getInt("emitDebounceMs")?.let {
|
||||
@ -480,19 +482,15 @@ class DumonGeolocation : Plugin() {
|
||||
|
||||
@PluginMethod
|
||||
fun startBackgroundTracking(call: PluginCall) {
|
||||
if (!ensureBackgroundPermissions(call)) {
|
||||
return
|
||||
}
|
||||
val title = call.getString("title") ?: "Location tracking active"
|
||||
val text = call.getString("text") ?: "Updating location in background"
|
||||
val channelId = call.getString("channelId") ?: "DUMON_GEO_BG"
|
||||
val channelName = call.getString("channelName") ?: "Dumon Geolocation"
|
||||
val postUrl = call.getString("postUrl")
|
||||
|
||||
val fine = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
val coarse = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
if (!fine && !coarse) {
|
||||
call.reject("Location permission not granted")
|
||||
return
|
||||
}
|
||||
|
||||
val intent = Intent(context, BackgroundLocationService::class.java).apply {
|
||||
putExtra(BackgroundLocationService.EXTRA_CHANNEL_ID, channelId)
|
||||
putExtra(BackgroundLocationService.EXTRA_CHANNEL_NAME, channelName)
|
||||
@ -800,4 +798,88 @@ class DumonGeolocation : Plugin() {
|
||||
applyKeepScreenOn(false)
|
||||
super.handleOnDestroy()
|
||||
}
|
||||
|
||||
private fun buildForegroundPermissionResult(): JSObject {
|
||||
val locationStatus = if (PermissionUtils.hasLocationPermissions(context)) "granted" else "denied"
|
||||
val wifiStatus = if (PermissionUtils.hasWifiScanPermissions(context)) "granted" else "denied"
|
||||
return JSObject().apply {
|
||||
put("location", locationStatus)
|
||||
put("wifi", wifiStatus)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMissingForegroundPermissionAlias(): String? {
|
||||
return when {
|
||||
!PermissionUtils.hasLocationPermissions(context) -> "location"
|
||||
!PermissionUtils.hasWifiScanPermissions(context) -> "wifi"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestNextForegroundPermission(call: PluginCall): Boolean {
|
||||
val missing = getMissingForegroundPermissionAlias()
|
||||
if (missing == null) {
|
||||
pendingPermissionAlias = null
|
||||
return true
|
||||
}
|
||||
|
||||
if (pendingPermissionAlias == missing) {
|
||||
pendingPermissionAlias = null
|
||||
call.resolve(buildForegroundPermissionResult())
|
||||
return false
|
||||
}
|
||||
|
||||
pendingPermissionAlias = missing
|
||||
call.save()
|
||||
requestPermissionForAlias(missing, call, "onPermissionResult")
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getMissingBackgroundPermissionAlias(): String? {
|
||||
if (!PermissionUtils.hasLocationPermissions(context)) {
|
||||
return "location"
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val bgGranted = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
if (!bgGranted) return "backgroundLocation"
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val notifGranted = ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
|
||||
if (!notifGranted) return "notifications"
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun ensureBackgroundPermissions(call: PluginCall): Boolean {
|
||||
val missing = getMissingBackgroundPermissionAlias()
|
||||
if (missing == null) {
|
||||
pendingBackgroundPermissionAlias = null
|
||||
return true
|
||||
}
|
||||
|
||||
if (pendingBackgroundPermissionAlias == missing) {
|
||||
pendingBackgroundPermissionAlias = null
|
||||
val msg = when (missing) {
|
||||
"location" -> "Location permission not granted"
|
||||
"backgroundLocation" -> "Background location permission not granted"
|
||||
"notifications" -> "Notification permission not granted"
|
||||
else -> "Required permission not granted"
|
||||
}
|
||||
call.reject(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
pendingBackgroundPermissionAlias = missing
|
||||
call.save()
|
||||
requestPermissionForAlias(missing, call, "onBackgroundPermissionResult")
|
||||
return false
|
||||
}
|
||||
|
||||
@PermissionCallback
|
||||
private fun onBackgroundPermissionResult(call: PluginCall) {
|
||||
if (!ensureBackgroundPermissions(call)) {
|
||||
return
|
||||
}
|
||||
startBackgroundTracking(call)
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ class GpsStatusManager(
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
|
||||
private var pollingIntervalMs: Long = 1000L // Default NORMAL mode
|
||||
private var isPolling = false
|
||||
private var minDistanceMeters: Float = 0f
|
||||
private var currentMode = GpsTrackingMode.NORMAL
|
||||
private var continuousListener: LocationListener? = null
|
||||
|
||||
@ -153,83 +153,17 @@ class GpsStatusManager(
|
||||
mainHandler.postDelayed(timeoutRunnable, timeoutMs)
|
||||
}
|
||||
|
||||
private fun pollOnceAndEmit() {
|
||||
val oneShotListener = object : LocationListener {
|
||||
override fun onLocationChanged(location: Location) {
|
||||
val providerTag = when (location.provider) {
|
||||
LocationManager.GPS_PROVIDER -> "[GPS]"
|
||||
LocationManager.NETWORK_PROVIDER -> "[NET]"
|
||||
else -> "[OTHER]"
|
||||
}
|
||||
|
||||
val timestamp = DateFormat.format("HH:mm:ss", System.currentTimeMillis())
|
||||
val isMocked = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
location.isMock
|
||||
} else {
|
||||
location.isFromMockProvider
|
||||
}
|
||||
|
||||
val info = "$providerTag Lat: ${location.latitude}, Lon: ${location.longitude}, Acc: ${location.accuracy} m @ $timestamp | Mock=$isMocked"
|
||||
LogUtils.d("GPS_LOCATION", info)
|
||||
|
||||
onLocationUpdate(location, isMocked)
|
||||
locationManager.removeUpdates(this)
|
||||
}
|
||||
|
||||
override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {}
|
||||
override fun onProviderEnabled(provider: String) {}
|
||||
override fun onProviderDisabled(provider: String) {}
|
||||
}
|
||||
val hasFine = ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
val hasCoarse = ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
var requested = false
|
||||
if (hasFine) {
|
||||
try {
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
0L,
|
||||
0f,
|
||||
oneShotListener
|
||||
)
|
||||
requested = true
|
||||
} catch (e: Exception) {
|
||||
LogUtils.e("GPS_STATUS", "Failed GPS one-shot request: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
if (hasCoarse) {
|
||||
try {
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.NETWORK_PROVIDER,
|
||||
0L,
|
||||
0f,
|
||||
oneShotListener
|
||||
)
|
||||
requested = true
|
||||
} catch (e: Exception) {
|
||||
LogUtils.e("GPS_STATUS", "Failed NETWORK one-shot request: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
if (!requested) {
|
||||
LogUtils.e("GPS_STATUS", "pollOnceAndEmit: no provider requested (missing permissions)")
|
||||
}
|
||||
}
|
||||
|
||||
private val pollingRunnable = object : Runnable {
|
||||
override fun run() {
|
||||
if (!isPolling) return
|
||||
pollOnceAndEmit()
|
||||
handler.postDelayed(this, pollingIntervalMs)
|
||||
}
|
||||
}
|
||||
|
||||
fun setPollingInterval(intervalMs: Long) {
|
||||
this.pollingIntervalMs = intervalMs
|
||||
if (isPolling) {
|
||||
handler.removeCallbacks(pollingRunnable)
|
||||
handler.postDelayed(pollingRunnable, pollingIntervalMs)
|
||||
if (currentMode == GpsTrackingMode.NORMAL) {
|
||||
startContinuousUpdates(pollingIntervalMs, minDistanceMeters)
|
||||
}
|
||||
}
|
||||
|
||||
fun setMinDistanceMeters(distanceMeters: Double) {
|
||||
minDistanceMeters = distanceMeters.toFloat().coerceAtLeast(0f)
|
||||
if (currentMode == GpsTrackingMode.NORMAL) {
|
||||
startContinuousUpdates(pollingIntervalMs, minDistanceMeters)
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,11 +172,14 @@ class GpsStatusManager(
|
||||
stop() // Reset dulu
|
||||
currentMode = mode
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
val hasFine = ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
val hasCoarse = ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
||||
if (!hasFine && !hasCoarse) {
|
||||
LogUtils.e("GPS_STATUS", "Missing location permissions")
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
locationManager.registerGnssStatusCallback(
|
||||
ContextCompat.getMainExecutor(context),
|
||||
@ -251,12 +188,14 @@ class GpsStatusManager(
|
||||
} else {
|
||||
locationManager.registerGnssStatusCallback(gnssStatusCallback, handler)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
LogUtils.e("GPS_STATUS", "Failed to register GNSS status callback: ${e.message}")
|
||||
}
|
||||
|
||||
if (mode == GpsTrackingMode.DRIVING) {
|
||||
startContinuousUpdates()
|
||||
startContinuousUpdates(0L, 0f)
|
||||
} else {
|
||||
isPolling = true
|
||||
handler.post(pollingRunnable)
|
||||
startContinuousUpdates(pollingIntervalMs, minDistanceMeters)
|
||||
}
|
||||
|
||||
// Fallback lokasi terakhir
|
||||
@ -274,12 +213,25 @@ class GpsStatusManager(
|
||||
LogUtils.d("GPS_STATUS", "GPS started with mode: $mode")
|
||||
}
|
||||
|
||||
private fun startContinuousUpdates() {
|
||||
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
LogUtils.e("GPS_STATUS", "Missing ACCESS_FINE_LOCATION permission")
|
||||
private fun startContinuousUpdates(minTimeMs: Long, minDistanceMeters: Float) {
|
||||
val hasFine = ActivityCompat.checkSelfPermission(
|
||||
context,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
val hasCoarse = ActivityCompat.checkSelfPermission(
|
||||
context,
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
if (!hasFine && !hasCoarse) {
|
||||
LogUtils.e("GPS_STATUS", "Missing location permissions")
|
||||
return
|
||||
}
|
||||
|
||||
continuousListener?.let {
|
||||
try { locationManager.removeUpdates(it) } catch (_: Exception) {}
|
||||
}
|
||||
|
||||
continuousListener = object : LocationListener {
|
||||
override fun onLocationChanged(location: Location) {
|
||||
val isMocked = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) location.isMock else location.isFromMockProvider
|
||||
@ -291,31 +243,77 @@ class GpsStatusManager(
|
||||
override fun onProviderDisabled(provider: String) {}
|
||||
}
|
||||
|
||||
val gpsEnabled = try {
|
||||
locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
val netEnabled = try {
|
||||
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
if (!gpsEnabled && !netEnabled) {
|
||||
LogUtils.w("GPS_STATUS", "No provider enabled; skip location requests")
|
||||
}
|
||||
|
||||
var requested = false
|
||||
if (hasFine && gpsEnabled) {
|
||||
try {
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
0L,
|
||||
0f,
|
||||
minTimeMs,
|
||||
minDistanceMeters,
|
||||
continuousListener!!
|
||||
)
|
||||
requested = true
|
||||
} catch (e: Exception) {
|
||||
LogUtils.e("GPS_STATUS", "Failed GPS request: ${e.message}")
|
||||
}
|
||||
} else if (hasFine) {
|
||||
LogUtils.w("GPS_STATUS", "GPS provider disabled; skip GPS request")
|
||||
}
|
||||
|
||||
LogUtils.d("GPS_STATUS", "Started continuous location updates")
|
||||
if (hasCoarse && netEnabled) {
|
||||
try {
|
||||
locationManager.requestLocationUpdates(
|
||||
LocationManager.NETWORK_PROVIDER,
|
||||
minTimeMs,
|
||||
minDistanceMeters,
|
||||
continuousListener!!
|
||||
)
|
||||
requested = true
|
||||
} catch (e: Exception) {
|
||||
LogUtils.e("GPS_STATUS", "Failed NETWORK request: ${e.message}")
|
||||
}
|
||||
} else if (hasCoarse) {
|
||||
LogUtils.w("GPS_STATUS", "Network provider disabled; skip NETWORK request")
|
||||
}
|
||||
|
||||
if (requested) {
|
||||
LogUtils.d("GPS_STATUS", "Started continuous updates (minTimeMs=$minTimeMs, minDistanceMeters=$minDistanceMeters)")
|
||||
} else {
|
||||
LogUtils.e("GPS_STATUS", "No provider requested (permissions/providers)")
|
||||
}
|
||||
}
|
||||
|
||||
fun startContinuousMode() {
|
||||
stop()
|
||||
startContinuousUpdates()
|
||||
currentMode = GpsTrackingMode.DRIVING
|
||||
startContinuousUpdates(0L, 0f)
|
||||
}
|
||||
|
||||
fun startPollingMode() {
|
||||
stop()
|
||||
isPolling = true
|
||||
handler.post(pollingRunnable)
|
||||
currentMode = GpsTrackingMode.NORMAL
|
||||
startContinuousUpdates(pollingIntervalMs, minDistanceMeters)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
isPolling = false
|
||||
handler.removeCallbacks(pollingRunnable)
|
||||
try {
|
||||
locationManager.unregisterGnssStatusCallback(gnssStatusCallback)
|
||||
} catch (_: Exception) {}
|
||||
continuousListener?.let {
|
||||
locationManager.removeUpdates(it)
|
||||
continuousListener = null
|
||||
|
||||
@ -29,6 +29,7 @@ class ImuSensorManager(
|
||||
|
||||
private var latestDirectionRad = 0f
|
||||
private var latestSpeed = 0f
|
||||
private var lastLogTimestampMs: Long = 0L
|
||||
|
||||
private var currentDelay: Int = SensorManager.SENSOR_DELAY_GAME
|
||||
|
||||
@ -111,9 +112,16 @@ class ImuSensorManager(
|
||||
|
||||
emitCombinedImuData(speed, acceleration, latestDirectionRad)
|
||||
|
||||
LogUtils.d("IMU_SENSOR", "Accel x: %.3f y: %.3f z: %.3f | Speed: %.3f | AccelMag: %.3f | Dir: %.2f rad".format(
|
||||
val nowMs = System.currentTimeMillis()
|
||||
if (nowMs - lastLogTimestampMs >= 1000L) {
|
||||
lastLogTimestampMs = nowMs
|
||||
LogUtils.d(
|
||||
"IMU_SENSOR",
|
||||
"Accel x: %.3f y: %.3f z: %.3f | Speed: %.3f | AccelMag: %.3f | Dir: %.2f rad".format(
|
||||
lastAccel[0], lastAccel[1], lastAccel[2], speed, acceleration, latestDirectionRad
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleGyroscope(event: SensorEvent) {
|
||||
|
||||
@ -57,11 +57,6 @@ object BgPrefs {
|
||||
.putLong(KEY_TS, timestamp)
|
||||
.putString(KEY_SRC, source)
|
||||
.putBoolean(KEY_MOCK, isMocked)
|
||||
.apply()
|
||||
|
||||
// Optional IMU fields
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit()
|
||||
.putFloat(KEY_SPEED, speed ?: 0f)
|
||||
.putFloat(KEY_ACCEL, acceleration ?: 0f)
|
||||
.putFloat(KEY_DIR, directionRad ?: 0f)
|
||||
|
||||
@ -7,18 +7,28 @@ import android.os.Build
|
||||
import androidx.core.app.ActivityCompat
|
||||
|
||||
object PermissionUtils {
|
||||
fun hasLocationAndWifiPermissions(context: Context): Boolean {
|
||||
fun hasLocationPermissions(context: Context): Boolean {
|
||||
val fineLocation = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
val coarseLocation = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||
val nearbyWifi = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.NEARBY_WIFI_DEVICES)
|
||||
} else {
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
return fineLocation == PackageManager.PERMISSION_GRANTED || coarseLocation == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
return fineLocation == PackageManager.PERMISSION_GRANTED &&
|
||||
coarseLocation == PackageManager.PERMISSION_GRANTED &&
|
||||
nearbyWifi == PackageManager.PERMISSION_GRANTED
|
||||
fun hasWifiScanPermissions(context: Context): Boolean {
|
||||
val wifiState = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_WIFI_STATE)
|
||||
val changeWifi = ActivityCompat.checkSelfPermission(context, Manifest.permission.CHANGE_WIFI_STATE)
|
||||
if (wifiState != PackageManager.PERMISSION_GRANTED || changeWifi != PackageManager.PERMISSION_GRANTED) {
|
||||
return false
|
||||
}
|
||||
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ActivityCompat.checkSelfPermission(context, Manifest.permission.NEARBY_WIFI_DEVICES) == PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
hasLocationPermissions(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun hasLocationAndWifiPermissions(context: Context): Boolean {
|
||||
return hasLocationPermissions(context) && hasWifiScanPermissions(context)
|
||||
}
|
||||
|
||||
fun getPermissionStatus(granted: Int): String {
|
||||
|
||||
@ -14,8 +14,8 @@ import android.net.wifi.rtt.WifiRttManager
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import com.dumon.plugin.geolocation.utils.LogUtils
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.dumon.plugin.geolocation.utils.PermissionUtils
|
||||
|
||||
class WifiPositioningManager(
|
||||
private val context: Context,
|
||||
@ -62,18 +62,20 @@ class WifiPositioningManager(
|
||||
}
|
||||
|
||||
fun startWifiScan() {
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
if (!PermissionUtils.hasWifiScanPermissions(context)) {
|
||||
LogUtils.e("WIFI_POSITION", "Missing Wi-Fi scan permission")
|
||||
onWifiPositioningUpdate(WifiScanResult(0, emptyList()))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
val success = wifiManager.startScan()
|
||||
if (!success) {
|
||||
LogUtils.e("WIFI_POSITION", "Wi-Fi scan failed")
|
||||
onWifiPositioningUpdate(WifiScanResult(0, emptyList()))
|
||||
}
|
||||
} else {
|
||||
LogUtils.e("WIFI_POSITION", "Missing ACCESS_FINE_LOCATION permission")
|
||||
} catch (e: SecurityException) {
|
||||
LogUtils.e("WIFI_POSITION", "SecurityException on Wi-Fi scan: ${e.message}")
|
||||
onWifiPositioningUpdate(WifiScanResult(0, emptyList()))
|
||||
}
|
||||
}
|
||||
|
||||
2
dist/esm/definitions.js.map
vendored
2
dist/esm/definitions.js.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n// export interface SatelliteStatus {\n// satellitesInView: number;\n// usedInFix: number;\n// constellationCounts: { [key: string]: number };\n// }\n\n// export interface WifiAp {\n// ssid: string;\n// bssid: string;\n// rssi: number;\n// distance?: number;\n// }\n\n// export interface WifiScanResult {\n// apCount: number;\n// aps: WifiAp[];\n// }\n\n// export interface ImuData {\n// accelX: number;\n// accelY: number;\n// accelZ: number;\n// gyroX: number;\n// gyroY: number;\n// gyroZ: number;\n// speed?: number;\n// acceleration?: number;\n// directionRad?: number;\n// }\n\n// export interface GpsData {\n// latitude: number;\n// longitude: number;\n// accuracy: number;\n// satellitesInView?: number;\n// usedInFix?: number;\n// constellationCounts?: { [key: string]: number };\n// }\n\n// export interface PositioningData {\n// source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK';\n// timestamp: number;\n// latitude: number;\n// longitude: number;\n// accuracy: number;\n\n// gnssData?: SatelliteStatus;\n// wifiData?: WifiAp[];\n// imuData?: ImuData;\n// }\n\nexport interface PositioningData {\n source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK';\n timestamp: number;\n latitude: number;\n longitude: number;\n accuracy: number;\n speed: number;\n acceleration: number;\n directionRad: number;\n isMocked: boolean;\n mode: 'normal' | 'driving';\n predicted?: boolean;\n // Optional detailed speed fields and provenance\n speedSource?: 'GNSS' | 'IMU' | 'DELTA' | 'NONE';\n speedGnss?: number; // m/s from Location.getSpeed when available and fresh\n speedImu?: number; // m/s from IMU fusion (internal heuristic)\n speedDerived?: number; // m/s from delta-position / delta-time (coarse)\n}\n\nexport interface SatelliteStatus {\n satellitesInView: number;\n usedInFix: number;\n constellationCounts: { [key: string]: number };\n}\n\nexport interface DumonGeoOptions {\n distanceThresholdMeters?: number;\n speedChangeThreshold?: number;\n directionChangeThreshold?: number;\n emitDebounceMs?: number;\n drivingEmitIntervalMs?: number;\n wifiScanIntervalMs?: number;\n enableWifiRtt?: boolean;\n enableLogging?: boolean;\n enableForwardPrediction?: boolean;\n maxPredictionSeconds?: number;\n emitGnssStatus?: boolean;\n suppressMockedUpdates?: boolean;\n keepScreenOn?: boolean;\n backgroundPollingIntervalMs?: number; // Android background polling interval\n backgroundPostMinDistanceMeters?: number; // Android background min distance to post\n backgroundPostMinAccuracyMeters?: number; // Android background min acceptable accuracy for POST (meters)\n backgroundMinPostIntervalMs?: number; // Android background minimum interval between POST attempts\n backgroundUseImuFallback?: boolean; // Android background: enable IMU-based speed fallback (default true)\n}\n\nexport interface PermissionStatus {\n location: 'granted' | 'denied';\n wifi: 'granted' | 'denied';\n}\n\nexport interface DumonGeolocationPlugin {\n startPositioning(): Promise<void>;\n stopPositioning(): Promise<void>;\n getLatestPosition(): Promise<PositioningData>;\n checkAndRequestPermissions(): Promise<PermissionStatus>;\n setOptions(options: DumonGeoOptions): Promise<void>;\n getGnssStatus(): Promise<SatelliteStatus | null>;\n getLocationServicesStatus(): Promise<{ gpsEnabled: boolean; networkEnabled: boolean }>;\n // Background tracking (Android)\n startBackgroundTracking(options?: {\n title?: string;\n text?: string;\n channelId?: string;\n channelName?: string;\n postUrl?: string; // optional: service will POST latest fixes here as JSON\n }): Promise<void>;\n stopBackgroundTracking(): Promise<void>;\n isBackgroundTrackingActive(): Promise<{ active: boolean }>;\n getBackgroundLatestPosition(): Promise<PositioningData | null>;\n openBackgroundPermissionSettings(): Promise<void>;\n openNotificationPermissionSettings(): Promise<void>;\n // Auth token management for background posting\n setAuthTokens(tokens: { accessToken: string; refreshToken: string }): Promise<void>;\n clearAuthTokens(): Promise<void>;\n getAuthState(): Promise<{ present: boolean }>;\n setBackgroundPostUrl(options: { url?: string }): Promise<void>;\n getBackgroundPostUrl(): Promise<{ url: string | null }>;\n\n configureEdgeToEdge(options: {\n bgColor: string;\n style: 'DARK' | 'LIGHT';\n overlay?: boolean;\n }): Promise<void>;\n\n setGpsMode(options: { mode: 'normal' | 'driving' }): Promise<void>;\n\n addListener(\n eventName: 'onPositionUpdate',\n listenerFunc: (data: PositioningData) => void\n ): PluginListenerHandle;\n\n addListener(\n eventName: 'onGnssStatus',\n listenerFunc: (data: SatelliteStatus) => void\n ): PluginListenerHandle;\n}\n"]}
|
||||
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n// export interface SatelliteStatus {\n// satellitesInView: number;\n// usedInFix: number;\n// constellationCounts: { [key: string]: number };\n// }\n\n// export interface WifiAp {\n// ssid: string;\n// bssid: string;\n// rssi: number;\n// distance?: number;\n// }\n\n// export interface WifiScanResult {\n// apCount: number;\n// aps: WifiAp[];\n// }\n\n// export interface ImuData {\n// accelX: number;\n// accelY: number;\n// accelZ: number;\n// gyroX: number;\n// gyroY: number;\n// gyroZ: number;\n// speed?: number;\n// acceleration?: number;\n// directionRad?: number;\n// }\n\n// export interface GpsData {\n// latitude: number;\n// longitude: number;\n// accuracy: number;\n// satellitesInView?: number;\n// usedInFix?: number;\n// constellationCounts?: { [key: string]: number };\n// }\n\n// export interface PositioningData {\n// source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK';\n// timestamp: number;\n// latitude: number;\n// longitude: number;\n// accuracy: number;\n\n// gnssData?: SatelliteStatus;\n// wifiData?: WifiAp[];\n// imuData?: ImuData;\n// }\n\nexport interface PositioningData {\n source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK';\n timestamp: number;\n latitude: number;\n longitude: number;\n accuracy: number;\n speed: number;\n acceleration: number;\n directionRad: number;\n isMocked: boolean;\n mode: 'normal' | 'driving';\n predicted?: boolean;\n // Optional detailed speed fields and provenance\n speedSource?: 'GNSS' | 'IMU' | 'DELTA' | 'NONE';\n speedGnss?: number; // m/s from Location.getSpeed when available and fresh\n speedImu?: number; // m/s from IMU fusion (internal heuristic)\n speedDerived?: number; // m/s from delta-position / delta-time (coarse)\n}\n\nexport interface SatelliteStatus {\n satellitesInView: number;\n usedInFix: number;\n constellationCounts: { [key: string]: number };\n}\n\nexport interface DumonGeoOptions {\n distanceThresholdMeters?: number;\n speedChangeThreshold?: number;\n directionChangeThreshold?: number;\n emitDebounceMs?: number;\n drivingEmitIntervalMs?: number;\n wifiScanIntervalMs?: number;\n enableWifiRtt?: boolean;\n enableLogging?: boolean;\n enableForwardPrediction?: boolean;\n maxPredictionSeconds?: number;\n emitGnssStatus?: boolean;\n suppressMockedUpdates?: boolean;\n keepScreenOn?: boolean;\n backgroundPollingIntervalMs?: number; // Android background polling interval\n backgroundPostMinDistanceMeters?: number; // Android background min distance to post\n backgroundPostMinAccuracyMeters?: number; // Android background min acceptable accuracy for POST (meters)\n backgroundMinPostIntervalMs?: number; // Android background minimum interval between POST attempts\n backgroundUseImuFallback?: boolean; // Android background: enable IMU-based speed fallback (default false)\n}\n\nexport interface PermissionStatus {\n location: 'granted' | 'denied';\n wifi: 'granted' | 'denied';\n}\n\nexport interface DumonGeolocationPlugin {\n startPositioning(): Promise<void>;\n stopPositioning(): Promise<void>;\n getLatestPosition(): Promise<PositioningData>;\n checkAndRequestPermissions(): Promise<PermissionStatus>;\n setOptions(options: DumonGeoOptions): Promise<void>;\n getGnssStatus(): Promise<SatelliteStatus | null>;\n getLocationServicesStatus(): Promise<{ gpsEnabled: boolean; networkEnabled: boolean }>;\n // Background tracking (Android)\n startBackgroundTracking(options?: {\n title?: string;\n text?: string;\n channelId?: string;\n channelName?: string;\n postUrl?: string; // optional: service will POST latest fixes here as JSON\n }): Promise<void>;\n stopBackgroundTracking(): Promise<void>;\n isBackgroundTrackingActive(): Promise<{ active: boolean }>;\n getBackgroundLatestPosition(): Promise<PositioningData | null>;\n openBackgroundPermissionSettings(): Promise<void>;\n openNotificationPermissionSettings(): Promise<void>;\n // Auth token management for background posting\n setAuthTokens(tokens: { accessToken: string; refreshToken: string }): Promise<void>;\n clearAuthTokens(): Promise<void>;\n getAuthState(): Promise<{ present: boolean }>;\n setBackgroundPostUrl(options: { url?: string }): Promise<void>;\n getBackgroundPostUrl(): Promise<{ url: string | null }>;\n\n configureEdgeToEdge(options: {\n bgColor: string;\n style: 'DARK' | 'LIGHT';\n overlay?: boolean;\n }): Promise<void>;\n\n setGpsMode(options: { mode: 'normal' | 'driving' }): Promise<void>;\n\n addListener(\n eventName: 'onPositionUpdate',\n listenerFunc: (data: PositioningData) => void\n ): PluginListenerHandle;\n\n addListener(\n eventName: 'onGnssStatus',\n listenerFunc: (data: SatelliteStatus) => void\n ): PluginListenerHandle;\n}\n"]}
|
||||
6
dist/esm/index.d.ts
vendored
6
dist/esm/index.d.ts
vendored
@ -1,4 +1,8 @@
|
||||
import type { DumonGeolocationPlugin } from './definitions';
|
||||
declare const DumonGeolocation: DumonGeolocationPlugin;
|
||||
declare const DumonGeolocationPlugin: DumonGeolocationPlugin;
|
||||
declare const DumonGeolocation: DumonGeolocationPlugin & {
|
||||
getGnssStatus(): Promise<import("./definitions").SatelliteStatus | null>;
|
||||
getBackgroundLatestPosition(): Promise<import("./definitions").PositioningData | null>;
|
||||
};
|
||||
export * from './definitions';
|
||||
export { DumonGeolocation };
|
||||
|
||||
17
dist/esm/index.js
vendored
17
dist/esm/index.js
vendored
@ -1,7 +1,22 @@
|
||||
import { registerPlugin } from '@capacitor/core';
|
||||
const DumonGeolocation = registerPlugin('DumonGeolocation', {
|
||||
const DumonGeolocationPlugin = registerPlugin('DumonGeolocation', {
|
||||
web: () => import('./web').then((m) => new m.DumonGeolocationWeb()),
|
||||
});
|
||||
const isEmptyObject = (value) => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value))
|
||||
return false;
|
||||
return Object.keys(value).length === 0;
|
||||
};
|
||||
const DumonGeolocation = Object.assign(DumonGeolocationPlugin, {
|
||||
async getGnssStatus() {
|
||||
const result = await DumonGeolocationPlugin.getGnssStatus();
|
||||
return isEmptyObject(result) ? null : result;
|
||||
},
|
||||
async getBackgroundLatestPosition() {
|
||||
const result = await DumonGeolocationPlugin.getBackgroundLatestPosition();
|
||||
return isEmptyObject(result) ? null : result;
|
||||
},
|
||||
});
|
||||
export * from './definitions';
|
||||
export { DumonGeolocation };
|
||||
//# sourceMappingURL=index.js.map
|
||||
2
dist/esm/index.js.map
vendored
2
dist/esm/index.js.map
vendored
@ -1 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,gBAAgB,GAAG,cAAc,CAAyB,kBAAkB,EAAE;IAClF,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;CACpE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { DumonGeolocationPlugin } from './definitions';\n\nconst DumonGeolocation = registerPlugin<DumonGeolocationPlugin>('DumonGeolocation', {\n web: () => import('./web').then((m) => new m.DumonGeolocationWeb()),\n});\n\nexport * from './definitions';\nexport { DumonGeolocation };"]}
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,sBAAsB,GAAG,cAAc,CAAyB,kBAAkB,EAAE;IACxF,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,mBAAmB,EAAE,CAAC;CACpE,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,CAAC,KAAc,EAAW,EAAE;IAChD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,OAAO,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACpE,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,EAAE;IAC7D,KAAK,CAAC,aAAa;QACjB,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,aAAa,EAAE,CAAC;QAC5D,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,CAAC;IACD,KAAK,CAAC,2BAA2B;QAC/B,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,2BAA2B,EAAE,CAAC;QAC1E,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,CAAC;CACF,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { DumonGeolocationPlugin } from './definitions';\n\nconst DumonGeolocationPlugin = registerPlugin<DumonGeolocationPlugin>('DumonGeolocation', {\n web: () => import('./web').then((m) => new m.DumonGeolocationWeb()),\n});\n\nconst isEmptyObject = (value: unknown): boolean => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n return Object.keys(value as Record<string, unknown>).length === 0;\n};\n\nconst DumonGeolocation = Object.assign(DumonGeolocationPlugin, {\n async getGnssStatus() {\n const result = await DumonGeolocationPlugin.getGnssStatus();\n return isEmptyObject(result) ? null : result;\n },\n async getBackgroundLatestPosition() {\n const result = await DumonGeolocationPlugin.getBackgroundLatestPosition();\n return isEmptyObject(result) ? null : result;\n },\n});\n\nexport * from './definitions';\nexport { DumonGeolocation };\n"]}
|
||||
105
dist/plugin.cjs.js
vendored
105
dist/plugin.cjs.js
vendored
@ -1,105 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var core = require('@capacitor/core');
|
||||
|
||||
const DumonGeolocation = core.registerPlugin('DumonGeolocation', {
|
||||
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.DumonGeolocationWeb()),
|
||||
});
|
||||
|
||||
class DumonGeolocationWeb extends core.WebPlugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this._mode = 'normal';
|
||||
}
|
||||
async startPositioning() {
|
||||
console.log('DumonGeolocationWeb: startPositioning() called (no-op)');
|
||||
}
|
||||
async stopPositioning() {
|
||||
console.log('DumonGeolocationWeb: stopPositioning() called (no-op)');
|
||||
}
|
||||
async getLatestPosition() {
|
||||
console.log('DumonGeolocationWeb: getLatestPosition() called (returning dummy data)');
|
||||
return {
|
||||
source: 'GNSS',
|
||||
timestamp: Date.now(),
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
accuracy: 999,
|
||||
speed: 0,
|
||||
acceleration: 0,
|
||||
directionRad: 0,
|
||||
isMocked: false,
|
||||
mode: this._mode,
|
||||
speedSource: 'NONE',
|
||||
speedImu: 0,
|
||||
speedGnss: 0,
|
||||
speedDerived: 0,
|
||||
};
|
||||
}
|
||||
async checkAndRequestPermissions() {
|
||||
console.info('[dumon-geolocation] checkAndRequestPermissions mocked for web.');
|
||||
return {
|
||||
location: 'granted',
|
||||
wifi: 'granted',
|
||||
};
|
||||
}
|
||||
async configureEdgeToEdge(options) {
|
||||
console.info('[dumon-geolocation] configureEdgeToEdge called on web with:', options);
|
||||
// No-op
|
||||
}
|
||||
async setOptions(_options) {
|
||||
// No-op on web
|
||||
}
|
||||
async setGpsMode(options) {
|
||||
this._mode = (options === null || options === void 0 ? void 0 : options.mode) === 'driving' ? 'driving' : 'normal';
|
||||
}
|
||||
async getGnssStatus() {
|
||||
return null;
|
||||
}
|
||||
async getLocationServicesStatus() {
|
||||
// Web stub; assume enabled
|
||||
return { gpsEnabled: true, networkEnabled: true };
|
||||
}
|
||||
// Background tracking stubs (no-op on web)
|
||||
async startBackgroundTracking(_options) {
|
||||
console.info('[dumon-geolocation] startBackgroundTracking is not supported on web.');
|
||||
}
|
||||
async stopBackgroundTracking() {
|
||||
console.info('[dumon-geolocation] stopBackgroundTracking is not supported on web.');
|
||||
}
|
||||
async isBackgroundTrackingActive() {
|
||||
return { active: false };
|
||||
}
|
||||
async getBackgroundLatestPosition() {
|
||||
return null;
|
||||
}
|
||||
async openBackgroundPermissionSettings() {
|
||||
console.info('[dumon-geolocation] openBackgroundPermissionSettings is not supported on web.');
|
||||
}
|
||||
async openNotificationPermissionSettings() {
|
||||
console.info('[dumon-geolocation] openNotificationPermissionSettings is not supported on web.');
|
||||
}
|
||||
async setAuthTokens(_tokens) {
|
||||
console.info('[dumon-geolocation] setAuthTokens is a no-op on web.');
|
||||
}
|
||||
async clearAuthTokens() {
|
||||
console.info('[dumon-geolocation] clearAuthTokens is a no-op on web.');
|
||||
}
|
||||
async getAuthState() {
|
||||
return { present: false };
|
||||
}
|
||||
async setBackgroundPostUrl(_options) {
|
||||
console.info('[dumon-geolocation] setBackgroundPostUrl is not supported on web.');
|
||||
}
|
||||
async getBackgroundPostUrl() {
|
||||
return { url: null };
|
||||
}
|
||||
}
|
||||
|
||||
var web = /*#__PURE__*/Object.freeze({
|
||||
__proto__: null,
|
||||
DumonGeolocationWeb: DumonGeolocationWeb
|
||||
});
|
||||
|
||||
exports.DumonGeolocation = DumonGeolocation;
|
||||
//# sourceMappingURL=plugin.cjs.js.map
|
||||
1
dist/plugin.cjs.js.map
vendored
1
dist/plugin.cjs.js.map
vendored
File diff suppressed because one or more lines are too long
108
dist/plugin.js
vendored
108
dist/plugin.js
vendored
@ -1,108 +0,0 @@
|
||||
var capacitorDumonGeolocation = (function (exports, core) {
|
||||
'use strict';
|
||||
|
||||
const DumonGeolocation = core.registerPlugin('DumonGeolocation', {
|
||||
web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.DumonGeolocationWeb()),
|
||||
});
|
||||
|
||||
class DumonGeolocationWeb extends core.WebPlugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this._mode = 'normal';
|
||||
}
|
||||
async startPositioning() {
|
||||
console.log('DumonGeolocationWeb: startPositioning() called (no-op)');
|
||||
}
|
||||
async stopPositioning() {
|
||||
console.log('DumonGeolocationWeb: stopPositioning() called (no-op)');
|
||||
}
|
||||
async getLatestPosition() {
|
||||
console.log('DumonGeolocationWeb: getLatestPosition() called (returning dummy data)');
|
||||
return {
|
||||
source: 'GNSS',
|
||||
timestamp: Date.now(),
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
accuracy: 999,
|
||||
speed: 0,
|
||||
acceleration: 0,
|
||||
directionRad: 0,
|
||||
isMocked: false,
|
||||
mode: this._mode,
|
||||
speedSource: 'NONE',
|
||||
speedImu: 0,
|
||||
speedGnss: 0,
|
||||
speedDerived: 0,
|
||||
};
|
||||
}
|
||||
async checkAndRequestPermissions() {
|
||||
console.info('[dumon-geolocation] checkAndRequestPermissions mocked for web.');
|
||||
return {
|
||||
location: 'granted',
|
||||
wifi: 'granted',
|
||||
};
|
||||
}
|
||||
async configureEdgeToEdge(options) {
|
||||
console.info('[dumon-geolocation] configureEdgeToEdge called on web with:', options);
|
||||
// No-op
|
||||
}
|
||||
async setOptions(_options) {
|
||||
// No-op on web
|
||||
}
|
||||
async setGpsMode(options) {
|
||||
this._mode = (options === null || options === void 0 ? void 0 : options.mode) === 'driving' ? 'driving' : 'normal';
|
||||
}
|
||||
async getGnssStatus() {
|
||||
return null;
|
||||
}
|
||||
async getLocationServicesStatus() {
|
||||
// Web stub; assume enabled
|
||||
return { gpsEnabled: true, networkEnabled: true };
|
||||
}
|
||||
// Background tracking stubs (no-op on web)
|
||||
async startBackgroundTracking(_options) {
|
||||
console.info('[dumon-geolocation] startBackgroundTracking is not supported on web.');
|
||||
}
|
||||
async stopBackgroundTracking() {
|
||||
console.info('[dumon-geolocation] stopBackgroundTracking is not supported on web.');
|
||||
}
|
||||
async isBackgroundTrackingActive() {
|
||||
return { active: false };
|
||||
}
|
||||
async getBackgroundLatestPosition() {
|
||||
return null;
|
||||
}
|
||||
async openBackgroundPermissionSettings() {
|
||||
console.info('[dumon-geolocation] openBackgroundPermissionSettings is not supported on web.');
|
||||
}
|
||||
async openNotificationPermissionSettings() {
|
||||
console.info('[dumon-geolocation] openNotificationPermissionSettings is not supported on web.');
|
||||
}
|
||||
async setAuthTokens(_tokens) {
|
||||
console.info('[dumon-geolocation] setAuthTokens is a no-op on web.');
|
||||
}
|
||||
async clearAuthTokens() {
|
||||
console.info('[dumon-geolocation] clearAuthTokens is a no-op on web.');
|
||||
}
|
||||
async getAuthState() {
|
||||
return { present: false };
|
||||
}
|
||||
async setBackgroundPostUrl(_options) {
|
||||
console.info('[dumon-geolocation] setBackgroundPostUrl is not supported on web.');
|
||||
}
|
||||
async getBackgroundPostUrl() {
|
||||
return { url: null };
|
||||
}
|
||||
}
|
||||
|
||||
var web = /*#__PURE__*/Object.freeze({
|
||||
__proto__: null,
|
||||
DumonGeolocationWeb: DumonGeolocationWeb
|
||||
});
|
||||
|
||||
exports.DumonGeolocation = DumonGeolocation;
|
||||
|
||||
return exports;
|
||||
|
||||
})({}, capacitorExports);
|
||||
//# sourceMappingURL=plugin.js.map
|
||||
1
dist/plugin.js.map
vendored
1
dist/plugin.js.map
vendored
File diff suppressed because one or more lines are too long
18
src/index.ts
18
src/index.ts
@ -2,9 +2,25 @@ import { registerPlugin } from '@capacitor/core';
|
||||
|
||||
import type { DumonGeolocationPlugin } from './definitions';
|
||||
|
||||
const DumonGeolocation = registerPlugin<DumonGeolocationPlugin>('DumonGeolocation', {
|
||||
const DumonGeolocationPlugin = registerPlugin<DumonGeolocationPlugin>('DumonGeolocation', {
|
||||
web: () => import('./web').then((m) => new m.DumonGeolocationWeb()),
|
||||
});
|
||||
|
||||
const isEmptyObject = (value: unknown): boolean => {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
||||
return Object.keys(value as Record<string, unknown>).length === 0;
|
||||
};
|
||||
|
||||
const DumonGeolocation = Object.assign(DumonGeolocationPlugin, {
|
||||
async getGnssStatus() {
|
||||
const result = await DumonGeolocationPlugin.getGnssStatus();
|
||||
return isEmptyObject(result) ? null : result;
|
||||
},
|
||||
async getBackgroundLatestPosition() {
|
||||
const result = await DumonGeolocationPlugin.getBackgroundLatestPosition();
|
||||
return isEmptyObject(result) ? null : result;
|
||||
},
|
||||
});
|
||||
|
||||
export * from './definitions';
|
||||
export { DumonGeolocation };
|
||||
Loading…
x
Reference in New Issue
Block a user