ReviewOS

also looking at this

craft-native/craft

feat(android): the motion pair, and org.json's numbers — ratchet 54 → 52

#187
Merged glennmichael123 wants to merge feat/android-motion into main
7 files +577 -3
packages/android/templates/CraftNative.kt.templatemodified+75-0
Changes to packages/android/templates/CraftNative.kt.template
@@ -1,6 +1,10 @@
11package com.craft.runtime
22
33import android.app.Activity
4import android.hardware.SensorManager
5import android.hardware.SensorEventListener
6import android.hardware.SensorEvent
7import android.hardware.Sensor
48import androidx.core.app.ActivityCompat
59import android.os.Build
610import android.bluetooth.le.ScanResult
@@ -162,6 +166,9 @@ object CraftNative {
162166 private external fun nativeBluetoothDevice(address: String, name: String?, rssi: Int)
163167 private external fun nativeStartBluetoothScan(activity: Activity): Boolean
164168 private external fun nativeStopBluetoothScan(activity: Activity): Boolean
169 private external fun nativeMotionSample(isAccelerometer: Boolean, x: Float, y: Float, z: Float)
170 private external fun nativeStartMotionUpdates(activity: Activity, intervalMs: Int): Boolean
171 private external fun nativeStopMotionUpdates(activity: Activity): Boolean
165172
166173 /**
167174 * `getDeviceInfo`, or null to use the Kotlin implementation.
@@ -1017,4 +1024,72 @@ object CraftNative {
10171024 false
10181025 }
10191026 }
1027
1028 // ==================== Motion sensors ====================
1029 //
1030 // The fourth listener shim. `SensorEventListener` is a Java interface, so
1031 // the object is here — but only the object: which sensor a sample came
1032 // from is passed across as a boolean and everything else, including the
1033 // last-value bookkeeping and the delay the interval maps to, is Zig's.
1034 //
1035 // `registerListener` without a Handler delivers on the main looper, so
1036 // every sample arrives on one thread and the state on the other side
1037 // needs no lock.
1038
1039 private var sensorManager: SensorManager? = null
1040 private var motionListener: SensorEventListener? = null
1041
1042 @JvmStatic
1043 fun startMotionWatch(activity: Activity, delay: Int) {
1044 val manager = activity.getSystemService(Context.SENSOR_SERVICE) as SensorManager
1045 sensorManager = manager
1046
1047 val accelerometer = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
1048 val gyroscope = manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
1049
1050 val listener = object : SensorEventListener {
1051 override fun onSensorChanged(event: SensorEvent) {
1052 try {
1053 nativeMotionSample(
1054 event.sensor.type == Sensor.TYPE_ACCELEROMETER,
1055 event.values[0],
1056 event.values[1],
1057 event.values[2]
1058 )
1059 } catch (e: UnsatisfiedLinkError) {
1060 // The library went away. Nothing is waiting on this.
1061 }
1062 }
1063
1064 override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
1065 }
1066
1067 accelerometer?.let { manager.registerListener(listener, it, delay) }
1068 gyroscope?.let { manager.registerListener(listener, it, delay) }
1069 motionListener = listener
1070 }
1071
1072 @JvmStatic
1073 fun stopMotionWatch(activity: Activity) {
1074 motionListener?.let { sensorManager?.unregisterListener(it) }
1075 motionListener = null
1076 }
1077
1078 fun startMotionUpdates(activity: Activity, intervalMs: Int): Boolean {
1079 if (!isAvailable) return false
1080 return try {
1081 nativeStartMotionUpdates(activity, intervalMs)
1082 } catch (e: UnsatisfiedLinkError) {
1083 false
1084 }
1085 }
1086
1087 fun stopMotionUpdates(activity: Activity): Boolean {
1088 if (!isAvailable) return false
1089 return try {
1090 nativeStopMotionUpdates(activity)
1091 } catch (e: UnsatisfiedLinkError) {
1092 false
1093 }
1094 }
10201095}