Skip to content

Complete Android application and windowing host - #169

Merged
ProGraMajster merged 2 commits into
masterfrom
codex/issue-72-android-windowing
Oct 5, 2026
Merged

ProGraMajster merged 2 commits into
masterfrom
codex/issue-72-android-windowing

Conversation

@ProGraMajster

@ProGraMajster ProGraMajster commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

Android applications can now call Application.Run(Form) through a registered IWindowingPlatform, AndroidWindowImpl and Activity-owned native host. Shared Form lifetime, owned popups/modals, recreation and the externally owned dispatcher run over the existing Skia, focus, validation, IME and accessibility stack.

Final review fixed three reproduced regressions: repeated Show retired a live View's epoch, Back/recreation used construction rather than presentation order, and an older owner Hide could destroy a newer reentrant Show. Native cleanup also tolerates popups disposed during lifecycle callbacks and rejects queued Back from a retired host.

Detailed review, API inventory, all 56 paths, acceptance evidence and commands.

Before / After

Before: Activity → AndroidAppHost → AndroidSkiaHostView → SkiaControlSurface assembled by the sample.

After: Application.Run → Form → Android window backend → Activity host → existing native Skia presentation.

Window policy

One main Form per Activity host + owner-bound modal child Forms + reusable in-Activity popups. A second independent main Form or concurrent Activity host is explicitly rejected. This does not implement a desktop-style multiple top-level window manager.

External loop

Android owns its system main Looper. An explicit neutral IExternallyOwnedDispatcherImpl capability makes Run establish lifetime, show the Form and return; subscriptions remain until Exit. Posts, timers and InvokeAsync use the main Handler. There is no nested Looper or worker UI thread; framework Exit finishes native presentation without quitting the system loop. Windows retains its controlled/blocking loop and TestHost keeps its existing semantics.

Lifecycle / recreation

The process registry holds a weak Activity host, while the Activity owns its container, Views and bitmaps. The same Form/control tree survives recreation. Generation and presentation epochs retire old input, IME, provider and Back callbacks; native focus must be confirmed before reacquiring text input. Hide releases presentation; terminal Close cleans once. OpenForms, Load/Shown and all three lifetime modes remain shared.

Platform semantics

Main size and chrome belong to Android. Modal/popup sizes are clamped hints; geometry is confirmed by native layout. Arbitrary top-level Move, non-Normal WindowState and unsupported desktop setters reject. Screen describes the current Activity display; AndroidView is a borrowed JNI handle valid for its presentation. Safe area is applied once, matching painting, touch and PointToScreen; IME insets remain informational. Rendering stays software Skia.

Input / focus / validation / IME

Reuse #160 ControlFocusScope, #161 validation, existing bindings and ControlTextInputHost. A borrowed surface router uses the actual Form adapter rather than another root. Revocable clients feed the existing Android InputConnection; no EditText or second document model. Regressions cover validation veto/session retention, Form preview changing binding focus and shortcut-owned KeyUp.

Popup / modal / Back

Popups retain reusable Hide/Show and shared text leases. ShowDialog disables its owner and completes the existing asynchronous DialogResult task, restoring owner input. Back follows popup → last shown modal → cancellable main close after native IME handling. API 33+ uses guarded OnBackInvokedDispatcher; earlier APIs use OnBackPressed. Instrumentation waits for native IME transition idle without retrying Back.

Accessibility

Native nodes project the canonical semantic tree, including ancestry around the omitted Form client-area peer. Shared accessibility semantics are unchanged. Window peer bounds already use physical screen pixels. Phase 3 observes the real native focus event after one action, without increasing timeouts or adding action retries.

Sample

Removed transitional AndroidAppHost.cs from the normal path. MainActivity uses AndroidWindowActivity and Application.Run. WindowsAppHost derives from the same MainForm, keeping only desktop settings. The public AndroidActivityHost remains an intentional alternative for custom Activity inheritance/lifecycle forwarding. No new dotnet-new/VS Android template is claimed; complete startup/template guidance is documented with the sample.

Tests

  • Restore and full sequential Debug/Release builds: PASS, 0 warnings / 0 errors.
  • Full Release: 4097/4097 PASS, 0 skipped, one run.
  • Full Debug: 4096/4097 in each of two runs, 0 skipped. First failure: native Windows UIA calendar popup not discovered. That test passed in isolation and the subsequent full Debug and Release Windows suites (328/328). Second Debug failure: PreparedPlanDoesNotAllocatePerIntermediateFrame, 552 B vs 256 B; it passed in the first Debug run and Release. Exact causes remain unestablished; neither full Debug run is represented as wholly green.
  • The brush test/implementation have no diff in this PR. This is distinct from Investigate intermittent allocations in the profiler recording-only regression test #168's profiler allocation test. No threshold, timeout, skip, retry or required check was weakened; failed evidence remains preserved.
  • Android backend: 382/382, including 24 windowing cases; three new regressions were red before correction.
  • Windows native HWND startup/normal close: ControlGallery, DemoApp and CrossPlatform.Sample PASS, exit 0. This is automated native evidence, not manual visual/VS F5 qualification.

