From 8ecd890bc95d0daf83f7b476aa4684466e22d6f0 Mon Sep 17 00:00:00 2001 From: wengki81 Date: Sun, 15 Jun 2025 00:04:11 +0800 Subject: [PATCH] Refined gradle config --- .history/android/build_20250615000203.gradle | 67 +++++++ .history/android/build_20250615000205.gradle | 67 +++++++ .../DumonGeolocation_20250614224800.kt | 183 ++++++++++++++++++ .../DumonGeolocation_20250614225329.kt | 183 ++++++++++++++++++ .../utils/PermissionUtils_20250614224627.kt | 0 .../utils/PermissionUtils_20250614224658.kt | 23 +++ .history/src/definitions_20250614165106.ts | 75 +++++++ .history/src/definitions_20250614225309.ts | 81 ++++++++ .history/src/definitions_20250614225810.ts | 81 ++++++++ .history/src/web_20250614165348.ts | 27 +++ android/build.gradle | 4 +- .../plugin/geolocation/DumonGeolocation.kt | 19 ++ .../geolocation/utils/PermissionUtils.kt | 23 +++ src/definitions.ts | 92 +++++---- src/web.ts | 21 +- 15 files changed, 890 insertions(+), 56 deletions(-) create mode 100644 .history/android/build_20250615000203.gradle create mode 100644 .history/android/build_20250615000205.gradle create mode 100644 .history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614224800.kt create mode 100644 .history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614225329.kt create mode 100644 .history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224627.kt create mode 100644 .history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224658.kt create mode 100644 .history/src/definitions_20250614165106.ts create mode 100644 .history/src/definitions_20250614225309.ts create mode 100644 .history/src/definitions_20250614225810.ts create mode 100644 .history/src/web_20250614165348.ts create mode 100644 android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils.kt diff --git a/.history/android/build_20250615000203.gradle b/.history/android/build_20250615000203.gradle new file mode 100644 index 0000000..ce5bd0b --- /dev/null +++ b/.history/android/build_20250615000203.gradle @@ -0,0 +1,67 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1' +} + +buildscript { + ext { + kotlin_version = '1.9.24' + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.7.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'com.android.library' +apply plugin: 'org.jetbrains.kotlin.android' + +android { + namespace "com.dumon.plugin.geolocation" + compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } +} + +repositories { + google() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':capacitor-android') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation 'androidx.core:core-ktx:1.16.0' + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/.history/android/build_20250615000205.gradle b/.history/android/build_20250615000205.gradle new file mode 100644 index 0000000..ce5bd0b --- /dev/null +++ b/.history/android/build_20250615000205.gradle @@ -0,0 +1,67 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' + androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1' +} + +buildscript { + ext { + kotlin_version = '1.9.24' + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.7.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: 'com.android.library' +apply plugin: 'org.jetbrains.kotlin.android' + +android { + namespace "com.dumon.plugin.geolocation" + compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34 + defaultConfig { + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } +} + +repositories { + google() + mavenCentral() +} + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':capacitor-android') + implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" + implementation 'androidx.core:core-ktx:1.16.0' + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" +} diff --git a/.history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614224800.kt b/.history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614224800.kt new file mode 100644 index 0000000..e994a60 --- /dev/null +++ b/.history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614224800.kt @@ -0,0 +1,183 @@ +package com.dumon.plugin.geolocation + +import android.Manifest +import com.getcapacitor.* +import com.getcapacitor.annotation.CapacitorPlugin +import com.getcapacitor.annotation.Permission +import com.dumon.plugin.geolocation.gps.GpsStatusManager +import com.dumon.plugin.geolocation.gps.SatelliteStatus +import com.dumon.plugin.geolocation.imu.ImuData +import com.dumon.plugin.geolocation.imu.ImuSensorManager +import com.dumon.plugin.geolocation.wifi.WifiPositioningManager +import com.dumon.plugin.geolocation.wifi.WifiScanResult +import com.dumon.plugin.geolocation.fusion.SensorFusionManager +import com.dumon.plugin.geolocation.utils.PermissionUtils +import org.json.JSONArray +import org.json.JSONObject + +@CapacitorPlugin( + name = "DumonGeolocation", + permissions = [ + Permission(strings = [ + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_WIFI_STATE, + Manifest.permission.CHANGE_WIFI_STATE, + Manifest.permission.NEARBY_WIFI_DEVICES + ]) + ] +) +class DumonGeolocation : Plugin() { + + private var gpsManager: GpsStatusManager? = null + private var imuManager: ImuSensorManager? = null + private var wifiManager: WifiPositioningManager? = null + private var fusionManager: SensorFusionManager? = null + + private var latestLatitude = 0.0 + private var latestLongitude = 0.0 + private var latestAccuracy = 999.0 + private var latestSource = "GNSS" + private var latestTimestamp: Long = 0L + + private var latestImu: ImuData? = null + private var satelliteStatus: SatelliteStatus? = null + private var wifiScanResult: WifiScanResult? = null + + private var isMockedLocation = false + private var lastEmitTimestamp: Long = 0L + private val emitIntervalMs: Long = 500L + + override fun load() { + gpsManager = GpsStatusManager( + context, + onSatelliteStatusUpdate = { satelliteStatus = it }, + onLocationUpdate = { location, isMocked -> + latestLatitude = location.latitude + latestLongitude = location.longitude + latestAccuracy = location.accuracy.toDouble() + latestSource = if (isMocked) "MOCK" else "GNSS" + isMockedLocation = isMocked + latestTimestamp = location.time + fusionManager?.updateGpsPosition(latestLatitude, latestLongitude) + emitPositionUpdate() + } + ) + + imuManager = ImuSensorManager( + context, + onImuUpdate = { + latestImu = it + emitPositionUpdate() + } + ) + + wifiManager = WifiPositioningManager( + context, + onWifiPositioningUpdate = { + wifiScanResult = it + emitPositionUpdate() + } + ) + + fusionManager = SensorFusionManager { lat, lon -> + latestLatitude = lat + latestLongitude = lon + latestAccuracy = 3.0 + latestSource = "FUSED" + latestTimestamp = System.currentTimeMillis() + emitPositionUpdate() + } + } + + @PluginMethod + fun startPositioning(call: PluginCall) { + if (!PermissionUtils.hasLocationAndWifiPermissions(context)) { + call.reject("Required permissions not granted") + return + } + + gpsManager?.start() + imuManager?.start() + wifiManager?.startPeriodicScan(3000L) + call.resolve() + } + + @PluginMethod + fun stopPositioning(call: PluginCall) { + gpsManager?.stop() + imuManager?.stop() + wifiManager?.stopPeriodicScan() + call.resolve() + } + + @PluginMethod + fun getLatestPosition(call: PluginCall) { + call.resolve(buildPositionData()) + } + + private fun emitPositionUpdate() { + val now = System.currentTimeMillis() + if (now - lastEmitTimestamp < emitIntervalMs) return + lastEmitTimestamp = now + notifyListeners("onPositionUpdate", buildPositionData()) + } + + private fun buildPositionData(): JSObject { + val obj = JSObject() + obj.put("source", latestSource) + obj.put("timestamp", if (latestTimestamp > 0) latestTimestamp else System.currentTimeMillis()) + obj.put("latitude", latestLatitude) + obj.put("longitude", latestLongitude) + obj.put("accuracy", latestAccuracy) + obj.put("isMocked", isMockedLocation) + + latestImu?.let { + obj.put("speed", it.speed) + obj.put("acceleration", it.acceleration) + obj.put("directionRad", it.directionRad) + } + + // === Full Detail (commented out for future use) === + /* + satelliteStatus?.let { + val gnss = JSObject() + gnss.put("satellitesInView", it.satellitesInView) + gnss.put("usedInFix", it.usedInFix) + val constellations = JSObject() + it.constellationCounts.forEach { (k, v) -> constellations.put(k, v) } + gnss.put("constellationCounts", constellations) + obj.put("gnssData", gnss) + } + + latestImu?.let { + val imu = JSObject() + imu.put("accelX", it.accelX) + imu.put("accelY", it.accelY) + imu.put("accelZ", it.accelZ) + imu.put("gyroX", it.gyroX) + imu.put("gyroY", it.gyroY) + imu.put("gyroZ", it.gyroZ) + imu.put("speed", it.speed) + imu.put("acceleration", it.acceleration) + imu.put("directionRad", it.directionRad) + obj.put("imuData", imu) + } + + wifiScanResult?.let { + val wifi = JSArray() + it.aps.forEach { ap -> + val a = JSObject() + a.put("ssid", ap.ssid) + a.put("bssid", ap.bssid) + a.put("rssi", ap.rssi) + ap.distance?.let { d -> a.put("distance", d) } + wifi.put(a) + } + obj.put("wifiData", wifi) + } + */ + + return obj + } +} \ No newline at end of file diff --git a/.history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614225329.kt b/.history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614225329.kt new file mode 100644 index 0000000..e994a60 --- /dev/null +++ b/.history/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation_20250614225329.kt @@ -0,0 +1,183 @@ +package com.dumon.plugin.geolocation + +import android.Manifest +import com.getcapacitor.* +import com.getcapacitor.annotation.CapacitorPlugin +import com.getcapacitor.annotation.Permission +import com.dumon.plugin.geolocation.gps.GpsStatusManager +import com.dumon.plugin.geolocation.gps.SatelliteStatus +import com.dumon.plugin.geolocation.imu.ImuData +import com.dumon.plugin.geolocation.imu.ImuSensorManager +import com.dumon.plugin.geolocation.wifi.WifiPositioningManager +import com.dumon.plugin.geolocation.wifi.WifiScanResult +import com.dumon.plugin.geolocation.fusion.SensorFusionManager +import com.dumon.plugin.geolocation.utils.PermissionUtils +import org.json.JSONArray +import org.json.JSONObject + +@CapacitorPlugin( + name = "DumonGeolocation", + permissions = [ + Permission(strings = [ + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_WIFI_STATE, + Manifest.permission.CHANGE_WIFI_STATE, + Manifest.permission.NEARBY_WIFI_DEVICES + ]) + ] +) +class DumonGeolocation : Plugin() { + + private var gpsManager: GpsStatusManager? = null + private var imuManager: ImuSensorManager? = null + private var wifiManager: WifiPositioningManager? = null + private var fusionManager: SensorFusionManager? = null + + private var latestLatitude = 0.0 + private var latestLongitude = 0.0 + private var latestAccuracy = 999.0 + private var latestSource = "GNSS" + private var latestTimestamp: Long = 0L + + private var latestImu: ImuData? = null + private var satelliteStatus: SatelliteStatus? = null + private var wifiScanResult: WifiScanResult? = null + + private var isMockedLocation = false + private var lastEmitTimestamp: Long = 0L + private val emitIntervalMs: Long = 500L + + override fun load() { + gpsManager = GpsStatusManager( + context, + onSatelliteStatusUpdate = { satelliteStatus = it }, + onLocationUpdate = { location, isMocked -> + latestLatitude = location.latitude + latestLongitude = location.longitude + latestAccuracy = location.accuracy.toDouble() + latestSource = if (isMocked) "MOCK" else "GNSS" + isMockedLocation = isMocked + latestTimestamp = location.time + fusionManager?.updateGpsPosition(latestLatitude, latestLongitude) + emitPositionUpdate() + } + ) + + imuManager = ImuSensorManager( + context, + onImuUpdate = { + latestImu = it + emitPositionUpdate() + } + ) + + wifiManager = WifiPositioningManager( + context, + onWifiPositioningUpdate = { + wifiScanResult = it + emitPositionUpdate() + } + ) + + fusionManager = SensorFusionManager { lat, lon -> + latestLatitude = lat + latestLongitude = lon + latestAccuracy = 3.0 + latestSource = "FUSED" + latestTimestamp = System.currentTimeMillis() + emitPositionUpdate() + } + } + + @PluginMethod + fun startPositioning(call: PluginCall) { + if (!PermissionUtils.hasLocationAndWifiPermissions(context)) { + call.reject("Required permissions not granted") + return + } + + gpsManager?.start() + imuManager?.start() + wifiManager?.startPeriodicScan(3000L) + call.resolve() + } + + @PluginMethod + fun stopPositioning(call: PluginCall) { + gpsManager?.stop() + imuManager?.stop() + wifiManager?.stopPeriodicScan() + call.resolve() + } + + @PluginMethod + fun getLatestPosition(call: PluginCall) { + call.resolve(buildPositionData()) + } + + private fun emitPositionUpdate() { + val now = System.currentTimeMillis() + if (now - lastEmitTimestamp < emitIntervalMs) return + lastEmitTimestamp = now + notifyListeners("onPositionUpdate", buildPositionData()) + } + + private fun buildPositionData(): JSObject { + val obj = JSObject() + obj.put("source", latestSource) + obj.put("timestamp", if (latestTimestamp > 0) latestTimestamp else System.currentTimeMillis()) + obj.put("latitude", latestLatitude) + obj.put("longitude", latestLongitude) + obj.put("accuracy", latestAccuracy) + obj.put("isMocked", isMockedLocation) + + latestImu?.let { + obj.put("speed", it.speed) + obj.put("acceleration", it.acceleration) + obj.put("directionRad", it.directionRad) + } + + // === Full Detail (commented out for future use) === + /* + satelliteStatus?.let { + val gnss = JSObject() + gnss.put("satellitesInView", it.satellitesInView) + gnss.put("usedInFix", it.usedInFix) + val constellations = JSObject() + it.constellationCounts.forEach { (k, v) -> constellations.put(k, v) } + gnss.put("constellationCounts", constellations) + obj.put("gnssData", gnss) + } + + latestImu?.let { + val imu = JSObject() + imu.put("accelX", it.accelX) + imu.put("accelY", it.accelY) + imu.put("accelZ", it.accelZ) + imu.put("gyroX", it.gyroX) + imu.put("gyroY", it.gyroY) + imu.put("gyroZ", it.gyroZ) + imu.put("speed", it.speed) + imu.put("acceleration", it.acceleration) + imu.put("directionRad", it.directionRad) + obj.put("imuData", imu) + } + + wifiScanResult?.let { + val wifi = JSArray() + it.aps.forEach { ap -> + val a = JSObject() + a.put("ssid", ap.ssid) + a.put("bssid", ap.bssid) + a.put("rssi", ap.rssi) + ap.distance?.let { d -> a.put("distance", d) } + wifi.put(a) + } + obj.put("wifiData", wifi) + } + */ + + return obj + } +} \ No newline at end of file diff --git a/.history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224627.kt b/.history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224627.kt new file mode 100644 index 0000000..e69de29 diff --git a/.history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224658.kt b/.history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224658.kt new file mode 100644 index 0000000..b4a3e24 --- /dev/null +++ b/.history/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils_20250614224658.kt @@ -0,0 +1,23 @@ +package com.dumon.plugin.geolocation.utils + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.core.app.ActivityCompat + +object PermissionUtils { + fun hasLocationAndWifiPermissions(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 && + nearbyWifi == PackageManager.PERMISSION_GRANTED + } +} \ No newline at end of file diff --git a/.history/src/definitions_20250614165106.ts b/.history/src/definitions_20250614165106.ts new file mode 100644 index 0000000..cece80a --- /dev/null +++ b/.history/src/definitions_20250614165106.ts @@ -0,0 +1,75 @@ +import type { PluginListenerHandle } from '@capacitor/core'; + +// export interface SatelliteStatus { +// satellitesInView: number; +// usedInFix: number; +// constellationCounts: { [key: string]: number }; +// } + +// export interface WifiAp { +// ssid: string; +// bssid: string; +// rssi: number; +// distance?: number; +// } + +// export interface WifiScanResult { +// apCount: number; +// aps: WifiAp[]; +// } + +// export interface ImuData { +// accelX: number; +// accelY: number; +// accelZ: number; +// gyroX: number; +// gyroY: number; +// gyroZ: number; +// speed?: number; +// acceleration?: number; +// directionRad?: number; +// } + +// export interface GpsData { +// latitude: number; +// longitude: number; +// accuracy: number; +// satellitesInView?: number; +// usedInFix?: number; +// constellationCounts?: { [key: string]: number }; +// } + +// export interface PositioningData { +// source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; +// timestamp: number; +// latitude: number; +// longitude: number; +// accuracy: number; + +// gnssData?: SatelliteStatus; +// wifiData?: WifiAp[]; +// imuData?: ImuData; +// } + +export interface PositioningData { + source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; + timestamp: number; + latitude: number; + longitude: number; + accuracy: number; + speed: number; + acceleration: number; + directionRad: number; + isMocked: boolean; +} + +export interface DumonGeolocationPlugin { + startPositioning(): Promise; + stopPositioning(): Promise; + getLatestPosition(): Promise; + + addListener( + eventName: 'onPositionUpdate', + listenerFunc: (data: PositioningData) => void + ): PluginListenerHandle; +} \ No newline at end of file diff --git a/.history/src/definitions_20250614225309.ts b/.history/src/definitions_20250614225309.ts new file mode 100644 index 0000000..bf35b8a --- /dev/null +++ b/.history/src/definitions_20250614225309.ts @@ -0,0 +1,81 @@ +import type { PluginListenerHandle } from '@capacitor/core'; + +// export interface SatelliteStatus { +// satellitesInView: number; +// usedInFix: number; +// constellationCounts: { [key: string]: number }; +// } + +// export interface WifiAp { +// ssid: string; +// bssid: string; +// rssi: number; +// distance?: number; +// } + +// export interface WifiScanResult { +// apCount: number; +// aps: WifiAp[]; +// } + +// export interface ImuData { +// accelX: number; +// accelY: number; +// accelZ: number; +// gyroX: number; +// gyroY: number; +// gyroZ: number; +// speed?: number; +// acceleration?: number; +// directionRad?: number; +// } + +// export interface GpsData { +// latitude: number; +// longitude: number; +// accuracy: number; +// satellitesInView?: number; +// usedInFix?: number; +// constellationCounts?: { [key: string]: number }; +// } + +// export interface PositioningData { +// source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; +// timestamp: number; +// latitude: number; +// longitude: number; +// accuracy: number; + +// gnssData?: SatelliteStatus; +// wifiData?: WifiAp[]; +// imuData?: ImuData; +// } + +export interface PositioningData { + source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; + timestamp: number; + latitude: number; + longitude: number; + accuracy: number; + speed: number; + acceleration: number; + directionRad: number; + isMocked: boolean; +} + +export interface PermissionStatus { + location: 'granted' | 'denied' | 'prompt'; + wifi: 'granted' | 'denied' | 'prompt'; +} + +export interface DumonGeolocationPlugin { + startPositioning(): Promise; + stopPositioning(): Promise; + getLatestPosition(): Promise; + checkPermissions(): Promise; + + addListener( + eventName: 'onPositionUpdate', + listenerFunc: (data: PositioningData) => void + ): PluginListenerHandle; +} \ No newline at end of file diff --git a/.history/src/definitions_20250614225810.ts b/.history/src/definitions_20250614225810.ts new file mode 100644 index 0000000..f8ee400 --- /dev/null +++ b/.history/src/definitions_20250614225810.ts @@ -0,0 +1,81 @@ +import type { PluginListenerHandle } from '@capacitor/core'; + +// export interface SatelliteStatus { +// satellitesInView: number; +// usedInFix: number; +// constellationCounts: { [key: string]: number }; +// } + +// export interface WifiAp { +// ssid: string; +// bssid: string; +// rssi: number; +// distance?: number; +// } + +// export interface WifiScanResult { +// apCount: number; +// aps: WifiAp[]; +// } + +// export interface ImuData { +// accelX: number; +// accelY: number; +// accelZ: number; +// gyroX: number; +// gyroY: number; +// gyroZ: number; +// speed?: number; +// acceleration?: number; +// directionRad?: number; +// } + +// export interface GpsData { +// latitude: number; +// longitude: number; +// accuracy: number; +// satellitesInView?: number; +// usedInFix?: number; +// constellationCounts?: { [key: string]: number }; +// } + +// export interface PositioningData { +// source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; +// timestamp: number; +// latitude: number; +// longitude: number; +// accuracy: number; + +// gnssData?: SatelliteStatus; +// wifiData?: WifiAp[]; +// imuData?: ImuData; +// } + +export interface PositioningData { + source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; + timestamp: number; + latitude: number; + longitude: number; + accuracy: number; + speed: number; + acceleration: number; + directionRad: number; + isMocked: boolean; +} + +export interface PermissionStatus { + location: 'granted' | 'denied' | 'prompt'; + wifi: 'granted' | 'denied' | 'prompt'; +} + +export interface DumonGeolocationPlugin { + startPositioning(): Promise; + stopPositioning(): Promise; + getLatestPosition(): Promise; + checkAndRequestPermissions(): Promise; + + addListener( + eventName: 'onPositionUpdate', + listenerFunc: (data: PositioningData) => void + ): PluginListenerHandle; +} \ No newline at end of file diff --git a/.history/src/web_20250614165348.ts b/.history/src/web_20250614165348.ts new file mode 100644 index 0000000..b84a947 --- /dev/null +++ b/.history/src/web_20250614165348.ts @@ -0,0 +1,27 @@ +import { WebPlugin } from '@capacitor/core'; +import type { PositioningData } from './definitions'; + +export class DumonGeolocationWeb extends WebPlugin { + async startPositioning(): Promise { + console.log('DumonGeolocationWeb: startPositioning() called (no-op)'); + } + + async stopPositioning(): Promise { + console.log('DumonGeolocationWeb: stopPositioning() called (no-op)'); + } + + async getLatestPosition(): Promise { + 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, + }; + } +} \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 9940916..ce5bd0b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -24,10 +24,10 @@ apply plugin: 'org.jetbrains.kotlin.android' android { namespace "com.dumon.plugin.geolocation" - compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35 + compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34 defaultConfig { minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24 - targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation.kt b/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation.kt index dc6d3ab..d43947f 100644 --- a/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation.kt +++ b/android/src/main/java/com/dumon/plugin/geolocation/DumonGeolocation.kt @@ -11,6 +11,7 @@ import com.dumon.plugin.geolocation.imu.ImuSensorManager import com.dumon.plugin.geolocation.wifi.WifiPositioningManager import com.dumon.plugin.geolocation.wifi.WifiScanResult import com.dumon.plugin.geolocation.fusion.SensorFusionManager +import com.dumon.plugin.geolocation.utils.PermissionUtils import org.json.JSONArray import org.json.JSONObject @@ -91,6 +92,11 @@ class DumonGeolocation : Plugin() { @PluginMethod fun startPositioning(call: PluginCall) { + if (!PermissionUtils.hasLocationAndWifiPermissions(context)) { + call.reject("Required permissions not granted") + return + } + gpsManager?.start() imuManager?.start() wifiManager?.startPeriodicScan(3000L) @@ -110,6 +116,19 @@ class DumonGeolocation : Plugin() { call.resolve(buildPositionData()) } + @PluginMethod + fun checkAndRequestPermissions(call: PluginCall) { + if (PermissionUtils.hasLocationAndWifiPermissions(context)) { + val result = JSObject().apply { + put("location", "granted") + put("wifi", "granted") + } + call.resolve(result) + } else { + requestAllPermissions(call, "checkAndRequestPermissions") + } + } + private fun emitPositionUpdate() { val now = System.currentTimeMillis() if (now - lastEmitTimestamp < emitIntervalMs) return diff --git a/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils.kt b/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils.kt new file mode 100644 index 0000000..b4a3e24 --- /dev/null +++ b/android/src/main/java/com/dumon/plugin/geolocation/utils/PermissionUtils.kt @@ -0,0 +1,23 @@ +package com.dumon.plugin.geolocation.utils + +import android.Manifest +import android.content.Context +import android.content.pm.PackageManager +import android.os.Build +import androidx.core.app.ActivityCompat + +object PermissionUtils { + fun hasLocationAndWifiPermissions(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 && + nearbyWifi == PackageManager.PERMISSION_GRANTED + } +} \ No newline at end of file diff --git a/src/definitions.ts b/src/definitions.ts index 1c0c36c..f8ee400 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -1,43 +1,55 @@ import type { PluginListenerHandle } from '@capacitor/core'; -export interface SatelliteStatus { - satellitesInView: number; - usedInFix: number; - constellationCounts: { [key: string]: number }; -} +// export interface SatelliteStatus { +// satellitesInView: number; +// usedInFix: number; +// constellationCounts: { [key: string]: number }; +// } -export interface WifiAp { - ssid: string; - bssid: string; - rssi: number; - distance?: number; -} +// export interface WifiAp { +// ssid: string; +// bssid: string; +// rssi: number; +// distance?: number; +// } -export interface WifiScanResult { - apCount: number; - aps: WifiAp[]; -} +// export interface WifiScanResult { +// apCount: number; +// aps: WifiAp[]; +// } -export interface ImuData { - accelX: number; - accelY: number; - accelZ: number; - gyroX: number; - gyroY: number; - gyroZ: number; - speed?: number; - acceleration?: number; - directionRad?: number; -} +// export interface ImuData { +// accelX: number; +// accelY: number; +// accelZ: number; +// gyroX: number; +// gyroY: number; +// gyroZ: number; +// speed?: number; +// acceleration?: number; +// directionRad?: number; +// } -export interface GpsData { - latitude: number; - longitude: number; - accuracy: number; - satellitesInView?: number; - usedInFix?: number; - constellationCounts?: { [key: string]: number }; -} +// export interface GpsData { +// latitude: number; +// longitude: number; +// accuracy: number; +// satellitesInView?: number; +// usedInFix?: number; +// constellationCounts?: { [key: string]: number }; +// } + +// export interface PositioningData { +// source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; +// timestamp: number; +// latitude: number; +// longitude: number; +// accuracy: number; + +// gnssData?: SatelliteStatus; +// wifiData?: WifiAp[]; +// imuData?: ImuData; +// } export interface PositioningData { source: 'GNSS' | 'WIFI' | 'FUSED' | 'MOCK'; @@ -45,16 +57,22 @@ export interface PositioningData { latitude: number; longitude: number; accuracy: number; + speed: number; + acceleration: number; + directionRad: number; + isMocked: boolean; +} - gnssData?: SatelliteStatus; - wifiData?: WifiAp[]; - imuData?: ImuData; +export interface PermissionStatus { + location: 'granted' | 'denied' | 'prompt'; + wifi: 'granted' | 'denied' | 'prompt'; } export interface DumonGeolocationPlugin { startPositioning(): Promise; stopPositioning(): Promise; getLatestPosition(): Promise; + checkAndRequestPermissions(): Promise; addListener( eventName: 'onPositionUpdate', diff --git a/src/web.ts b/src/web.ts index a5c2df4..b84a947 100644 --- a/src/web.ts +++ b/src/web.ts @@ -18,23 +18,10 @@ export class DumonGeolocationWeb extends WebPlugin { latitude: 0, longitude: 0, accuracy: 999, - gnssData: { - satellitesInView: 0, - usedInFix: 0, - constellationCounts: {} - }, - wifiData: [], - imuData: { - accelX: 0, - accelY: 0, - accelZ: 0, - gyroX: 0, - gyroY: 0, - gyroZ: 0, - speed: 0, - acceleration: 0, - directionRad: 0 - } + speed: 0, + acceleration: 0, + directionRad: 0, + isMocked: false, }; } } \ No newline at end of file