Files
XQKqueue/.project-docs/30-worklog/tasks/20260811-native-display-f2456ea9.md

9.9 KiB

Task: Implement native Android display screens

Identity

  • Task ID: 20260811-native-display-f2456ea9
  • Mode: Feature
  • Branch: main
  • Worktree: D:\Datas\PythonProjects\XQKqueue
  • Base commit: e4e3e6a735
  • Owner: codex
  • Status: Blocked at documentation completion gate; Android 1.5.2 range-display fix and APK are complete and ready for target-device acceptance

Scope

  • Replace the Android WebView presentation shell with native Android overview and project-detail screens.
  • Call the existing public overview and project snapshot APIs directly from the APK.
  • Preserve project navigation, polling, new-call deduplication, three-repeat announcement playback, immersive landscape display, error recovery, and deliverable APK documentation.
  • Replace Android system TTS with APK-embedded Mandarin PCM audio fragments composed from the server-provided ticket numbers.
  • Keep the existing server and browser UI behavior unchanged unless an API-contract defect is proven.

Intent And Constraints

  • The user explicitly chose native Android because the target display device remains unreliable with WebView rendering and system TTS.
  • The overview screen must never announce calls; only a concrete /display/{identifier} project screen may announce.
  • The target panel is 1920x1080 landscape, but layout must use available dimensions/density rather than hard-coded physical pixels.
  • Existing uncommitted landscape/WebView work and deliverables were explicitly adopted as the starting worktree state.
  • Facts must be verified against current server and Android source; unknown API fields must not be invented.
  • The server contract and database must remain unchanged; the APK owns number-to-audio composition.
  • Embedded voice assets must have a documented, distributable source and a uniform decoder-independent PCM WAV format.

Outcome

  • Replaced the Android WebView shell with native platform Views for the project overview and project detail screens.
  • Added strict public-display DTO parsing, a typed HTTP client, and one generation-safe fixed-delay polling loop per active screen.
  • The overview polls every 5 seconds, supports an adaptive 1-4 column project-card grid and DPAD/touch navigation, and has no announcement coordinator.
  • The project screen polls every 3 seconds; the same successful snapshot updates the UI and drives announcement deduplication.
  • Preserved first-snapshot silence and replaced system TTS with 13 APK-embedded Mandarin PCM WAV fragments. The app composes strict five-digit single/range calls locally, streams each new batch three times through AudioTrack, and never includes the project name.
  • Rapid new batches remain FIFO ordered, with 350 ms gaps between repeats and batches. Pause, navigation away, audio-focus loss, or shutdown stops the active/pending queue; overview construction has no announcement path.
  • Streaming uses bounded 16 KiB writes and transient media audio focus instead of a long static native buffer, reducing Android TV implementation and memory risk.
  • Added stable loading, empty, 404, fatal-error, cached-offline, and delayed-update states; forecast pages rotate every 6 seconds independently of the 3-second refresh.
  • Reused the existing scenic logo and water artwork in native resources and retained density-adaptive fixed-landscape behavior.
  • Removed the obsolete WebView-only announcement poller. After target-device feedback proved the first eSpeak voice assets did not produce Chinese speech, restored the project's original browser WAV fragments from Git history and remapped them to the Android composer. Produced debug APK version 1.5.1 (versionCode 8).
  • Target-TV evidence then showed a two-ticket batch rendering only 00010 至. The live snapshot was verified to contain both 00010 and 00011, proving the API and formatter were complete. Replaced the current-number platform auto-size dependency with an API-23-compatible SingleLineFitTextView that measures the real content width and height, chooses the largest fitting size, never ellipsizes, and can shrink below the nominal 30sp floor rather than hide the last ticket. Produced debug APK version 1.5.2 (versionCode 9).