Native validation

Final focused runs after review corrections, using real Views/main Looper/InputConnection/Back/recreation:

Device Configuration Windowing Accessibility Phase 4 Phase 3
Pixel_8 emulator, API 34, x86_64 Debug and Release 61/61 each 65/65 each 49/49 each
nubia NX769J physical phone, API 36, arm64 Debug and Release 61/61 each 65/65 each 49/49 each

Windowing includes five recreations, retired View/Activity collection, stale IME rejection, repeated Show rendering, nested modal order, reentrant owner Hide/Show, backgrounding with a popup, posts/timers/cancellation and the surviving system Looper after framework Exit. A locked/asleep-phone startup failure is retained separately; the unchanged test passed after the user unlocked it.

The earlier complete native matrix (95 emulator / 105 phone assertions) and ten physical Release Phase 3 repetitions are historical implementation-stage evidence. They were not repeated in full after review; the final focused results above qualify the changed paths. Manual checks are listed separately below.

Packaging

Debug standalone APK, Release APK and Release AAB: PASS. Release uses profiled Mono AOT, partial trimming (SdkOnly), embedded assemblies, arm64+x64, minimum API 23 / target 36. Framework/backend/sample AOT libraries were verified in both APK and AAB. Native Release runs used the preserved final APK. No store/distribution signing or submission claim.

Limitations

  • Backend remains experimental; Windows is the primary platform.
  • Runtime API 23–32: NOT EXECUTED.
  • Manual TalkBack speech/gestures, vendor IME composition, physical keyboard, broad OEM coverage, manual Windows visual interaction and Visual Studio F5 Android workflow: NOT EXECUTED.
  • Actual 90/120 Hz rendering qualification: NOT EXECUTED; earlier physical measurements were approximately 60 Hz.
  • Play Store signing/submission: NOT EXECUTED.
  • No desktop multi-main manager. Complete Android platform services #79 platform services, Add native view hosting abstraction for platform controls #60 native child View hosting and GPU Accelerated support like Avalonia.OpenGL,Avalonia.Vulkan and more #46 GPU remain separate; no Linux/macOS/iOS work, version bump, new dependencies or CI changes.
  • The two disclosed Debug failures require consideration during final merge review; Release success does not erase them.

Acceptance and issue links

#72 criterion Final assessment
Supported Android application startup aligned with Application PASS
Required WindowKit backend contracts without Windows assumptions PASS
Form/popup/modal/ownership/multiple-window policy PASS
Lifecycle/recreation/insets/input/renderer integration PASS
Capability differences and useful diagnostics PASS
Android template guidance/docs and representative emulator/physical validation PASS

All six criteria are met within the documented bounded mobile policy; this does not claim production-wide qualification or universally green Debug tests.

Fixes #72

Related to #63, #60, #79, #46, #160 and #161. #60/#79/#46/#168 remain OPEN and are not closed by this PR.

Two commits preserve the feature and its documentation correction separately:

  1. 6d14a538291b144e616dafd2a7e69e1c2443b298 — Complete Android application windowing host.
  2. 72db978ec3d431c5577bb6f14a637bafdf6aa895 — Fix stale Android windowing documentation.

The documentation follow-up corrects obsolete manual-surface startup, missing Form/window host, lifetime/DPI/inset, accessibility/calendar and ownership claims in 16 Markdown files. All 13 original PR Markdown files were audited; repository search also identified six related current guides requiring small corrections. Dated implementation reports, historical baselines and original validation counts remain preserved. Production code and tests are unchanged by the second commit.

Follow-up checks: repository documentation validation passed for all 19 PR Markdown files; CommonMark local link checks passed for 224 links/images including 53 anchor links; release-documentation script tests passed 32 assertions; stale-claim search and git diff --check passed. No full local build or 4097-test rerun was needed for this Markdown-only correction. Required CI for the new head is tracked separately; the prior head's green result does not qualify it.

The implementation review covers its original 56 paths. The complete PR now contains 62 paths: 44 modified, 17 added, 1 deleted. No artifacts, APK/AAB, captures, logs, TRX, helper scripts, machine configuration or .codex files are committed. PR remains open for a separate final merge review; no merge in this task.

@ProGraMajster
ProGraMajster merged commit f521f9d into master Oct 5, 2026
1 check passed
@ProGraMajster
ProGraMajster deleted the codex/issue-72-android-windowing branch October 5, 2026 17:07
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 the Android application and windowing host

1 participant