From afd27bca10c283de792a9dd4c66ae9ff0b482a9b Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:08:03 +0200 Subject: [PATCH 01/10] Loop back through animation demo forms before waiting for host --- .github/workflows/developer-guide-docs.yml | 2 +- .../AnimationDemosScreenshotTest.java | 305 +++++++++++++++++- 2 files changed, 291 insertions(+), 16 deletions(-) diff --git a/.github/workflows/developer-guide-docs.yml b/.github/workflows/developer-guide-docs.yml index cb1fd62212..15fffffa4f 100644 --- a/.github/workflows/developer-guide-docs.yml +++ b/.github/workflows/developer-guide-docs.yml @@ -51,7 +51,7 @@ jobs: mkdir -p "$HOME/.codenameone" touch "$HOME/.codenameone/guibuilder.jar" cp maven/CodeNameOneBuildClient.jar "$HOME/.codenameone/CodeNameOneBuildClient.jar" - xvfb-run -a mvn -B -ntp -Dgenerate-gui-sources-done=true -pl common -am -f docs/demos/pom.xml install + xvfb-run -a mvn -B -ntp -Dgenerate-gui-sources-done=true -am -f docs/demos/pom.xml install - name: Install ImageMagick for screenshot comparison if: github.event_name != 'pull_request' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true' diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 0bda882b98..054f07fc83 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -4,17 +4,25 @@ import com.codename1.io.Util; import com.codename1.testing.AbstractTest; import com.codename1.testing.TestUtils; +import com.codename1.ui.AnimationManager; +import com.codename1.ui.Button; +import com.codename1.ui.Component; +import com.codename1.ui.Container; import com.codename1.ui.Display; import com.codename1.ui.Form; import com.codename1.ui.Image; +import com.codename1.ui.animations.Motion; import com.codename1.ui.util.ImageIO; import com.codenameone.developerguide.Demo; +import com.codenameone.developerguide.DemoBrowserForm; import com.codenameone.developerguide.DemoRegistry; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -23,9 +31,14 @@ * that external tooling can compare them against the developer guide imagery. */ public class AnimationDemosScreenshotTest extends AbstractTest { - private static final String HOST_TITLE = "Demo Test Host"; + private static final String HOST_TITLE = "Developer Guide Demos"; private static final long FORM_TIMEOUT_MS = 10000L; private static final String STORAGE_PREFIX = "developer-guide.animations."; + private static final int FRAMES_PER_ANIMATION = 6; + private static final long ANIMATION_CAPTURE_TIMEOUT_MS = 2000L; + private static final long ANIMATION_SETTLE_TIMEOUT_MS = 1500L; + private static final int ANIMATION_FRAME_DELAY_MS = 180; + private static final String FRAME_MANIFEST_SUFFIX = "-frames.manifest"; private static final Map SCREENSHOT_NAME_OVERRIDES = createScreenshotNameOverrides(); private static final Set OVERRIDE_FILE_NAMES = new HashSet<>(SCREENSHOT_NAME_OVERRIDES.values()); @@ -36,24 +49,39 @@ public class AnimationDemosScreenshotTest extends AbstractTest { public boolean runTest() throws Exception { clearPreviousScreenshots(); - Form host = new Form(HOST_TITLE); - host.show(); - TestUtils.waitForFormTitle(HOST_TITLE, FORM_TIMEOUT_MS); + boolean previousSlowMotion = Motion.isSlowMotion(); + Motion.setSlowMotion(true); + try { + Form host = new DemoBrowserForm(); + host.show(); + TestUtils.waitForFormTitle(HOST_TITLE, FORM_TIMEOUT_MS); - for (Demo demo : DemoRegistry.getDemos()) { - Form previous = Display.getInstance().getCurrent(); - demo.show(host); - Form demoForm = waitForFormChange(previous); - waitForFormReady(demoForm); + for (Demo demo : DemoRegistry.getDemos()) { + Form previous = Display.getInstance().getCurrent(); + demo.show(host); + Form demoForm = waitForFormChange(previous); + waitForFormReady(demoForm); - Image screenshot = capture(demoForm); - saveScreenshot(storageKeyFor(demo.getTitle()), screenshot); + waitForAnimationsToFinish(demoForm); - host.show(); - waitForHost(host); - } + triggerAnimationIfNeeded(demo, demoForm); + Form activeForm = ensureCurrentFormReady(demoForm); - return true; + if (waitForAnimationStart(activeForm, ANIMATION_CAPTURE_TIMEOUT_MS)) { + captureAnimationFrames(demo, activeForm); + finalizeAnimations(activeForm); + } else { + Image screenshot = capture(activeForm); + saveScreenshot(storageKeyFor(demo.getTitle()), screenshot); + } + + returnToHost(activeForm, host); + } + + return true; + } finally { + Motion.setSlowMotion(previousSlowMotion); + } } private void clearPreviousScreenshots() { @@ -125,6 +153,7 @@ private void waitForFormReady(Form form) { private void waitForHost(Form host) { long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; while (Display.getInstance().getCurrent() != host) { + Display.getInstance().animate(); TestUtils.waitFor(50); if (System.currentTimeMillis() > deadline) { fail("Timed out waiting to return to host form."); @@ -134,6 +163,207 @@ private void waitForHost(Form host) { TestUtils.waitFor(200); } + private void returnToHost(Form demoForm, Form host) { + if (host == null) { + return; + } + + long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; + + if (demoForm != null && demoForm != currentForm()) { + demoForm.showBack(); + } + + while (System.currentTimeMillis() <= deadline) { + Form active = currentForm(); + if (active == host) { + break; + } + + if (active == null) { + host.show(); + } else { + active.showBack(); + } + + TestUtils.waitFor(150); + } + + if (currentForm() != host) { + host.show(); + } + + waitForHost(host); + } + + private Form currentForm() { + Component current = Display.getInstance().getCurrent(); + return (current instanceof Form) ? (Form) current : null; + } + + private void triggerAnimationIfNeeded(Demo demo, Form form) { + if (demo == null || form == null) { + return; + } + + if (demo instanceof LayoutAnimationsDemo) { + clickButton(form, "Fall"); + } else if (demo instanceof UnlayoutAnimationsDemo) { + clickButton(form, "Fall"); + } else if (demo instanceof HiddenComponentDemo) { + clickButton(form, "Hide It"); + } else if (demo instanceof AnimationSynchronicityDemo) { + clickButton(form, "Run Sequence"); + } else if (demo instanceof ReplaceTransitionDemo) { + clickButton(form, "Replace Pending"); + } else if (demo instanceof SlideTransitionsDemo) { + clickButton(form, "Show"); + } else if (demo instanceof BubbleTransitionDemo) { + clickButton(form, "+"); + } else if (demo instanceof SwipeBackSupportDemo) { + clickButton(form, "Open Destination"); + } + } + + private void clickButton(Component root, String text) { + Button button = findButton(root, text); + if (button != null) { + button.pressed(); + button.released(); + TestUtils.waitFor(200); + } + } + + private Button findButton(Component component, String text) { + if (component instanceof Button) { + Button button = (Button) component; + if (text.equals(button.getText())) { + return button; + } + } + + if (component instanceof Form) { + return findButton(((Form) component).getContentPane(), text); + } + + if (component instanceof Container) { + Container container = (Container) component; + int childCount = container.getComponentCount(); + for (int i = 0; i < childCount; i++) { + Button match = findButton(container.getComponentAt(i), text); + if (match != null) { + return match; + } + } + } + + return null; + } + + private Form ensureCurrentFormReady(Form fallback) { + Component current = Display.getInstance().getCurrent(); + if (current instanceof Form) { + Form form = (Form) current; + waitForFormReady(form); + return form; + } + return fallback; + } + + private void waitForAnimationsToFinish(Form form) { + if (form == null) { + return; + } + long deadline = System.currentTimeMillis() + ANIMATION_SETTLE_TIMEOUT_MS; + while (System.currentTimeMillis() <= deadline) { + AnimationManager manager = form.getAnimationManager(); + if (manager == null || !manager.isAnimating()) { + break; + } + form.animate(); + TestUtils.waitFor(50); + } + } + + private void captureAnimationFrames(Demo demo, Form form) throws IOException { + String sanitized = sanitizeFileName(demo.getTitle()); + String baseKey = storageKeyFor(demo.getTitle()); + boolean baseSaved = false; + List frameKeys = new ArrayList<>(FRAMES_PER_ANIMATION); + Image finalFrameImage = null; + + for (int frameIndex = 0; frameIndex < FRAMES_PER_ANIMATION; frameIndex++) { + if (!isAnimating(form) && frameIndex == 0) { + break; + } + + Image frameImage = capture(form); + if (!baseSaved) { + saveScreenshot(baseKey, frameImage); + baseSaved = true; + } + + String frameKey = stageStorageKeyFor(sanitized, frameIndex); + saveScreenshot(frameKey, frameImage); + frameKeys.add(frameKey); + finalFrameImage = frameImage; + + if (frameIndex >= FRAMES_PER_ANIMATION - 1) { + break; + } + + if (!advanceAnimation(form)) { + finalFrameImage = capture(form); + break; + } + } + + if (!baseSaved) { + Image screenshot = capture(form); + saveScreenshot(baseKey, screenshot); + finalFrameImage = screenshot; + } + + if (finalFrameImage == null) { + finalFrameImage = capture(form); + } + + while (frameKeys.size() < FRAMES_PER_ANIMATION) { + String frameKey = stageStorageKeyFor(sanitized, frameKeys.size()); + saveScreenshot(frameKey, finalFrameImage); + frameKeys.add(frameKey); + } + + if (!frameKeys.isEmpty()) { + recordFrameManifest(sanitized, frameKeys); + } + } + + private String stageStorageKeyFor(String sanitizedTitle, int frame) { + return STORAGE_PREFIX + sanitizedTitle + "-frame-" + (frame + 1) + ".png"; + } + + private void recordFrameManifest(String sanitizedTitle, List frameKeys) { + if (sanitizedTitle == null || frameKeys == null || frameKeys.isEmpty()) { + return; + } + + String manifestKey = STORAGE_PREFIX + sanitizedTitle + FRAME_MANIFEST_SUFFIX; + storage.deleteStorageFile(manifestKey); + + Map manifest = new HashMap<>(); + manifest.put("frames", new ArrayList<>(frameKeys)); + + List comparableFrames = new ArrayList<>(2); + comparableFrames.add(Integer.valueOf(0)); + if (frameKeys.size() > 1) { + comparableFrames.add(Integer.valueOf(frameKeys.size() - 1)); + } + manifest.put("compareFrames", comparableFrames); + + storage.writeObject(manifestKey, manifest); + } + private static Map createScreenshotNameOverrides() { Map map = new HashMap<>(); map.put("Layout Animations", "layout-animation-1.png"); @@ -148,6 +378,51 @@ private String sanitizeFileName(String value) { return sanitized.isEmpty() ? "demo-screenshot" : sanitized; } + private void finalizeAnimations(Form form) { + if (form == null) { + return; + } + form.animate(); + waitForAnimationsToFinish(form); + } + + private boolean waitForAnimationStart(Form form, long timeoutMs) { + if (form == null) { + return false; + } + long deadline = System.currentTimeMillis() + timeoutMs; + while (System.currentTimeMillis() <= deadline) { + if (isAnimating(form)) { + return true; + } + form.animate(); + TestUtils.waitFor(50); + } + return isAnimating(form); + } + + private boolean isAnimating(Form form) { + if (form == null) { + return false; + } + AnimationManager manager = form.getAnimationManager(); + return manager != null && manager.isAnimating(); + } + + private boolean advanceAnimation(Form form) { + if (form == null) { + return false; + } + long deadline = System.currentTimeMillis() + ANIMATION_FRAME_DELAY_MS; + boolean animating = isAnimating(form); + while (System.currentTimeMillis() <= deadline && animating) { + form.animate(); + TestUtils.waitFor(20); + animating = isAnimating(form); + } + return animating; + } + @Override public boolean shouldExecuteOnEDT() { return true; From 3ffb9b21706840614e5bfe4ce963def76f421c74 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:47:09 +0200 Subject: [PATCH 02/10] Dispose dialogs while returning to demo host --- .../AnimationDemosScreenshotTest.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 054f07fc83..a70cee45b9 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -8,6 +8,7 @@ import com.codename1.ui.Button; import com.codename1.ui.Component; import com.codename1.ui.Container; +import com.codename1.ui.Dialog; import com.codename1.ui.Display; import com.codename1.ui.Form; import com.codename1.ui.Image; @@ -171,7 +172,7 @@ private void returnToHost(Form demoForm, Form host) { long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; if (demoForm != null && demoForm != currentForm()) { - demoForm.showBack(); + unwindForm(demoForm, host); } while (System.currentTimeMillis() <= deadline) { @@ -183,10 +184,11 @@ private void returnToHost(Form demoForm, Form host) { if (active == null) { host.show(); } else { - active.showBack(); + unwindForm(active, host); } - TestUtils.waitFor(150); + Display.getInstance().animate(); + TestUtils.waitFor(120); } if (currentForm() != host) { @@ -196,6 +198,23 @@ private void returnToHost(Form demoForm, Form host) { waitForHost(host); } + private void unwindForm(Form form, Form host) { + if (form == null) { + return; + } + + if (form instanceof Dialog) { + ((Dialog) form).dispose(); + return; + } + + if (form == host) { + return; + } + + form.showBack(); + } + private Form currentForm() { Component current = Display.getInstance().getCurrent(); return (current instanceof Form) ? (Form) current : null; From c8dbe291d9846433b1553ea0528da153f940e3e4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 26 Oct 2025 21:15:31 +0200 Subject: [PATCH 03/10] Add Xalan serializer dependency for demo tests --- docs/demos/common/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/demos/common/pom.xml b/docs/demos/common/pom.xml index 6b463e867b..6b22111373 100644 --- a/docs/demos/common/pom.xml +++ b/docs/demos/common/pom.xml @@ -19,6 +19,12 @@ provided + + xalan + serializer + 2.7.2 + + From 986bf025fc348160f911512cef406b3f6168c08c Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 27 Oct 2025 05:13:48 +0200 Subject: [PATCH 04/10] Use form animation helpers in demo screenshot test --- docs/demos/common/pom.xml | 6 ------ .../animations/AnimationDemosScreenshotTest.java | 11 +++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/demos/common/pom.xml b/docs/demos/common/pom.xml index 6b22111373..6b463e867b 100644 --- a/docs/demos/common/pom.xml +++ b/docs/demos/common/pom.xml @@ -19,12 +19,6 @@ provided - - xalan - serializer - 2.7.2 - - diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index a70cee45b9..4f9a1f68c9 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -154,7 +154,7 @@ private void waitForFormReady(Form form) { private void waitForHost(Form host) { long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; while (Display.getInstance().getCurrent() != host) { - Display.getInstance().animate(); + animateCurrentForm(); TestUtils.waitFor(50); if (System.currentTimeMillis() > deadline) { fail("Timed out waiting to return to host form."); @@ -187,7 +187,7 @@ private void returnToHost(Form demoForm, Form host) { unwindForm(active, host); } - Display.getInstance().animate(); + animateCurrentForm(); TestUtils.waitFor(120); } @@ -220,6 +220,13 @@ private Form currentForm() { return (current instanceof Form) ? (Form) current : null; } + private void animateCurrentForm() { + Form current = currentForm(); + if (current != null) { + current.animate(); + } + } + private void triggerAnimationIfNeeded(Demo demo, Form form) { if (demo == null || form == null) { return; From d871a5d2c440ac5169d65bdc1de881fba32511f4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:18:33 +0200 Subject: [PATCH 05/10] Handle active dialogs when returning to host --- .../animations/AnimationDemosScreenshotTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 4f9a1f68c9..1f30d2dde6 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -176,6 +176,14 @@ private void returnToHost(Form demoForm, Form host) { } while (System.currentTimeMillis() <= deadline) { + Dialog activeDialog = Dialog.getActiveDialog(); + if (activeDialog != null) { + activeDialog.dispose(); + animateCurrentForm(); + TestUtils.waitFor(120); + continue; + } + Form active = currentForm(); if (active == host) { break; @@ -224,6 +232,12 @@ private void animateCurrentForm() { Form current = currentForm(); if (current != null) { current.animate(); + return; + } + + Dialog dialog = Dialog.getActiveDialog(); + if (dialog != null) { + dialog.animate(); } } From 1d6d08f9c9511c5d121d65eddc34db7bf4296aaf Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 27 Oct 2025 07:55:27 +0200 Subject: [PATCH 06/10] Fix dialog handling without getActiveDialog --- .../animations/AnimationDemosScreenshotTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 1f30d2dde6..8b384221cc 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -176,7 +176,7 @@ private void returnToHost(Form demoForm, Form host) { } while (System.currentTimeMillis() <= deadline) { - Dialog activeDialog = Dialog.getActiveDialog(); + Dialog activeDialog = activeDialog(); if (activeDialog != null) { activeDialog.dispose(); animateCurrentForm(); @@ -228,6 +228,11 @@ private Form currentForm() { return (current instanceof Form) ? (Form) current : null; } + private Dialog activeDialog() { + Component current = Display.getInstance().getCurrent(); + return (current instanceof Dialog) ? (Dialog) current : null; + } + private void animateCurrentForm() { Form current = currentForm(); if (current != null) { @@ -235,7 +240,7 @@ private void animateCurrentForm() { return; } - Dialog dialog = Dialog.getActiveDialog(); + Dialog dialog = activeDialog(); if (dialog != null) { dialog.animate(); } From c24ee1ae98877d538405f367fa742bfc2d2d94b9 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 27 Oct 2025 17:52:50 +0200 Subject: [PATCH 07/10] Adjust animation test host return timing --- .../AnimationDemosScreenshotTest.java | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 8b384221cc..daab5af81f 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -152,15 +152,7 @@ private void waitForFormReady(Form form) { } private void waitForHost(Form host) { - long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; - while (Display.getInstance().getCurrent() != host) { - animateCurrentForm(); - TestUtils.waitFor(50); - if (System.currentTimeMillis() > deadline) { - fail("Timed out waiting to return to host form."); - break; - } - } + TestUtils.waitForFormTitle(HOST_TITLE, FORM_TIMEOUT_MS); TestUtils.waitFor(200); } @@ -170,40 +162,50 @@ private void returnToHost(Form demoForm, Form host) { } long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; - - if (demoForm != null && demoForm != currentForm()) { - unwindForm(demoForm, host); + boolean restoreSlowMotion = Motion.isSlowMotion(); + if (restoreSlowMotion) { + Motion.setSlowMotion(false); } - while (System.currentTimeMillis() <= deadline) { - Dialog activeDialog = activeDialog(); - if (activeDialog != null) { - activeDialog.dispose(); - animateCurrentForm(); - TestUtils.waitFor(120); - continue; + try { + if (demoForm != null && demoForm != currentForm()) { + unwindForm(demoForm, host); } - Form active = currentForm(); - if (active == host) { - break; + while (System.currentTimeMillis() <= deadline) { + Dialog activeDialog = activeDialog(); + if (activeDialog != null) { + activeDialog.dispose(); + animateCurrentForm(); + TestUtils.waitFor(120); + continue; + } + + Form active = currentForm(); + if (active == host) { + break; + } + + if (active == null) { + host.show(); + } else { + unwindForm(active, host); + } + + animateCurrentForm(); + TestUtils.waitFor(120); } - if (active == null) { + if (currentForm() != host) { host.show(); - } else { - unwindForm(active, host); } - animateCurrentForm(); - TestUtils.waitFor(120); - } - - if (currentForm() != host) { - host.show(); + waitForHost(host); + } finally { + if (restoreSlowMotion) { + Motion.setSlowMotion(true); + } } - - waitForHost(host); } private void unwindForm(Form form, Form host) { From 062040e3f74985b7e8266d004f44382076e34fe9 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:13:03 +0200 Subject: [PATCH 08/10] Improve demo form detection for animation screenshots --- .../AnimationDemosScreenshotTest.java | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index daab5af81f..3309f7917e 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -12,6 +12,7 @@ import com.codename1.ui.Display; import com.codename1.ui.Form; import com.codename1.ui.Image; +import com.codename1.ui.Label; import com.codename1.ui.animations.Motion; import com.codename1.ui.util.ImageIO; import com.codenameone.developerguide.Demo; @@ -58,9 +59,8 @@ public boolean runTest() throws Exception { TestUtils.waitForFormTitle(HOST_TITLE, FORM_TIMEOUT_MS); for (Demo demo : DemoRegistry.getDemos()) { - Form previous = Display.getInstance().getCurrent(); demo.show(host); - Form demoForm = waitForFormChange(previous); + Form demoForm = waitForDemoForm(host); waitForFormReady(demoForm); waitForAnimationsToFinish(demoForm); @@ -129,16 +129,32 @@ private Image capture(Form form) { return screenshot; } - private Form waitForFormChange(Form previous) { + private Form waitForDemoForm(Form host) { long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; - while (Display.getInstance().getCurrent() == previous) { + while (System.currentTimeMillis() <= deadline) { + Component current = Display.getInstance().getCurrent(); + Form form = (current instanceof Form) ? (Form) current : null; + if (form != null && form != host && !HOST_TITLE.equals(formTitle(form))) { + return form; + } + animateCurrentForm(); TestUtils.waitFor(50); - if (System.currentTimeMillis() > deadline) { - fail("Timed out waiting for demo form to appear."); - break; + } + fail("Timed out waiting for demo form to appear."); + return host; + } + + private String formTitle(Form form) { + if (form == null) { + return null; + } + if (form.getToolbar() != null) { + Component titleComponent = form.getToolbar().getTitleComponent(); + if (titleComponent instanceof Label) { + return ((Label) titleComponent).getText(); } } - return Display.getInstance().getCurrent(); + return form.getTitle(); } private void waitForFormReady(Form form) { From fcecb5c61997fa8cc1b138277b8f181821ca54b4 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Tue, 28 Oct 2025 04:26:12 +0200 Subject: [PATCH 09/10] Use CN current form when locating demos --- .../animations/AnimationDemosScreenshotTest.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 3309f7917e..2281dcf421 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -13,6 +13,7 @@ import com.codename1.ui.Form; import com.codename1.ui.Image; import com.codename1.ui.Label; +import com.codename1.ui.CN; import com.codename1.ui.animations.Motion; import com.codename1.ui.util.ImageIO; import com.codenameone.developerguide.Demo; @@ -132,8 +133,7 @@ private Image capture(Form form) { private Form waitForDemoForm(Form host) { long deadline = System.currentTimeMillis() + FORM_TIMEOUT_MS; while (System.currentTimeMillis() <= deadline) { - Component current = Display.getInstance().getCurrent(); - Form form = (current instanceof Form) ? (Form) current : null; + Form form = currentForm(); if (form != null && form != host && !HOST_TITLE.equals(formTitle(form))) { return form; } @@ -243,7 +243,14 @@ private void unwindForm(Form form, Form host) { private Form currentForm() { Component current = Display.getInstance().getCurrent(); - return (current instanceof Form) ? (Form) current : null; + if (current instanceof Form) { + return (Form) current; + } + Form cnForm = CN.getCurrentForm(); + if (cnForm instanceof Dialog) { + return null; + } + return cnForm; } private Dialog activeDialog() { From 206600e9a677bbc971265124be5ee1b7a1e6af8f Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Tue, 28 Oct 2025 07:36:16 +0200 Subject: [PATCH 10/10] Adjust slow motion usage during animation captures --- .../AnimationDemosScreenshotTest.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java index 2281dcf421..aa484b1c38 100644 --- a/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java +++ b/docs/demos/common/src/test/java/com/codenameone/developerguide/animations/AnimationDemosScreenshotTest.java @@ -53,13 +53,14 @@ public boolean runTest() throws Exception { clearPreviousScreenshots(); boolean previousSlowMotion = Motion.isSlowMotion(); - Motion.setSlowMotion(true); + Motion.setSlowMotion(false); try { Form host = new DemoBrowserForm(); host.show(); TestUtils.waitForFormTitle(HOST_TITLE, FORM_TIMEOUT_MS); for (Demo demo : DemoRegistry.getDemos()) { + Motion.setSlowMotion(false); demo.show(host); Form demoForm = waitForDemoForm(host); waitForFormReady(demoForm); @@ -69,12 +70,17 @@ public boolean runTest() throws Exception { triggerAnimationIfNeeded(demo, demoForm); Form activeForm = ensureCurrentFormReady(demoForm); - if (waitForAnimationStart(activeForm, ANIMATION_CAPTURE_TIMEOUT_MS)) { - captureAnimationFrames(demo, activeForm); - finalizeAnimations(activeForm); - } else { - Image screenshot = capture(activeForm); - saveScreenshot(storageKeyFor(demo.getTitle()), screenshot); + Motion.setSlowMotion(true); + try { + if (waitForAnimationStart(activeForm, ANIMATION_CAPTURE_TIMEOUT_MS)) { + captureAnimationFrames(demo, activeForm); + finalizeAnimations(activeForm); + } else { + Image screenshot = capture(activeForm); + saveScreenshot(storageKeyFor(demo.getTitle()), screenshot); + } + } finally { + Motion.setSlowMotion(false); } returnToHost(activeForm, host);