Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8ee059d
feat(compute): per-category calibration policy for the live 100 Hz pe…
Oct 26, 2026
347c48a
fix(compute): everyday is a low positive scale against the PHONE, not…
Oct 26, 2026
40a7801
feat(compute,data): persist the live-pedometer calibration; align its…
Oct 26, 2026
cd52c7d
feat(state): bank live runs through the wearer's calibration
Oct 26, 2026
26a4155
feat(compute): calibration session — the wearer counts, the band does…
Oct 26, 2026
3348aa3
refactor(compute): session inputs are what a screen can observe
Oct 26, 2026
da357c4
feat(ui): step calibration screen, settings row, and the phone refere…
Oct 26, 2026
03f416d
fix(ui): settings row and screen imports
Oct 26, 2026
922df66
fix(steps): address review findings, and four the review did not find
Oct 26, 2026
0388d2b
chore(compute): make the three clamp result types explicit
Oct 26, 2026
906f016
fix(steps): the two review findings that were only half done
Oct 26, 2026
e51cd1a
fix(steps): CodeRabbit's real findings — a NULL turned back into a re…
Oct 26, 2026
8555b50
fix(steps): close the remaining CodeRabbit findings
Oct 26, 2026
63a2dbf
make the calibration screen compile and pass the ui checks
abdulsaheel Oct 28, 2026
04750c8
save calibration atomically and refit it after a restore
abdulsaheel Oct 28, 2026
ecc45aa
put the permission docs back on requestPermission
abdulsaheel Oct 28, 2026
5065865
take kAlgoVersion 118 for step calibration
abdulsaheel Oct 28, 2026
ae91fcd
ask what the wearer counted, and flush android's step batch around a …
abdulsaheel Oct 31, 2026
9cd868c
Merge branch 'main' into feat/live-step-calibration
abdulsaheel Oct 31, 2026
ffe8e3b
wait for the flushed step batch in the pedometer, and pin the early-s…
abdulsaheel Oct 31, 2026
93459e0
drop the cached calibration after an import even if the refit fails
abdulsaheel Oct 31, 2026
0488d8a
refuse a gait routine whose cadence is outside the walking range
abdulsaheel Oct 31, 2026
65f953e
take the household reference from the step sensor's own total on android
abdulsaheel Oct 31, 2026
25cda12
inflect the calibration counts in russian and keep the gait result ne…
abdulsaheel Oct 31, 2026
6de1d1a
end a walk routine at the done tap, not when the count is answered
abdulsaheel Oct 31, 2026
56c3256
refuse a household routine on android without two flushed totals
abdulsaheel Oct 31, 2026
58f3a65
make the russian band counter label unambiguous
abdulsaheel Oct 31, 2026
a0fcd3e
wait for a step-sensor flush to complete instead of a fixed pause
abdulsaheel Oct 31, 2026
024ceaf
start a household routine only once the phone's starting total is in
abdulsaheel Oct 31, 2026
829daa3
ask for phone step access before a household routine every time
abdulsaheel Oct 31, 2026
361f7f3
stop the band count where the household phone reference stops
abdulsaheel Oct 31, 2026
587a60b
report a stored calibration as saved even if the reload after it fails
abdulsaheel Oct 31, 2026
66868b8
drop the cached calibration even when an import fails part way
abdulsaheel Oct 31, 2026
60a7251
show the saved category from the save itself when the reload fails
abdulsaheel Oct 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorEventListener2
import android.hardware.SensorManager
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
Expand Down Expand Up @@ -52,7 +54,7 @@ import kotlin.math.roundToInt
* adding a second service: Android 9+ withholds sensor events from background
* processes, and a foreground service of any type lifts that.
*/
object PhoneStepCounter : SensorEventListener {
object PhoneStepCounter : SensorEventListener2 {
private const val CHANNEL = "openstrap/phone_steps"
private const val PREFS = "openstrap_steps"

Expand Down Expand Up @@ -111,6 +113,19 @@ object PhoneStepCounter : SensorEventListener {
stopAndForget(app)
result.success(null)
}
// The listener batches for up to 60 s. A three-minute calibration
// routine read without a flush misses up to a third of itself.
// Answers when the flush has COMPLETED (onFlushCompleted, after the
// batched events are delivered), not when it was requested. False
// when it was refused or did not complete within FLUSH_TIMEOUT_MS.
"flush" -> flush(app, result)
// The sensor's own running total as last delivered — exact, unlike
// a range query, which prorates 5-minute bins. Calibration reads it
// at the start and end of a routine (after a flush) and differences.
"rawCount" -> {
val r = prefs(app).getFloat(KEY_LAST_RAW, -1f)
result.success(if (registered && r >= 0f) r.toLong() else null)
}
"stepsInInterval" -> {
val from = call.argument<Number>("fromMs")?.toLong()
val to = call.argument<Number>("toMs")?.toLong()
Expand Down Expand Up @@ -217,6 +232,37 @@ object PhoneStepCounter : SensorEventListener {

override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) = Unit

// ── flush ───────────────────────────────────────────────────────────────

private const val FLUSH_TIMEOUT_MS = 5_000L
private val main = Handler(Looper.getMainLooper())
private val pendingFlushes = mutableListOf<MethodChannel.Result>()

private fun flush(ctx: Context, result: MethodChannel.Result) {
if (!registered) {
result.success(false)
return
}
val sm = ctx.getSystemService(Context.SENSOR_SERVICE) as SensorManager
pendingFlushes.add(result)
if (!sm.flush(this)) {
pendingFlushes.remove(result)
result.success(false)
return
}
main.postDelayed({
if (pendingFlushes.remove(result)) result.success(false)
}, FLUSH_TIMEOUT_MS)
}

// Delivered on the listener's thread (main: registered without a handler),
// after every batched event, so the totals are current when it fires.
override fun onFlushCompleted(sensor: Sensor?) {
val done = pendingFlushes.toList()
pendingFlushes.clear()
done.forEach { it.success(true) }
}

override fun onSensorChanged(event: SensorEvent) {
val ctx = appContext ?: return
val raw = event.values?.firstOrNull() ?: return
Expand Down
Loading
Loading