Add live final-position feedback and fix step detection accuracy

Shows a live banner as each step of the approach is counted, ending in
"FINAL POSITION - RELEASE!" once the 5th footfall lands. Also fixes
LiveStepDetector's peak-prominence check, which compared a candidate
footfall only to its immediate neighboring frame and silently dropped
real steps that landed across several closely-spaced frames; it now
tracks the true rise/fall trough on each side instead. Switches
PoseAnalyzer to ML Kit's faster base pose model (the accurate model was
starving the peak detector of frames on unaccelerated hardware), and
makes LiveStepDetector's stillness-based reset toggleable, currently
off for easier testing against recorded reference clips.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
midnight-masala
2026-09-07 20:58:03 +08:00
co-authored by Claude Sonnet 5
parent afb9d800ff
commit 2bb7c6ca7b
10 changed files with 212 additions and 42 deletions
@@ -86,6 +86,30 @@
android:textStyle="bold" />
</LinearLayout>
<!-- Live "you're in your final position" banner, shown once the 5th
(final) foot-plant of the current attempt is detected (see
BowlingCameraActivity's stepEvents collector), cleared automatically
whenever the step count resets for the next attempt. Centered
horizontally regardless of orientation, anchored below the top
corner buttons so it never overlaps them. -->
<TextView
android:id="@+id/text_final_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/overlay_scrim"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:text="@string/final_position_reached"
android:textColor="@color/final_position_highlight"
android:textSize="22sp"
android:textStyle="bold"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/btn_switch_camera"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp" />
<!--
Mirrored onto the start edge at the same vertical center as btn_record
on the end edge. Live pose overlay + baked-in-recording toggle; only
@@ -85,6 +85,30 @@
android:textStyle="bold" />
</LinearLayout>
<!-- Live "you're in your final position" banner, shown once the 5th
(final) foot-plant of the current attempt is detected (see
BowlingCameraActivity's stepEvents collector), cleared automatically
whenever the step count resets for the next attempt. Centered
horizontally regardless of orientation, anchored below the top
corner buttons so it never overlaps them. -->
<TextView
android:id="@+id/text_final_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/overlay_scrim"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:text="@string/final_position_reached"
android:textColor="@color/final_position_highlight"
android:textSize="22sp"
android:textStyle="bold"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/btn_switch_camera"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp" />
<!-- Live pose overlay + baked-in-recording toggle. Only togglable while
not recording (see BowlingCameraActivity#renderRecordingState) since
the recording pipeline picks its pose mode once at start. -->
+1
View File
@@ -13,4 +13,5 @@
<color name="skeleton_joint">#FF00E5FF</color>
<color name="skeleton_bone">#FF76FF03</color>
<color name="overlay_scrim">#99000000</color>
<color name="final_position_highlight">#FFFFD600</color>
</resources>
+2
View File
@@ -15,6 +15,8 @@
<string name="recording_timer_placeholder">00:00</string>
<string name="step_count_placeholder">Step 0</string>
<string name="step_count_format">Step %1$d</string>
<string name="final_position_reached">FINAL POSITION — RELEASE!</string>
<string name="step_reached_format">STEP %1$d</string>
<string name="error_camera_unavailable">Camera unavailable: %1$s</string>
<string name="error_recording_failed">Recording failed: %1$s</string>
<string name="error_pose_detector">Pose detector error: %1$s</string>