Skip to content

Complete Android animation runtime integration and validation - #54

Merged
ProGraMajster merged 1 commit into
masterfrom
codex/issue-29-android-animation-runtime
Aug 15, 2026
Merged

Complete Android animation runtime integration and validation#54
ProGraMajster merged 1 commit into
masterfrom
codex/issue-29-android-animation-runtime

Conversation

@ProGraMajster

Copy link
Copy Markdown
Owner

Summary

Completes Android runtime integration for the shared ModernFormsNext animation system without introducing Android-only schedulers, easing, or interpolation.

This integrates the shared AnimationScheduler with Choreographer-based frame pacing and covers lifecycle pause/resume/rebase, Android animator-duration scaling, stable multi-touch ownership, interaction effects, theme transitions, layout and visual-state transitions, cleanup, diagnostics, and the Android diagnostic sample.

Architecture

The platform-neutral runtime remains responsible for:

  • animation models and easing
  • interpolation
  • AnimationScheduler
  • ThemeManager
  • InteractionEffect, RippleEffect, and PressScaleEffect
  • LayoutTransition and VisualStateTransition
  • logical and presentation state

The Android backend is limited to:

  • the Choreographer frame source
  • the lifecycle bridge
  • MotionEvent translation
  • density conversion
  • animator-duration-scale observation
  • native callback and subscription cleanup
  • Android runtime diagnostics

No second Android-only animation system was created.

Frame pacing

  • Uses one process-wide Choreographer source for the shared scheduler.
  • Keeps at most one native frame callback pending.
  • Requests callbacks only while shared animation demand and an attached/resumed surface are both present.
  • Returns to idle after the final animation and wakes for later work.
  • Uses the scheduler's monotonic clock and does not assume 60 Hz.
  • Dropped and long frames advance to the current presentation value without accumulating a frame backlog.
  • Late-binds the platform frame source, so early AnimationScheduler.Default access cannot permanently select the fallback ticker.
  • Active fallback demand hands off once to Choreographer without delivering a duplicate scheduler tick.

Lifecycle

  • Backgrounding stops frame demand and pauses the shared scheduler.
  • Resume rebases scheduler time so background elapsed time is excluded and cannot produce catch-up animation.
  • Attach/resume activates the Android surface; pause/stop/detach/dispose deactivates it.
  • A monotonic lifecycle version prevents stale foreground work from overtaking a newer background event.
  • Choreographer is acquired and reconciled on Android's main Looper.

Reduced motion

Android ANIMATOR_DURATION_SCALE is read through a lifecycle-aware ContentObserver using the application context and a main-thread Handler.

  • scale == 0: active animations publish their exact target immediately and the scheduler remains idle.
  • scale < 1: newly started animations use shortened durations.
  • scale == 1: normal duration.
  • scale > 1: newly started animations use extended durations.
  • Invalid or unavailable reads use a diagnostic fallback of 1.0.
  • Observation is enabled only while needed in the foreground and is unregistered during background/shutdown/disposal cleanup.

Multi-touch

  • Uses stable Android pointer IDs for shared pointer capture and effect ownership.
  • Uses ActionIndex only to find the changed pointer for DOWN/POINTER_DOWN and POINTER_UP/UP.
  • MOVE translates every currently present pointer.
  • CANCEL clears every tracked pointer.
  • Pointer-index reordering does not transfer ownership.
  • Ripple instances retain independent pointer ownership.
  • Press-scale ownership and cancellation remain in the shared effect implementation.

Cleanup and leak prevention

Cleanup covers scheduler entries, native frame callbacks, pointer captures, lifecycle and invalidation subscriptions, ContentObserver registration, detach/reparent/dispose, and surface recreation.

The Android activity tracker uses a WeakReference for the current Activity. The frame source does not retain a View or Activity, and reduced-motion observation uses application context. Automated weak-reference and lifecycle tests cover managed cleanup paths; no device-profiler leak claim is made.

Automated validation

  • Full restore: PASS
  • Debug solution build: PASS, 0 warnings / 0 errors
  • Release solution build: PASS, 0 warnings / 0 errors
  • All tests: 1083/1083
    • Core: 820/820
    • Android backend: 72/72
    • Designer: 168/168
    • Windows backend: 7/7
    • Cross-platform sample: 16/16
  • Android SmokeTest Debug/Release: PASS
  • CrossPlatform.Sample Android Debug/Release: PASS
  • VSIX Debug/Release validation: PASS
  • git diff --check: PASS

The complete test count was confirmed from a clean worktree at the exact feature SHA because nested worktrees under artifacts can otherwise contaminate ReleaseVersionConsistencyTests.

Manual emulator validation

A manual emulator smoke test confirmed only:

  • Android host startup
  • basic AnimationScheduler/Choreographer operation
  • animation start and retargeting
  • theme transition
  • TextBox
  • Android soft keyboard / IME
  • no visible crash in that scenario

Remaining device-specific validation

The following still require deeper manual/device validation and are not claimed as completed here:

  • real two-finger multi-touch
  • system-generated ACTION_CANCEL
  • dynamic animator-scale changes while the app is running
  • long background intervals, screen off/on, and app switching
  • rapid repeated rotation and resize
  • Activity/surface recreation during active effects
  • 90/120 Hz displays
  • visual behavior under dropped or unusually long frames
  • device-profiler leak checks
  • physical-device validation
  • more complex IME/composition scenarios

Closes #29

Drive the shared AnimationScheduler from one demand-driven, surface-gated Choreographer callback while preserving the shared monotonic clock and lifecycle pause rebasing.

Late-bind the default tick source so early AnimationScheduler.Default access cannot pin the fallback timer, serialize lifecycle state application, and acquire Choreographer only on Android's main Looper.

Observe Android animator duration scale dynamically with a lifecycle-aware ContentObserver, propagate the exact platform scalar through neutral policy, and ensure deterministic scale-zero endpoint completion and cleanup.

Preserve stable MotionEvent pointer ownership across multi-touch index changes and cancellation, add cleanup, resize, retargeting, idle-wake, and leak regressions, and document the Android capability and manual-validation matrix.
@ProGraMajster
ProGraMajster merged commit 171855a into master Aug 15, 2026
1 check passed
@ProGraMajster
ProGraMajster deleted the codex/issue-29-android-animation-runtime branch August 15, 2026 18:29
@github-project-automation github-project-automation Bot moved this from Backlog to Done in ModernFormsNext Roadmap Aug 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Complete Android animation runtime integration and validation

1 participant