Verification

  • android\gradlew.bat clean testDebugUnitTest lintDebug assembleDebug: PASS after the final 1.5.2 range-display fix; 56 JVM tests in 12 suites, 0 failures/errors/skipped; lint 0 errors / 24 warnings.
  • Web Vitest: PASS, 18 files / 66 tests.
  • Web TypeScript checks and Vite production build: PASS.
  • go test ./... in server: PASS.
  • git diff --check: PASS (only repository line-ending notices).
  • APK source and deliverable SHA-256 match: 5CB13105178EA5630EA124D0BE98A189E1B7F0557B2672C8CFAD3B6002FCBBEB.
  • aapt: package cn.nianxx.queue.display, versionCode 8, versionName 1.5.1, minSdk 23, targetSdk 36, landscape activity, no TTS service query, and all 13 voice WAV resources packaged.
  • apksigner verify: PASS with Android Debug certificate (v1/v2 signatures).
  • Actual voice resources are locked by JVM tests for exact names, strict WAV parsing, PCM16 mono 16 kHz format, frame alignment, and common sample rate. Git-history source, mapping, hashes, failed 1.5.0 diagnosis, and 1.5.1 ASR evidence are recorded in 50-evidence/topics/20260811-native-display-f2456ea9__embedded-audio-assets.md.
  • The 1.5.0 eSpeak cmn audio failed calibrated SAPI and Vosk recognition and was replaced. The restored legacy WAVs recover the ticket phonemes and sentence anchors with Vosk average confidence around 0.84-0.89. No ADB device or configured emulator was available, so target-TV listening remains required.
  • Final audio read-only Sol review: PASS; no P0/P1 findings after streaming, audio-focus cancellation, and stop/release serialization fixes.
  • Range-display regression: an API-25 Robolectric view test reproduces the real 00010 至 00011 batch through the complete native ProjectDisplayView and locks full text/single-line/no-ellipsis behavior. A narrow ASCII view test asserts the final measured width and font height fit the real content bounds. A deterministic test calls the production two-stage sizing decision and locks largest-fitting selection, below-30sp fallback, and the 1sp terminal boundary. The pre-fix API-25 case kept the initial 74sp because the old helper only enabled platform auto-size on API 26+.
  • Live API verification on 2026-08-12: /api/display/YYHHC/snapshot returned current_batch.tickets=[00010,00011] and latest_ticket_number=00011; this excluded the server contract and parser as the truncation source.
  • APK source and deliverable SHA-256 match after the final 1.5.2 build: 0D56C10B8CE706893F3EA8E59B21329847517F56F7347ABEA127AB30C6C71D77; aapt reports versionCode 9 / versionName 1.5.2 and apksigner verifies v1/v2 signatures.
  • Final range-display read-only Sol review: code and APK PASS with no P0/P1 implementation findings. Overall project-task status remains FAIL solely because the mandatory project-document drift gate is blocked by the pre-existing initializer FOREIGN_DOC state described below.
  • Task Documentation Gate: check_doc_drift.py --task-id 20260811-native-display-f2456ea9 remains BLOCKED because the document initializer created canonical templates that the feature-task boundary classifies as FOREIGN_DOC; product source, task-owned record, and task-prefixed evidence are otherwise present. task_context complete was not run because the drift prerequisite did not pass.

Follow-ups

  • Install the 1.5.2 debug APK on the target 1920x1080 television and confirm 00010 至 00011 plus a wider representative range show both endpoints; also smoke-test overview navigation, project refresh, DPAD focus, Home/resume silence, media volume/focus routing, and every digit in representative calls.
  • Confirm and archive the ownership/redistribution basis for the legacy project WAVs; Git history contains the files and usage but no original generator, speaker, or separate license record.
  • Build the production release with the operator's long-lived signing certificate rather than the debug certificate.
  • Revalidate orientation behavior before moving to targetSdk 37 because the Android 16 compatibility property is temporary.
  • Documentation gate: obtain human authorization to re-register this task in Integration mode so the initializer-created canonical .project-docs templates can be owned without committing, hiding, or deleting them.

Promotion Candidates

  • Target: architecture/system overview and data-flow documentation. Proposal: record that the dedicated Android display client is native Views rather than WebView; exactly one active screen poller owns network refresh; a project snapshot is the single source for both rendering and embedded-audio announcements; the overview screen cannot announce by construction. Evidence: native Activity/data/view/audio implementation, 53 JVM tests, lint/build results, and API/audio evidence under 50-evidence/topics/. Future impact: Android display changes should extend the native DTO/view boundary and must not introduce a second snapshot request or announcement path on overview. Conflicts: none known; the canonical files were initialized as placeholders and were intentionally not promoted during this feature task. Confirmation: the user explicitly approved replacing the current Android presentation with native pages, taking over the existing worktree changes, and replacing TTS with embedded audio.
  • Target: the maintain-project-docs initialization workflow. Proposal: provide an explicit first-install ownership mode so initializer-created canonical templates do not appear as foreign feature-task drift. Evidence: check_doc_drift.py classified every non-overwritten initializer template as FOREIGN_DOC; see 60-reflection/cases/20260811-native-display-f2456ea9__initialization-drift-deadlock.md. Future impact: avoids a completion deadlock when the document system is first introduced during a repository task. Conflicts: none with product behavior; this concerns task-document workflow only. Confirmation: required before changing task mode or shared skill behavior.