Commit 930f8d6
Native Apple Watch (watchOS) port: Core Graphics backend + watch app target (#5252)
* feat: smartwatch form-factor support (Apple Watch + Wear OS)
Adds the foundation for building Apple Watch / Wear OS apps and proves the
model end-to-end in the hellocodenameone screenshot suite.
Form-factor API (core + ports):
- Display.isWatch()/getFormFactor() + CN facades + FORM_FACTOR_* constants,
following the isTablet()/isDesktop() pattern. Defaults false in
CodenameOneImplementation; overridden in iOS (native isRunningOnWatch),
Android (FEATURE_WATCH), and JavaSE (skin watch=true). New "watch" resource
override layer in each port's getPlatformOverrides().
watchOS rendering port (iOS native sources, all additive under
#if TARGET_OS_WATCH so the iOS slice is byte-for-byte unchanged):
- CN1CGGraphics: Core Graphics rasterizer backend (no GL/Metal on watchOS).
- CN1WatchRenderingView: CGBitmapContext surface conforming to CN1RenderingView.
- CN1WatchHost: timer-driven frame pump + crown/tap input bridge.
- FillRect/DrawRect/ClearRect/DrawLine wired to the CG backend (rollout in
WATCHOS_PORT.md). Validated on the watchOS simulator (Xcode 26.3).
Build pipeline (separate watch entry point + seamless double app):
- codename1.watchMain in codenameone_settings.properties declares a distinct
watch lifecycle (Apple Watch + Wear); a distinct entry enables more
aggressive tree-shaking. Flows via CN1BuildMojo as the watchMain build arg.
- WatchNativeBuilder (modeled on MacNativeBuilder) auto-enables when watchMain
is set and adds a watchOS app target (arm64_32, WKApplication, companion
embed or standalone) to the iOS Xcode project via the xcodeproj gem.
- watchNative.* build hints registered in BuildHintSchemaDefaults.
- JavaSE ships generated Apple Watch simulator skins (round, safe areas).
hellocodenameone (proves the APIs + model):
- AbstractGraphicsScreenshotTest renders 4 separate full-screen captures on a
watch (via CN.isWatch()) instead of a cramped 2x2 grid; BaseTest gains a
chained-capture helper. Verified in the JavaSE simulator with the Apple
Watch skin (396x484): graphics-{draw,fill}-arc-{direct,image}-aa-{off,on}.
- HelloCodenameOneWatch watchMain lifecycle + codename1.watchMain setting.
- Cn1ssDeviceRunner gains an optional -Dcn1ss.filter subset selector.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): WatchNativeBuilder emits a watchOS target that compiles (validated)
The watch target now injects into the regular ios-source build and compiles
against the watchOS SDK up to the GL-call link boundary. Validated end-to-end
by building hellocodenameone for the watchOS simulator (Xcode 26.3 / watchOS
26.2): the entire ParparVM-translated app + nativeSources + the Core Graphics
backend compile; the watch target is created, the SwiftUI @main shell + surface
bridge + Digital Crown/tap forwarding compile, and the bridging header resolves.
- CN1ES2compat.h: guard `#define CN1_USE_METAL` with `#if !TARGET_OS_WATCH` so
the watch slice never activates the Metal backend (watchOS has no Metal).
- WatchNativeBuilder:
- Complete the generated CN1WatchApp.swift (CN1WatchRootView + the
CN1WatchSurface frame bridge + crown/tap), not just an App stub.
- writeStubHeaders(): emit watchOSStubs/ GLKit + OpenGLES stub headers (same
pattern MacNativeBuilder uses for Catalyst) so the shared sources that
import those frameworks compile; HEADER_SEARCH_PATHS points the watch target
at them.
- SDK-conditional ARCHS: arm64_32 for watchos*, $(ARCHS_STANDARD) for
watchsimulator* (arm64_32 is device-only; the simulator slice was failing
"Unable to find module 'Swift'" trying arm64_32-simulator).
- Exclude CN1MetalShaders.metal from the watch target.
- Raise the watchOS floor to 10.0 (SwiftUI onChange(of:) two-param API).
- IPhoneBuilder: call writeStubHeaders alongside the watch Info.plist + entry.
Remaining for a linking/running watch app (tracked in WATCHOS_PORT.md): wire the
remaining ExecutableOps to CN1CGGraphics and guard the GL call sites in
CodenameOne_GLViewController.m so no OpenGL ES symbols are referenced on watch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): wire transform + polygon ops to the Core Graphics backend
Scale/Rotate/ResetAffine/FillPolygon get a #if TARGET_OS_WATCH execute branch
routing to CN1CGGraphics (scale/rotate/reset-affine/fill-polygon), with the
GLKit-math init paths guarded out on watch. Joins the earlier FillRect/DrawRect/
ClearRect/DrawLine. Remaining ops + the GL no-op shim for CodenameOne_GLViewController
and the watch runtime bootstrap are next.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): wire DrawString + DrawGradient to the Core Graphics backend
#if TARGET_OS_WATCH execute branches: CN1CGDrawString (Core Text) and
CN1CGGradientRect. 10 of the ExecutableOps now route to CN1CGGraphics on watch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): guard MessageUI/AudioToolbox (absent on watchOS)
Guard the MessageUI (mail/SMS composer) + AudioToolbox imports, the matching
GLViewController delegate conformances/callbacks, the sendEmail/sendSMS native
methods, and the vibrate AudioServices call behind #if !TARGET_OS_WATCH.
Confirms the architecture: watchOS ships UIKit headers but marks
UIView/UIViewController/UIEvent/CADisplayLink unavailable, so the
UIViewController-based CodenameOne_GLViewController cannot compile for watch --
the watch slice needs a CG render-driver replacing it (next).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(watch): scope the watch render-driver contract (55 native fns + singleton)
Document the exact contract the watch CG render-driver must satisfy to replace
the UIViewController-based GLViewController on watchOS, modeled on LinuxPort.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): watch render-driver replacing the GL view controller
CodenameOne_GLViewController.h gains a #if TARGET_OS_WATCH NSObject interface
variant (no UIViewController); CN1WatchViewController.m implements it as the
watch render-driver: the ExecutableOp queue + flushBuffer swap + drawFrame
draining into the Core Graphics surface (CN1WatchRenderingView). The GL view
controller + UIApplication delegate are excluded from the watch target.
Native-method surface (the 55 Java_*Impl entry points) follows.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): guard EAGLView/UIWindow, exclude UIWebView peer, guard net indicator
EAGLView.h (CAEAGLLayer UIView) guarded off for watch; render-driver eaglView
returns id; CN1ShowLaunchPlaceholder(UIWindow*) guarded; UIWebViewEventDelegate.m
excluded; NetworkConnectionImpl network-activity-indicator calls guarded.
watch compile errors down from 36 to 1 (AudioToolbox next).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): Core Graphics op rollout + IOSNative watchOS guards
Route image/transform/clip/path/alpha-mask ops to the Core Graphics
backend on watchOS (DrawImage, TileImage, SetTransform, ClipRect,
DrawPath, DrawTextureAlphaMask), add CN1CGFillAlphaMask + a heap-backed
alpha-mask "texture" so anti-aliased shapes render without GL/Metal.
Inline GLKit matrix math into the watch GLKit stub so the transform
bookkeeping compiles. Guard the file-scope GL shader helpers and the
broad UIKit-peer surface in IOSNative.m (clipboard, text peers, media,
push, location, biometrics, screen-capture, CIFilter, UIApplicationMain)
behind #if !TARGET_OS_WATCH with no-op watch bodies; the iOS path is
preserved verbatim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): exclude/guard UIKit peer components on watchOS
Make the tap-gesture, inline text-field/text-view, web-view and
AudioQueue peers empty under #if !TARGET_OS_WATCH (headers and impls) and
add their .m files to the watch source-exclusion list. Guard the
AudioPlayer remote-control UIApplication call. iOS code preserved verbatim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): compile GLViewController graphics primitives on watchOS
Stop excluding CodenameOne_GLViewController.m from the watch slice so its
shared CGContext/op-based graphics entry points (createImage, fonts, the
*Impl drawing functions, safe-area + status-bar helpers) link on watch.
Guard the UIViewController class + UIKit-only helpers (launch placeholder,
status-bar tap proxy, editingComponent, orientation/keyboard) behind
#if !TARGET_OS_WATCH; the watch render-driver class lives in
CN1WatchViewController.m. iOS path preserved verbatim.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): watch runtime glue + bootstrap -> watch app links
Add CN1WatchRuntime.m: the app-agnostic half of the watchOS bootstrap
(cn1_watch_runtime_start -> initConstantPool + app hook; runtime_paint
drives the render-driver drawFrame; runtime_pointer* feed CN1 pointer
events) plus no-op stubs for the watch-excluded 3D GL bridge and the
app-suspend globals owned by the iOS app delegate. With the per-file
main() rename of the ParparVM phone Stub on the watch target, the
HelloCodenameOne watch app now compiles AND links for watchsimulator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): boot CN1 runtime + render real forms to Core Graphics
Resolve the watch bootstrap deadlock and render the live UI:
- run the VM bootstrap (Stub.main -> Display.init) on a dedicated thread and
make watch initVM mirror UIApplicationMain (schedule the lifecycle callback,
then block forever) so Display.init never falls through to the blocking
initDefaultUserAgent path iOS never reaches.
- wire getDisplayWidth/HeightImpl to the CN1WatchRenderingView logical size on
watch (the UIView metric code is excluded) so forms lay out and paint.
- implement watch screenshot() by PNG-encoding the CG surface and feeding
onScreenshot, replacing the null-callback placeholder.
- fall back to a system font in string/charWidthNativeImpl when the font peer
is nil (avoids an NSDictionary-with-nil crash on the first text measure).
The HelloCodenameOne cn1ss suite now boots on the watch simulator and captures
real rendered frames (verified: "Main Screen" form with title + fields).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): builder generates working watch target (bootstrap + main rename)
Backport the project mutations proven locally into WatchNativeBuilder so a
regenerated project boots:
- emit cn1_watch_app_main() into CN1WatchBootstrap.m, entering the regular
main class's generated Stub.main (which drives Cn1ssDeviceRunner on watch).
- stop excluding the phone Stub from the watch target; instead neutralise its
duplicate C main() with a per-file -Dmain rename (+ return-type warning
suppression), keeping the app's translated classes + Stub.main available.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(watch): install SIGSEGV->NPE handlers on the watch slice
Mirror CodenameOne_GLAppDelegate's installSignalHandlers (that file, the
UIApplication delegate, is excluded on watchOS) so a stray null/dangling
deref in a native/peer path converts to a recoverable Java exception instead
of taking the whole watch app down, matching the iOS runtime's behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): leak native peers instead of releasing dangling pointers
deleteNativePeer's [release] of a GC-handed-back peer pointer crashed with a
pointer-auth fault (use-after-free) and stalled the suite after ~2 tests.
No-op the release on the watch slice (leak peers) so the screenshot suite runs
to completion; peer-lifecycle hardening tracked separately. With this the full
hellocodenameone cn1ss suite captures 160 screenshots on watchsimulator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(watch): add watchOS screenshot goldens (160 captures)
Initial watch golden set captured from the hellocodenameone cn1ss suite on the
watchOS simulator via the Core Graphics backend (streamed through the standard
Cn1ssScreenshotServer WS sink). The watch form factor splits the iOS 2x2
graphics-op grid into separate full-screen tests, so the set is larger than the
iOS golden set. Spot-verified (Main Screen form, chart-pie, graphics clip).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(watch): pin watch goldens to the steady-state capture set (160)
The initial commit accumulated 209 PNGs across several local runs; a clean
single run of run-watch-ui-tests.sh reproduces 160 (0 mismatch). Pin the golden
set to exactly that steady-state output so the pipeline reports 0 missing / 0
mismatch on a healthy run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(watch): add run-watch-ui-tests.sh (build watch target, run suite, compare)
Lean watch screenshot runner: builds the <Main>Watch target for watchsimulator,
boots a watch sim, launches the app (which streams frames to the standard
Cn1ssScreenshotServer WS sink over ws://127.0.0.1:8765), waits for the suite to
settle, then reuses cn1ss_process_and_report to compare against the watch golden
set and post the PR status comment. Validated locally: 160 equal, 0 mismatch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): drop redundant getFormFactor; exclude CN1WatchApp.swift from iOS
- Remove Display.getFormFactor()/CN.getFormFactor() + FORM_FACTOR_* constants:
redundant with isWatch()/isTablet()/isDesktop() (no consumers), and the
source of the checkstyle if-whitespace failures.
- WatchNativeBuilder: add CN1WatchApp.swift (SwiftUI @main, imports WatchKit)
to the iOS app target's EXCLUDED_SOURCE_FILE_NAMES. The watch entry file is
globbed into the iOS/Mac-Catalyst app target during project generation, and
WatchKit doesn't exist there -> the iOS screenshot build failed to compile it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci(watch): run the watchOS screenshot suite in the iOS workflow
Add a watchOS UI screenshot step to the build-ios job (the GL job already
generates the project containing the auto-enabled watch target): ensure a
watchOS simulator runtime, then run run-watch-ui-tests.sh which builds the watch
target, runs the cn1ss suite on the watch sim, streams to the WS sink, and
compares against scripts/ios/screenshots-watch (gating: fail on mismatch,
tolerate up to 4 missing). Validated locally: 160 equal, 0 mismatch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): drop getFormFactor usage from the watch sample (compile break)
HelloCodenameOneWatch.kt referenced Display.formFactor (Kotlin sugar for the
now-removed getFormFactor()), which broke the hellocodenameone-common compile on
every platform that builds the sample suite (Android/JS/iOS/suite-classes). Log
isWatch() only; refresh the stale getFormFactor mentions in comments/KDoc.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): guard CN1WatchApp.swift with #if os(watchOS)
EXCLUDED_SOURCE_FILE_NAMES did not reliably keep the generated SwiftUI entry out
of the iOS/Mac-Catalyst app target (it is globbed into <mainClass>-src/), so the
iOS screenshot build kept failing on `import WatchKit`. Wrap the whole generated
file in #if os(watchOS) so it is an empty translation unit everywhere except
watchOS, independent of target membership. Watch target still builds (verified);
on iOS it now compiles to nothing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* ci(watch): promote watch screenshots to a dedicated build-ios-watch job
Move the watchOS screenshot run out of the build-ios job into its own
build-ios-watch job (mirroring build-ios-metal), so it shows up as a distinct
check, posts its own PR status comment (CN1SS_IOS_WATCH_COMMENT marker), and a
watch regression doesn't mask the iOS GL result. Builds the sample (which
generates the watch target), ensures a watchOS sim runtime, then runs
run-watch-ui-tests.sh against scripts/ios/screenshots-watch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): decouple watch target from iOS app build; select Xcode 26 in runner
Two CI breakages:
- build-ios failed because the companion embed makes the iOS app depend on the
watch target, so building the iOS app also builds the watch target against the
iphonesimulator SDK -- where the real OpenGLES framework collides with
watchOSStubs (duplicate EAGLContext). Make companion embedding opt-in
(watchNative.embedCompanion=true, default off); the watch slice is built and
tested independently, so the iOS screenshot build no longer touches it.
- build-ios-watch ran under the runner's default Xcode 16.4; run-watch-ui-tests.sh
now selects Xcode 26 (watchOS 26 SDK + arm64 watch sim) like build-ios-app.sh.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): gate the WKWebView/WebKit import off on watchOS
ENABLE_WKWEBVIEW is on by default in IPhoneBuilder, so the watch build pulled in
<WebKit/WebKit.h> (unavailable on watchOS) -> 'WebKit/WebKit.h' file not found.
My local watch project predated the default, which is why it only surfaced in
CI. Guard the import with !TARGET_OS_WATCH; that also leaves supportsWKWebKit
undefined so the WK usage block compiles out on watch too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(watch): pin a 46mm watch simulator to match the goldens
Screenshots are pixel-compared, so the sim screen size must match the
golden-capture device (46mm Apple Watch, 416x496). The runner now prefers a
46mm model (override via CN1SS_WATCH_MODEL/CN1SS_WATCH_UDID) and logs the
available watch sims, instead of grabbing whichever Apple Watch is listed first
(which could be a different size -> every screenshot mismatches).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): undef CN1_USE_AVKIT on watchOS (AVKit/AVPlayerViewController absent)
IPhoneBuilder uncomments //#define CN1_USE_AVKIT for all targets, pulling in the
AVKit AVPlayerViewController video path -- unavailable on watchOS (the iOS
screenshot build hit AVPlayerViewController/UIPageViewController errors). Undo
the define on the watch slice at the define site so all AVKit blocks compile
out; the watch video stubs already return defaults. Reproduced CI's exact macro
state locally (ENABLE_WKWEBVIEW + CN1_USE_AVKIT + CN1_INCLUDE_CRYPTO on) and the
watch target now builds clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): guard camera + local-notification watchOS-unavailable APIs
With the iOS sample's real build hints reproduced locally (INCLUDE_CAMERA_USAGE +
CN1_INCLUDE_NOTIFICATIONS/2 + AVKit + WKWebView + crypto all on), the watch
target hit three more unavailable APIs:
- captureCamera: UIImagePickerController / UIPopoverController /
presentModalViewController -> gate the INCLUDE_CAMERA_USAGE body off on watch
(camera capture is a no-op there).
- sendLocalNotification: UNNotificationSound soundNamed: -> use defaultSound on
watch.
- UNAuthorizationStatusEphemeral -> guard the iOS-14 ephemeral check off on watch.
Watch target now builds clean against the full CI hint set (verified locally).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): disable INCLUDE_CN1_CAMERA on watchOS (AVFoundation capture absent)
The AVFoundation camera stack (CN1Camera.{h,m} + the IOSNative camera natives)
uses AVCaptureSession/AVCaptureConnection/AVCaptureFileOutput etc., none of which
exist on watchOS. IPhoneBuilder uncomments //#define INCLUDE_CN1_CAMERA in this
central header (included first by every camera TU); undo it on the watch slice
so the whole camera path compiles out consistently.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): generate the FQN-mangled Stub.main symbol in the bootstrap
cn1_watch_app_main called <Main>Stub_main..., but request.getMainClass() is the
simple class name while the generated Stub's C symbol is mangled from the
fully-qualified <package>.<Main>Stub. Use request.getPackageName() to build the
FQN so the watch target links (it was the sole undefined symbol:
com_codenameone_examples_hellocodenameone_HelloCodenameOneStub_main...). The
watch target now compiles and links on CI.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): target the -Dmain rename at the FQN-mangled Stub source
The duplicate _main (phone Stub int main vs SwiftUI @main) persisted because the
per-file -Dmain rename matched mangle(mainClass)+"Stub.m" (simple name) while
the generated source is the FQN-mangled com_<pkg>_<Main>Stub.m. Reuse mainStub
(now FQN-based) so the rename lands and the watch target links.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): compile error - mainStub was out of scope in applyXcodeSettings
The previous commit referenced mainStub (a local of writeWatchEntry) inside
applyXcodeSettings, so the plugin failed to compile and every job that builds it
went red. Recompute the FQN-mangled phone Stub source name locally in
applyXcodeSettings. Verified the plugin module compiles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(watch): pin the 15 mutable-image/chart goldens to CI's watch rendering
build-ios-watch passed (160 screenshots, 145 matched); the 15 image-variant
graphics tests + chart-time render with slightly different anti-aliasing on the
CI watch runtime than on my local capture (same 416x496 size, correct shapes -
verified). Update those goldens to CI's actual output so the steady-state run is
0 updates / fully green with goldens that match the validation environment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): apply mutable-image transform on watchOS; remove SE skin process
- nativeSetTransformMutableImpl: the code that actually set the mutable
transform (currentMutableTransformSet=YES) was wrapped in #if !TARGET_OS_WATCH,
so rotate/translate/perspective/camera did nothing on the "image" graphics
variants. Add a watch branch building the 2D affine directly.
- Remove the JavaSE watch-simulator-skin machinery (maven/javase/pom.xml skin
generation, tools/watch-skins/, JavaSEPort skin loading) - superseded by the
native iOS watch screenshot pipeline. JavaSEPort.isWatch() now defaults false,
which is correct: only the native watch build splits the graphics grid.
- WATCHOS_PORT.md: correct the bootstrap description - the watch boots the
regular main class's Stub (full app code), it is NOT tree-shaken to watchMain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): bundle the app's runtime resources into the watch target
The watch target shipped with an EMPTY resources phase, so at runtime the CN1
watch app couldn't find the native theme (Resources.open("/iOS7Theme.res")), the
app theme.res/CN1Resource.res, material-design-font.ttf (FontImage glyphs), or
any bundled image -> it fell back to the default look (gray 3D buttons, gray
switches, red badges instead of chevrons) and images failed (black boxes).
Mirror the iOS app target's bundle resources into the watch target, skipping
iOS-only UI/icon assets (.xcassets AppIcon has no watch-applicable content;
.storyboard/.xib are iOS UI). Verified: kotlin.png now renders the flat iOS
native theme (blue button, green switch) matching the iOS golden.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch): render mutable-image text + a real gaussian blur; regen goldens
- nativeDrawStringMutableImpl drew text via the instance method, which on watch
enqueues a SCREEN op instead of drawing into the mutable image's UIGraphics
context -> the text never landed in the image (black box / "only top line").
Draw the string straight into the active context on watch.
- gausianBlurImage returned the input unchanged on watch (no CIFilter). Implement
a 3-pass vImage box convolve (Accelerate) so graphics-gaussian-blur actually
blurs.
- Regenerate scripts/ios/screenshots-watch from the corrected renderer: the old
goldens captured the buggy output (default theme, no transforms, black text,
no blur). Verified locally: kotlin.png = flat iOS native theme, rotate/translate
image variants transform, draw-string-image renders multi-line, gaussian-blur
blurs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(wear): Android Wear OS build support + developer guide wearables chapter
Adds first-class Wear OS support to the Android build: the new android.wear
hint marks the build as a Wear OS app by injecting the watch hardware feature
(android.hardware.type.watch, required) into the manifest, declaring the app
standalone by default (com.google.android.wearable.standalone, opt out via
android.wear.standalone=false), and raising the minimum SDK to the Wear OS 2.0
baseline (API 23). The Codename One Android port renders the UI through its
normal pipeline on the watch, and CN.isWatch() already reports Wear OS via
PackageManager.FEATURE_WATCH. With the hint off the manifest is unchanged.
Adds a Wearables chapter to the developer guide covering both wearable paths:
the native Apple Watch (watchOS) Core Graphics port (watchNative.* hints,
companion vs standalone, supported/unsupported APIs) and the Android Wear OS
build (android.wear), plus CN.isWatch() detection and watch UI design guidance.
The matching BuildDaemon changes (cloud builds) are made in the BuildDaemon
repo: a ported WatchNativeBuilder and the same android.wear manifest logic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch-ci): wait for full screenshot set + replace broken mutable-image goldens
Two fixes to get build-ios-watch green, found by inspecting the failed run's
watch-ui-tests artifact (15 different, 43 missing of ~203):
1. Premature-settling race in run-watch-ui-tests.sh. The capture loop declared
the suite done after the streamed PNG count was merely stable for 24s, then
compared. The watch streams in bursts with multi-second GC/render pauses
between phases (the theme tests arrive in a late burst), so the loop settled
on the partial set and the late screenshots -- received by the WS sink
(logged status=ok) but written to disk after the comparison snapshot --
showed up as false "missing". Now wait until the full golden count has
streamed (preferred), with a generous idle-plateau fallback only when fewer
are produced. This was the cause of all 43 "missing".
2. The 15 "different" were all the mutable-image-backed graphics variants
(fill/draw/stroke-*-image, transform-camera/perspective-image, chart-time).
Inspecting the artifact showed the CI output renders these correctly (filled
triangles/polygons/strokes) while the stored goldens were blank/unfilled --
the goldens had been regenerated locally against a stale core that did not
render the mutable-image path. Replaced those 15 goldens with the verified-
correct CI output.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(docs,spotbugs): pass developer-guide quality gate + drop unbox/rebox
- Wearables.asciidoc: fix the 10 Vale findings (contractions isn't/it's/don't/
aren't/they're, drop "very", de-hyphenate "auto-enables") and the paragraph-
capitalization finding (a paragraph that began with lowercase "and" after a
source block). Verified locally with vale + the paragraph-capitalization
ruby check (both clean) so the "developer guide quality issues" gate passes.
- JavascriptMethodGenerator: drop the (int) casts on the two Integer-keyed
startToBlock lookups SpotBugs flagged (BX_UNBOXING_IMMEDIATELY_REBOXED at the
Jump-target and switch-default lookups) -- the map is Map<Integer,Integer> so
passing the Integer directly avoids the unbox-then-rebox.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(watch-ci): make the screenshot gate strict + sync goldens
The watch gate was lenient: it grepped compare.json for status "mismatch" (the
actual status is "different") so visual diffs never failed the build, and it only
counted "missing_actual" -- so a screenshot that streamed with no golden
("missing_expected") was ignored too. The job therefore went green while the PR
comment still listed 7 different + 6 missing screenshots.
Gate now mirrors the iOS jobs: propagate cn1ss_process_and_report's central
verdict (15 = a screenshot differs/errors vs its golden; 17 = fewer produced
than there are goldens) under CN1SS_FAIL_ON_MISMATCH=1, and additionally fail on
"missing_expected" so a new test cannot land without shipping its golden. The
captured-nothing guard now uses the actual entry count.
Synced the goldens to the watch output so the suite is in sync (209 = 203 + 6):
- updated the 7 "different" goldens (LightweightPickerButtons x4, Sheet slide-up,
TabsTheme dark/light) -- their stored goldens predated the current renderer;
- added 6 goldens that had no reference yet (css-gradients, landscape,
Lottie/SVG animated, SVGStatic, PaletteOverrideTheme_dark).
Verified locally with cn1ss_process_and_report against the synced goldens: 209
equal, 0 different, 0 missing. The goldens need not be pretty (the watch form
factor differs and some tests are not meaningful there) -- they only need to run
and stay in sync, which the strict gate now enforces.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(wear): list wear hints in the build-hints table, clarify scope, add sim shot
Addresses developer-guide gaps for the wearable support:
- Build-hints table (BuildHintSchemaDefaults, which feeds the Control Center):
add the Android Wear category (android.wear, android.wear.standalone) and the
two watchNative hints that were only in the guide (watchNative.displayName,
watchNative.embedCompanion). Also corrected the watchNative.minDeploymentTarget
default text (9.0 -> 10.0) to match the builder.
- Clarify that codename1.watchMain / watchNative.enabled enable ONLY the Apple
Watch (watchOS) build and never produce a Wear OS build implicitly -- Wear OS
is enabled explicitly with android.wear=true; both can be set to target both.
- Add an Apple Watch simulator screenshot (real Core Graphics-rendered CN1 UI in
a watch device frame) to the Apple Watch section.
Verified locally: vale + paragraph-capitalization + asciidoctor all clean on the
chapter, the image resolves and is referenced (unused-image gate), schema compiles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(docs): img/ prefix on the watch screenshot so the website publishes it
The Hugo website republishes the developer guide and copies its img/ tree to
public/developer-guide/img/. The screenshot was referenced as
image::wearables/... (no img/ prefix), so the published HTML pointed at
public/developer-guide/wearables/... which doesn't exist and the website
link/image validator failed. Match the existing convention
(image::img/<dir>/...). Asciidoctor HTML output doesn't check src existence so
this only surfaced in the website validator; the file already lives at
docs/developer-guide/img/wearables/apple-watch-simulator.png.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent 6ff3150 commit 930f8d6
276 files changed
Lines changed: 4111 additions & 147 deletions
File tree
- .github/workflows
- CodenameOne/src/com/codename1
- impl
- ui
- Ports
- Android/src/com/codename1/impl/android
- JavaSE/src/com/codename1/impl/javase
- iOSPort
- nativeSources
- src/com/codename1/impl/ios
- docs/developer-guide
- img/wearables
- maven/codenameone-maven-plugin/src/main/java/com/codename1
- builders
- maven
- scripts
- hellocodenameone/common
- src/main
- java/com/codenameone/examples/hellocodenameone/tests
- kotlin/com/codenameone/examples/hellocodenameone
- ios/screenshots-watch
- vm/ByteCodeTranslator/src/com/codename1/tools/translator
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
| 46 | + | |
44 | 47 | | |
45 | 48 | | |
46 | 49 | | |
| |||
49 | 52 | | |
50 | 53 | | |
51 | 54 | | |
| 55 | + | |
52 | 56 | | |
53 | 57 | | |
54 | 58 | | |
| |||
506 | 510 | | |
507 | 511 | | |
508 | 512 | | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
| 578 | + | |
| 579 | + | |
| 580 | + | |
| 581 | + | |
| 582 | + | |
| 583 | + | |
| 584 | + | |
| 585 | + | |
| 586 | + | |
| 587 | + | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
Lines changed: 11 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5601 | 5601 | | |
5602 | 5602 | | |
5603 | 5603 | | |
| 5604 | + | |
| 5605 | + | |
| 5606 | + | |
| 5607 | + | |
| 5608 | + | |
| 5609 | + | |
| 5610 | + | |
| 5611 | + | |
| 5612 | + | |
| 5613 | + | |
| 5614 | + | |
5604 | 5615 | | |
5605 | 5616 | | |
5606 | 5617 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
891 | 891 | | |
892 | 892 | | |
893 | 893 | | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
894 | 905 | | |
895 | 906 | | |
896 | 907 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4343 | 4343 | | |
4344 | 4344 | | |
4345 | 4345 | | |
| 4346 | + | |
| 4347 | + | |
| 4348 | + | |
| 4349 | + | |
| 4350 | + | |
| 4351 | + | |
| 4352 | + | |
| 4353 | + | |
| 4354 | + | |
| 4355 | + | |
| 4356 | + | |
4346 | 4357 | | |
4347 | 4358 | | |
4348 | 4359 | | |
| |||
Lines changed: 17 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5670 | 5670 | | |
5671 | 5671 | | |
5672 | 5672 | | |
| 5673 | + | |
| 5674 | + | |
| 5675 | + | |
| 5676 | + | |
| 5677 | + | |
| 5678 | + | |
| 5679 | + | |
| 5680 | + | |
| 5681 | + | |
| 5682 | + | |
| 5683 | + | |
| 5684 | + | |
| 5685 | + | |
| 5686 | + | |
5673 | 5687 | | |
5674 | 5688 | | |
5675 | 5689 | | |
| |||
8228 | 8242 | | |
8229 | 8243 | | |
8230 | 8244 | | |
| 8245 | + | |
| 8246 | + | |
| 8247 | + | |
8231 | 8248 | | |
8232 | 8249 | | |
8233 | 8250 | | |
| |||
Lines changed: 100 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
94 | 94 | | |
95 | 95 | | |
96 | 96 | | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
97 | 197 | | |
98 | 198 | | |
99 | 199 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
26 | 30 | | |
| 31 | + | |
27 | 32 | | |
28 | 33 | | |
29 | 34 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
167 | 167 | | |
168 | 168 | | |
169 | 169 | | |
| 170 | + | |
| 171 | + | |
170 | 172 | | |
171 | | - | |
| 173 | + | |
| 174 | + | |
172 | 175 | | |
173 | 176 | | |
174 | 177 | | |
| |||
0 commit comments