ReviewOS

also looking at this

craft-native/craft

feat(android): getCurrentPosition in Zig — ratchet 52 → 51

#188
Merged glennmichael123 wants to merge feat/android-position into main
6 files +466 -3
packages/android/templates/CraftNative.kt.templatemodified+124-0
Changes to packages/android/templates/CraftNative.kt.template
@@ -1,6 +1,14 @@
11package com.craft.runtime
22
33import android.app.Activity
4import com.google.android.gms.location.Priority
5import com.google.android.gms.location.LocationServices
6import com.google.android.gms.location.LocationResult
7import com.google.android.gms.location.LocationRequest
8import com.google.android.gms.location.LocationCallback
9import com.google.android.gms.location.FusedLocationProviderClient
10import android.location.Location
11import android.annotation.SuppressLint
412import android.hardware.SensorManager
513import android.hardware.SensorEventListener
614import android.hardware.SensorEvent
@@ -169,6 +177,17 @@ object CraftNative {
169177 private external fun nativeMotionSample(isAccelerometer: Boolean, x: Float, y: Float, z: Float)
170178 private external fun nativeStartMotionUpdates(activity: Activity, intervalMs: Int): Boolean
171179 private external fun nativeStopMotionUpdates(activity: Activity): Boolean
180 private external fun nativeLocationResult(
181 latitude: Double,
182 longitude: Double,
183 accuracy: Double,
184 altitude: Double,
185 speed: Double,
186 bearing: Double,
187 time: Long
188 )
189 private external fun nativeLocationFailed(message: String?)
190 private external fun nativeGetCurrentPosition(activity: Activity): Boolean
172191
173192 /**
174193 * `getDeviceInfo`, or null to use the Kotlin implementation.
@@ -1092,4 +1111,109 @@ object CraftNative {
10921111 false
10931112 }
10941113 }
1114
1115 // ==================== Current position ====================
1116 //
1117 // The fifth listener shim, and the first with two Java interfaces in one
1118 // flow: `OnSuccessListener` and `OnFailureListener` on the Play Services
1119 // task, plus a `LocationCallback` for the fresh-location fallback.
1120 //
1121 // Every value crosses as a Double, including the three the framework types
1122 // as Float. That is not a convenience: `CraftBridge` writes them with
1123 // `put(name, value)`, and the overload Kotlin picks there is
1124 // `put(String, double)` — primitive widening beats boxing — so they print
1125 // as doubles. Passing them as Float and boxing them on the other side
1126 // would print `0.1` where the shim prints `0.10000000149011612`.
1127
1128 @JvmStatic
1129 fun requestLocationPermissions(activity: Activity) {
1130 ActivityCompat.requestPermissions(
1131 activity,
1132 arrayOf(
1133 android.Manifest.permission.ACCESS_FINE_LOCATION,
1134 android.Manifest.permission.ACCESS_COARSE_LOCATION
1135 ),
1136 REQUEST_LOCATION
1137 )
1138 }
1139
1140 /** `CraftBridge.REQUEST_LOCATION`, which this has to match. */
1141 private const val REQUEST_LOCATION = 1003
1142
1143 @JvmStatic
1144 @SuppressLint("MissingPermission")
1145 fun requestCurrentPosition(activity: Activity) {
1146 val client = LocationServices.getFusedLocationProviderClient(activity)
1147 client.lastLocation
1148 .addOnSuccessListener { location: Location? ->
1149 if (location != null) {
1150 deliverLocation(location)
1151 } else {
1152 requestFreshPosition(activity, client)
1153 }
1154 }
1155 .addOnFailureListener { e -> failLocation(e.message) }
1156 }
1157
1158 /**
1159 * The fallback when there is no cached fix.
1160 *
1161 * One update, then the callback removes itself — as `CraftBridge`'s does.
1162 * If it never fires, nothing settles the page's promise, here or there.
1163 */
1164 @SuppressLint("MissingPermission")
1165 private fun requestFreshPosition(
1166 activity: Activity,
1167 client: FusedLocationProviderClient
1168 ) {
1169 val request = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 1000)
1170 .setWaitForAccurateLocation(false)
1171 .setMinUpdateIntervalMillis(500)
1172 .setMaxUpdateDelayMillis(1000)
1173 .setMaxUpdates(1)
1174 .build()
1175
1176 client.requestLocationUpdates(
1177 request,
1178 object : LocationCallback() {
1179 override fun onLocationResult(result: LocationResult) {
1180 client.removeLocationUpdates(this)
1181 result.lastLocation?.let { deliverLocation(it) }
1182 }
1183 },
1184 activity.mainLooper
1185 )
1186 }
1187
1188 private fun deliverLocation(location: Location) {
1189 try {
1190 nativeLocationResult(
1191 location.latitude,
1192 location.longitude,
1193 location.accuracy.toDouble(),
1194 location.altitude,
1195 location.speed.toDouble(),
1196 location.bearing.toDouble(),
1197 location.time
1198 )
1199 } catch (e: UnsatisfiedLinkError) {
1200 // The library went away mid-flight. Nothing to answer to.
1201 }
1202 }
1203
1204 private fun failLocation(message: String?) {
1205 try {
1206 nativeLocationFailed(message)
1207 } catch (e: UnsatisfiedLinkError) {
1208 }
1209 }
1210
1211 fun getCurrentPosition(activity: Activity): Boolean {
1212 if (!isAvailable) return false
1213 return try {
1214 nativeGetCurrentPosition(activity)
1215 } catch (e: UnsatisfiedLinkError) {
1216 false
1217 }
1218 }
10951219}