diff --git a/CodenameOne/src/com/codename1/capture/VideoCaptureConstraints.java b/CodenameOne/src/com/codename1/capture/VideoCaptureConstraints.java index ad4dc3dda21..3a3f864e678 100644 --- a/CodenameOne/src/com/codename1/capture/VideoCaptureConstraints.java +++ b/CodenameOne/src/com/codename1/capture/VideoCaptureConstraints.java @@ -630,6 +630,13 @@ public boolean isSupported() { /// /// - #preferredQuality(int) public boolean isQualitySupported() { + // Resolve first. Every getter of a resolved value builds, and so do + // isSizeSupported() and isMaxLengthSupported(); these last two predicates + // did not, so asking one of them FIRST compared the caller's preference + // against a `quality` field the platform had never filled in, and answered + // "unsupported" for a constraint the platform honours. isSupported() + // masked it, because isSizeSupported() runs first and builds. + build(); return preferredQuality == 0 || quality == preferredQuality; } @@ -647,6 +654,8 @@ public boolean isQualitySupported() { /// /// - #getPreferredMaxFileSize() public boolean isMaxFileSizeSupported() { + // Resolve first, for the same reason as isQualitySupported() above. + build(); return preferredMaxFileSize == 0 || maxFileSize == preferredMaxFileSize; } diff --git a/Ports/JavaScriptPort/src/main/java/com/codename1/impl/html5/videojs/JSVideoCaptureConstraintsCompiler.java b/Ports/JavaScriptPort/src/main/java/com/codename1/impl/html5/videojs/JSVideoCaptureConstraintsCompiler.java index e952809439f..6c6d6ddb024 100644 --- a/Ports/JavaScriptPort/src/main/java/com/codename1/impl/html5/videojs/JSVideoCaptureConstraintsCompiler.java +++ b/Ports/JavaScriptPort/src/main/java/com/codename1/impl/html5/videojs/JSVideoCaptureConstraintsCompiler.java @@ -37,6 +37,11 @@ public VideoCaptureConstraints compile(VideoCaptureConstraints vcc) { VideoCaptureConstraints out = new VideoCaptureConstraints(); int prefW = vcc.getPreferredWidth(); int prefH = vcc.getPreferredHeight(); + // The size this platform uses to express the requested quality, or 0 when the + // caller asked for no quality or pinned the size itself. Kept so the negotiated + // result below can be compared against what the quality actually asked for. + int qualityW = 0; + int qualityH = 0; if (vcc.getPreferredQuality() != 0 && prefW == 0 && prefH == 0) { switch (vcc.getPreferredQuality()) { case VideoCaptureConstraints.QUALITY_LOW: @@ -48,12 +53,23 @@ public VideoCaptureConstraints compile(VideoCaptureConstraints vcc) { prefH = 720; break; } - out.preferredQuality(0); + qualityW = prefW; + qualityH = prefH; } if (prefW > 0 || prefH > 0) { MediaResult res = new MediaTool().query(prefW, prefH); out.preferredWidth(res.getWidth()) .preferredHeight(res.getHeight()); + // Report the quality back only when the device actually gave us the size that + // quality maps to. Leaving the resolved quality at 0 unconditionally, as this + // did, made isQualitySupported() answer false for every caller that asked for + // QUALITY_LOW or QUALITY_HIGH -- the resolved value differed from the nonzero + // preferred one -- even though the capture was constrained exactly as asked. + // getUserMedia negotiates, so a device that cannot reach 1280x720 returns + // something smaller, and then the quality genuinely was not honored. + if (qualityW > 0 && res.getWidth() == qualityW && res.getHeight() == qualityH) { + out.preferredQuality(vcc.getPreferredQuality()); + } } out.preferredMaxLength(vcc.getPreferredMaxLength()); return out; diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava001Snippet.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava001Snippet.java index 180075e89e8..58b44c1b024 100644 --- a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava001Snippet.java +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava001Snippet.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ package com.codenameone.developerguide.snippets.generated; import com.codename1.gpu.*; @@ -57,18 +79,18 @@ class ComponentSelectorJava001Snippet { Resources theme; void snippet() throws Exception { // tag::component-selector-java-001[] - // null + // ... - Button slideUp = $(new Button("Slide Up")) // - .setIcon(FontImage.MATERIAL_EXPAND_LESS) // - .addActionListener(e->{ // - $(e) // - .getParent() // - .find(">*") // - .slideUpAndWait(1000) // - .slideDownAndWait(1000); // + Button slideUp = $(new Button("Slide Up")) // <1> + .setIcon(FontImage.MATERIAL_EXPAND_LESS) // <2> + .addActionListener(e->{ // <3> + $(e) // <4> + .getParent() // <5> + .find(">*") // <6> + .slideUpAndWait(1000) // <7> + .slideDownAndWait(1000); // <8> }) - .asComponent(Button.class); // + .asComponent(Button.class); // <9> // end::component-selector-java-001[] } } diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava007Snippet.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava007Snippet.java new file mode 100644 index 00000000000..e37ee3ced65 --- /dev/null +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava007Snippet.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.codenameone.developerguide.snippets.generated; + +import com.codename1.gpu.*; +import com.codename1.ui.*; +import com.codename1.ui.animations.*; +import com.codename1.ui.events.*; +import com.codename1.ui.geom.*; +import com.codename1.ui.layouts.*; +import com.codename1.ui.list.*; +import com.codename1.ui.plaf.*; +import com.codename1.ui.util.*; +import com.codename1.components.*; +import com.codename1.charts.models.*; +import com.codename1.charts.renderers.*; +import com.codename1.charts.views.*; +import com.codename1.capture.*; +import com.codename1.io.*; +import com.codename1.l10n.*; +import com.codename1.location.*; +import com.codename1.maps.*; +import com.codename1.media.*; +import com.codename1.messaging.*; +import com.codename1.payment.*; +import com.codename1.processing.*; +import com.codename1.properties.*; +import com.codename1.push.*; +import com.codename1.security.*; +import com.codename1.social.*; +import com.codename1.ui.spinner.*; +import java.io.*; +import java.util.*; +import static com.codename1.ui.ComponentSelector.$; + +class ComponentSelectorJava007Snippet { + + Object context; + Object url; + Object value; + Object body; + Object event; + String apiKey = "test-key"; + String myHttpsURL = "https://example.com"; + java.util.List validKeysList = new java.util.ArrayList<>(); + Image myImage; + Graphics graphics; + Graphics g; + GraphicsDevice device; + Form form; + Form hi; + Container cnt; + Container myForm; + Component component; + Button button; + MultiButton myMultiButton; + Label label; + BrowserComponent browserComponent; + Resources theme; + void snippet() throws Exception { + // tag::component-selector-java-007[] + Button replace = $(new Button("Replace Fade/Slide")) + .setIcon(FontImage.MATERIAL_REDEEM) + .addActionListener(e->{ + $(e).getParent() + .find(">*") // <1> + .replaceAndWait(c->{ // <2> + return $(new Label("Replacement")) // <3> + .putClientProperty("origComponent", c) // <4> + .asComponent(); + }, CommonTransitions.createFade(1000)) // <5> + .replaceAndWait(c->{ + Component orig = (Component)c.getClientProperty("origComponent"); + if (orig != null) { + c.putClientProperty("origComponent", null); + return orig; // <6> + } + return c; + }, CommonTransitions.createCover(CommonTransitions.SLIDE_HORIZONTAL, false, 1000)); // <7> + }) + .asComponent(Button.class); + // end::component-selector-java-007[] + } +} diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava001Snippet.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava001Snippet.java new file mode 100644 index 00000000000..2a214471e85 --- /dev/null +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava001Snippet.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.codenameone.developerguide.snippets.generated; + +import com.codename1.gpu.*; +import com.codename1.ui.*; +import com.codename1.ui.animations.*; +import com.codename1.ui.events.*; +import com.codename1.ui.geom.*; +import com.codename1.ui.layouts.*; +import com.codename1.ui.list.*; +import com.codename1.ui.plaf.*; +import com.codename1.ui.util.*; +import com.codename1.components.*; +import com.codename1.charts.models.*; +import com.codename1.charts.renderers.*; +import com.codename1.charts.views.*; +import com.codename1.capture.*; +import com.codename1.io.*; +import com.codename1.l10n.*; +import com.codename1.location.*; +import com.codename1.maps.*; +import com.codename1.media.*; +import com.codename1.messaging.*; +import com.codename1.payment.*; +import com.codename1.processing.*; +import com.codename1.properties.*; +import com.codename1.push.*; +import com.codename1.security.*; +import com.codename1.social.*; +import com.codename1.ui.spinner.*; +import java.io.*; +import java.util.*; + + +class VideoCaptureConstraintsJava001Snippet { + + Object context; + Object url; + Object value; + Object body; + Object event; + String apiKey = "test-key"; + String myHttpsURL = "https://example.com"; + java.util.List validKeysList = new java.util.ArrayList<>(); + Image myImage; + Graphics graphics; + Graphics g; + GraphicsDevice device; + Form form; + Form hi; + Container cnt; + Container myForm; + Component component; + Button button; + MultiButton myMultiButton; + Label label; + BrowserComponent browserComponent; + Resources theme; + void snippet() throws Exception { + // tag::video-capture-constraints-java-001[] + // The original wrote "new VideoCaptureConstraint()" -- a class that does + // not exist. Corrected while restoring it: a snippet that cannot compile is + // worse than no snippet. + VideoCaptureConstraints cnst = new VideoCaptureConstraints() + .preferredQuality(VideoCaptureConstraints.QUALITY_LOW) + .preferredMaxLength(5); + // end::video-capture-constraints-java-001[] + } +} diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava002Snippet.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava002Snippet.java new file mode 100644 index 00000000000..8bb96ee9ffa --- /dev/null +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava002Snippet.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.codenameone.developerguide.snippets.generated; + +import com.codename1.gpu.*; +import com.codename1.ui.*; +import com.codename1.ui.animations.*; +import com.codename1.ui.events.*; +import com.codename1.ui.geom.*; +import com.codename1.ui.layouts.*; +import com.codename1.ui.list.*; +import com.codename1.ui.plaf.*; +import com.codename1.ui.util.*; +import com.codename1.components.*; +import com.codename1.charts.models.*; +import com.codename1.charts.renderers.*; +import com.codename1.charts.views.*; +import com.codename1.capture.*; +import com.codename1.io.*; +import com.codename1.l10n.*; +import com.codename1.location.*; +import com.codename1.maps.*; +import com.codename1.media.*; +import com.codename1.messaging.*; +import com.codename1.payment.*; +import com.codename1.processing.*; +import com.codename1.properties.*; +import com.codename1.push.*; +import com.codename1.security.*; +import com.codename1.social.*; +import com.codename1.ui.spinner.*; +import java.io.*; +import java.util.*; + + +class VideoCaptureConstraintsJava002Snippet { + + Object context; + Object url; + Object value; + Object body; + Object event; + String apiKey = "test-key"; + String myHttpsURL = "https://example.com"; + java.util.List validKeysList = new java.util.ArrayList<>(); + Image myImage; + Graphics graphics; + Graphics g; + GraphicsDevice device; + Form form; + Form hi; + Container cnt; + Container myForm; + Component component; + Button button; + MultiButton myMultiButton; + Label label; + BrowserComponent browserComponent; + Resources theme; + VideoCaptureConstraints cnst; + + void snippet() throws Exception { + // tag::video-capture-constraints-java-002[] + String videoPath = Capture.captureVideo(cnst); + // end::video-capture-constraints-java-002[] + } +} diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava003Snippet.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava003Snippet.java new file mode 100644 index 00000000000..02d12bb7e2a --- /dev/null +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava003Snippet.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.codenameone.developerguide.snippets.generated; + +import com.codename1.gpu.*; +import com.codename1.ui.*; +import com.codename1.ui.animations.*; +import com.codename1.ui.events.*; +import com.codename1.ui.geom.*; +import com.codename1.ui.layouts.*; +import com.codename1.ui.list.*; +import com.codename1.ui.plaf.*; +import com.codename1.ui.util.*; +import com.codename1.components.*; +import com.codename1.charts.models.*; +import com.codename1.charts.renderers.*; +import com.codename1.charts.views.*; +import com.codename1.capture.*; +import com.codename1.io.*; +import com.codename1.l10n.*; +import com.codename1.location.*; +import com.codename1.maps.*; +import com.codename1.media.*; +import com.codename1.messaging.*; +import com.codename1.payment.*; +import com.codename1.processing.*; +import com.codename1.properties.*; +import com.codename1.push.*; +import com.codename1.security.*; +import com.codename1.social.*; +import com.codename1.ui.spinner.*; +import java.io.*; +import java.util.*; + + +class VideoCaptureConstraintsJava003Snippet { + + Object context; + Object url; + Object value; + Object body; + Object event; + String apiKey = "test-key"; + String myHttpsURL = "https://example.com"; + java.util.List validKeysList = new java.util.ArrayList<>(); + Image myImage; + Graphics graphics; + Graphics g; + GraphicsDevice device; + Form form; + Form hi; + Container cnt; + Container myForm; + Component component; + Button button; + MultiButton myMultiButton; + Label label; + BrowserComponent browserComponent; + Resources theme; + VideoCaptureConstraints cnst; + + void snippet() throws Exception { + // tag::video-capture-constraints-java-003[] + if (cnst.isMaxLengthSupported()) { + // The max length constraint we specified is supported on this platform. + } else { + // It is not. Check the effective value to see whether it is partially + // supported. + int effectiveMaxLength = cnst.getMaxLength(); + if (effectiveMaxLength == 0) { + // Not supported at all: the user can capture without a duration limit. + } else { + // Set to a different value than preferredMaxLength asked for, so the + // platform is at least trying to accommodate us. + } + } + // end::video-capture-constraints-java-003[] + } +} diff --git a/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava005Snippet.java b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava005Snippet.java new file mode 100644 index 00000000000..f5d47f1434e --- /dev/null +++ b/docs/demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava005Snippet.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ +package com.codenameone.developerguide.snippets.generated; + +import com.codename1.gpu.*; +import com.codename1.ui.*; +import com.codename1.ui.animations.*; +import com.codename1.ui.events.*; +import com.codename1.ui.geom.*; +import com.codename1.ui.layouts.*; +import com.codename1.ui.list.*; +import com.codename1.ui.plaf.*; +import com.codename1.ui.util.*; +import com.codename1.components.*; +import com.codename1.charts.models.*; +import com.codename1.charts.renderers.*; +import com.codename1.charts.views.*; +import com.codename1.capture.*; +import com.codename1.io.*; +import com.codename1.l10n.*; +import com.codename1.location.*; +import com.codename1.maps.*; +import com.codename1.media.*; +import com.codename1.messaging.*; +import com.codename1.payment.*; +import com.codename1.processing.*; +import com.codename1.properties.*; +import com.codename1.push.*; +import com.codename1.security.*; +import com.codename1.social.*; +import com.codename1.ui.spinner.*; +import java.io.*; +import java.util.*; + + +class VideoCaptureConstraintsJava005Snippet { + + Object context; + Object url; + Object value; + Object body; + Object event; + String apiKey = "test-key"; + String myHttpsURL = "https://example.com"; + java.util.List validKeysList = new java.util.ArrayList<>(); + Image myImage; + Graphics graphics; + Graphics g; + GraphicsDevice device; + Form form; + Form hi; + Container cnt; + Container myForm; + Component component; + Button button; + MultiButton myMultiButton; + Label label; + BrowserComponent browserComponent; + Resources theme; + VideoCaptureConstraints cnst; + + void snippet() throws Exception { + // tag::video-capture-constraints-java-005[] + if (cnst.isSizeSupported()) { + // This platform supports the constraint, so the captured video will be + // exactly 320x240. + } else { + // Not supported -- see whether the platform will get close. + int effectiveWidth = cnst.getWidth(); + int effectiveHeight = cnst.getHeight(); + int quality = cnst.getQuality(); + if (effectiveWidth == 0 && effectiveHeight == 0) { + // No control over width and height. In many cases the platform will + // approximate with the quality setting instead. + if (quality != 0) { + // Quality was set for us. Since 320x240 is small, it would + // probably be QUALITY_LOW. + } + } else { + // Could not capture at 320x240, but supplied the closest size it can. + } + } + // end::video-capture-constraints-java-005[] + } +} diff --git a/docs/developer-guide/About-This-Guide.asciidoc b/docs/developer-guide/About-This-Guide.asciidoc index 831222c4c9a..4810d3e981e 100644 --- a/docs/developer-guide/About-This-Guide.asciidoc +++ b/docs/developer-guide/About-This-Guide.asciidoc @@ -3,19 +3,25 @@ toc::[] [preface] == Preface -This developer guide comes directly from the `docs` directory of the https://github.com/codenameone/CodenameOne/[Codename One Git repository]. The documentation is written in AsciiDoc, reviewed through pull requests, and published from the main branch to several targets. +This developer guide comes directly from the `docs` directory of the https://github.com/codenameone/CodenameOne/[Codename One Git repository]. The documentation is written in AsciiDoc and published from the main branch to several targets. -=== How to contribute updates +=== Where else to look -To contribute updates, clone the repository, create a feature branch, and edit the AsciiDoc files in `docs/developer-guide`. Follow the steps in the link:https://github.com/codenameone/CodenameOne/blob/master/CONTRIBUTING.md[CONTRIBUTING guidelines] to open a GitHub pull request (PR) instead of using the deprecated community wiki. Continuous integration lints and builds each PR automatically. A maintainer then reviews the PR before merging it. After the merge, the content appears in the web manual at https://www.codenameone.com/manual/ and in the downloadable PDF at https://www.codenameone.com/files/developer-guide.pdf[https://www.codenameone.com/files/developer-guide.pdf]. From time to time, major revisions are collected for print-on-demand distribution. +This guide is the conceptual and tutorial reference. These resources cover the rest: -This guide focuses on tutorial and conceptual material. The complete API reference is available in the https://www.codenameone.com/javadoc/[Codename One Javadoc]. The framework source code and this manual live side by side in Git, so documentation and code improvements follow the same contribution workflow. +* https://www.codenameone.com/javadoc/[Codename One Javadoc] -- the complete API reference. +* https://www.codenameone.com/developer-guide/[Web edition of this guide] and the + https://www.codenameone.com/files/developer-guide.pdf[downloadable PDF]. +* https://www.codenameone.com/how-do-i/["`How Do I?`" video tutorials] -- short screencasts for common tasks. +* https://www.codenameone.com/blog/[The Codename One blog] -- release notes and deep dives. +* https://www.codenameone.com/discussion-forum/[The community discussion forum] -- questions and answers. +* https://github.com/codenameone/CodenameOne/[The Codename One repository] -- source and issue tracker. <<< **Authors** -This document includes content from contributors and community wiki edits. If you edit pages in the guide, add your name here in alphabetical order by surname: +This document includes content from the following contributors and from earlier community wiki edits: - https://github.com/shai-almog[Shai Almog] - https://github.com/Isborg[Ismael Baum] diff --git a/docs/developer-guide/Accessibility-Semantics.asciidoc b/docs/developer-guide/Accessibility-Semantics.asciidoc index e61be68d285..739941cf655 100644 --- a/docs/developer-guide/Accessibility-Semantics.asciidoc +++ b/docs/developer-guide/Accessibility-Semantics.asciidoc @@ -1,10 +1,10 @@ -= Accessibility Semantics +== Accessibility Semantics Codename One components are lightweight: they're painted by Codename One instead of being represented by a native widget on every platform. The accessibility semantics API builds an explicit, immutable virtual tree from those components and presents it to VoiceOver, TalkBack, Windows UI Automation, AT-SPI, Java Access Bridge, and web accessibility APIs. The semantic tree is separate from the visual tree. This is important for renderer-backed controls, merged cards, decorative content, custom controls, and applications that need a reading order different from paint order. -== Built-in semantics +=== Built-in semantics Standard components work without extra configuration. `Button`, `CheckBox`, `RadioButton`, `Slider`, text fields, lists, tables, tabs, labels, dialogs, and containers infer appropriate roles, values, states, collection metadata, and standard actions. Renderer-backed `List` rows are exposed as stable virtual children even though no `Component` exists for each painted row. @@ -15,7 +15,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Changes to text, selection, focus, enabled state, bounds, scrolling, ranges, tabs, and the current `Form` automatically invalidate the native semantic tree. Custom components should call `accessibilityChanged()` after a semantic value changes outside a standard setter. -== Roles, names, values, and state +=== Roles, names, values, and state `AccessibilityRole` contains portable control roles including buttons, toggle buttons, switches, checkboxes, radio buttons, headings, links, images, text and search fields, sliders, progress indicators, lists, grids, rows, cells, headers, tabs, dialogs, alerts, menus, toolbars, combo boxes, trees, and separators. A port maps an unsupported role to the closest native role without discarding its label or state. @@ -26,7 +26,7 @@ Tri-state controls use `UNCHECKED`, `CHECKED`, or `MIXED`. Nullable Boolean prop Use `setRoleDescription()` only when the platform role isn't sufficiently specific. Localize labels, hints, descriptions, errors, pane titles, role descriptions, and custom action labels. -== Ranges and editable values +=== Ranges and editable values `AccessibilityRange` describes minimum, maximum, current value, increment, and an optional spoken value. The spoken value is useful for ranges such as ratings and durations where a raw number is ambiguous. @@ -35,7 +35,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Editable controls can provide `SET_VALUE` or `SET_TEXT` actions. Sliders and other adjustable controls should expose `INCREMENT` and `DECREMENT`. Standard components infer these actions. -== Custom accessibility actions +=== Custom accessibility actions An `AccessibilityAction` has a stable ID, a localized label, an enabled state, and a handler. Handlers always execute on the Codename One EDT, including when the action originates on a native accessibility thread. @@ -44,7 +44,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Use the standard IDs in `AccessibilityAction` for activation, long press, increment, decrement, set value, set text, selection, character or word cursor movement, focus, show-on-screen, dismiss, expand, collapse, scrolling, and clipboard operations. A custom ID must be stable and its label must not be null. -== Grouping and virtual descendants +=== Grouping and virtual descendants `AccessibilityGrouping` controls how a component participates in the semantic tree: @@ -65,7 +65,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Virtual bounds are relative to the owning component. Component nodes use their clipped absolute bounds. -== Traversal order +=== Traversal order Visual order is the default reading order. `setSortKey()` assigns an ordered semantic key among siblings. `setTraversalBefore()` and `setTraversalAfter()` express a direct relationship when a numeric order would be fragile. @@ -74,7 +74,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Keep traversal relationships within the same semantic parent. The tree builder resolves these constraints deterministically and preserves stable node IDs. -== Live regions and screen changes +=== Live regions and screen changes Set `AccessibilityLiveRegion.POLITE` for non-urgent updates and `ASSERTIVE` for errors or urgent status. `OFF` is the default. Live changes produce the corresponding platform notification or ARIA live update. @@ -83,7 +83,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Form changes and nodes with a pane title produce screen or pane transition notifications. `Display.announceForAccessibility()` remains available for an exceptional announcement that isn't represented by persistent UI. Prefer a live region for state that's visible on screen. -== User accessibility preferences +=== User accessibility preferences Semantics describe what a control means. Accessibility preferences describe how the user wants the interface presented. Read these preferences through `Display` or the matching static shortcuts in `CN`: @@ -130,7 +130,7 @@ IMPORTANT: Never use `getColorVisionDeficiency() == NONE` as permission to conve Preference detection uses each platform's public signals. iOS and macOS expose contrast, differentiate-without-color, motion, transparency, bold text, inversion, grayscale, switch labels, and VoiceOver; Apple doesn't expose the selected color-filter type, so the deficiency value is `UNKNOWN`. Android reads high-text contrast, display inversion and color-correction mode, animation scale, font-weight adjustment, and touch exploration. Windows reads High Contrast, client-area animation, and screen-reader settings. Linux detects the GTK HighContrast theme, disabled GTK animation, and ATK bridge activation. JavaScript uses `forced-colors`, `prefers-contrast`, `prefers-reduced-motion`, and `prefers-reduced-transparency`. The Java SE simulator provides deterministic controls for every portable signal. -== Collections +=== Collections `AccessibilityCollectionInfo` describes row and column counts, hierarchy, and selection mode. `AccessibilityCollectionItemInfo` describes row and column index, spans, position and size in a set, nesting level, and header status. @@ -141,7 +141,7 @@ Row and column indexes are zero-based. Position and set size are one-based; use Renderer-backed lists keep the full model size in their collection metadata but materialize only the visible rows, a small navigation buffer, and the selected row as virtual children. Forward and backward semantic scroll actions move the window. This keeps accessibility-tree work proportional to the viewport instead of invoking a cell renderer for every row whenever a large list scrolls. -== Inspecting and testing semantics +=== Inspecting and testing semantics `AccessibilityInspector` returns an immutable snapshot. A snapshot is safe to inspect without racing native accessibility callbacks and includes stable IDs, hierarchy, bounds, resolved state, actions, range and collection data. `toJson()` is suitable for diagnostic reports and tooling. @@ -154,7 +154,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A The Java SE Component Inspector provides *Copy Accessibility Tree JSON* and *Audit Accessibility Tree* actions. Tests should assert resolved semantic properties instead of platform-specific spoken sentences. The `scripts/hellocodenameone` suite contains the cross-port conformance fixture used by native CI. -== Diagnosing and correcting an inaccessible screen +=== Diagnosing and correcting an inaccessible screen Accessibility review works best as a repeatable loop instead of a final checklist: @@ -181,7 +181,7 @@ Don't fix the warning by adding a label alone if the role, current state, range, .Auditing the semantic tree in the Component Inspector image::img/accessibility-component-inspector-audit.png[Component Inspector showing an accessibility audit,scaledwidth=80%] -=== Assertions that prevent regressions +==== Assertions that prevent regressions Snapshot the finished form and assert behavior that matters to a user. Prefer stable identifiers and resolved semantics over implementation class names or platform-specific speech: @@ -192,11 +192,11 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/A Keep targeted assertions for traversal order, validation errors, live-region behavior, ranges, and stable virtual keys. The `scripts/hellocodenameone` accessibility fixture invokes every portable preference API and exercises the resolved semantic tree on each native CI platform. -=== Native verification +==== Native verification The simulator finds portable problems, but the final pass must use VoiceOver, TalkBack, Narrator, Orca, or the browser accessibility tree. Navigate in both directions, activate every action, change adjustable values, enter and leave collections, trigger errors, and confirm that focus moves sensibly after a dialog, navigation, deletion, or live update. Record the platform, assistive-technology version, input method, and failed semantic node in the bug report; attach the inspector JSON when the native result differs from the portable snapshot. -== Platform mappings +=== Platform mappings [cols="1,2,2"] |=== diff --git a/docs/developer-guide/Advanced-Theming.asciidoc b/docs/developer-guide/Advanced-Theming.asciidoc index 0689bfe0111..2ebb5ab324a 100644 --- a/docs/developer-guide/Advanced-Theming.asciidoc +++ b/docs/developer-guide/Advanced-Theming.asciidoc @@ -770,13 +770,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/advancedth [[understanding-images-and-multi-images]] === Understanding images and Multi-Images -// HTML_ONLY_START -NOTE: This section provides a high-level overview of images. You dive deeper into the various types of images in the https://www.codenameone.com/manual/graphics.html#deep-into-images-section[graphics section]. -// HTML_ONLY_END -//// -//PDF_ONLY NOTE: This section provides a high-level overview of images. You dive deeper into the various types of images in the <>. -//// When working with a theme, you often use images for borders or backgrounds. You also use images within the GUI for various purposes and most such images will be extracted from the resource file. @@ -838,7 +832,7 @@ When configuring your styles, you should rarely use "Pixels" as the unit for pad and border thickness because the results will be inconsistent on different densities. Instead, you should use millimeters for all non-zero units of measurement. -As you now understand the <> it should be clear why this is important. +As you now understand the <> it should be clear why this is important. ==== Fractions of millimeters diff --git a/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc b/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc index 5aafd7cdaa5..373be8cb879 100644 --- a/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc +++ b/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc @@ -1530,13 +1530,7 @@ Another problem might be counterintuitive. iOS has screenshot images representin Its impractical to support something like HTML for the screenshot process since it would also look different from the web component running on the device. -// HTML_ONLY_START -TIP: You can read more about the screenshot process https://www.codenameone.com/manual/appendix-ios.html#section-ios-screenshots[here]. -// HTML_ONLY_END -//// -//PDF_ONLY -TIP: You can read more about the screenshot process <>. -//// +TIP: The launch storyboard replaced the build server's screenshot generator. See <>. === Integrating 3rd party native SDKs diff --git a/docs/developer-guide/Analytics.asciidoc b/docs/developer-guide/Analytics.asciidoc index d6c4fadcd08..4eacb306bcf 100644 --- a/docs/developer-guide/Analytics.asciidoc +++ b/docs/developer-guide/Analytics.asciidoc @@ -1,3 +1,4 @@ +[[analytics]] == Analytics The analytics API records how your application is used in the field. It's built around a small provider SPI: you register one or more providers with the `Analytics` entry point, then report screen views, events, user properties and crashes. The `Analytics` class fans every call out to all registered providers, but only after the matching consent has been granted. Consent is central to this API and is explained in <> below. diff --git a/docs/developer-guide/Animations.asciidoc b/docs/developer-guide/Animations.asciidoc index 6b7917e1c08..73f7c0e4054 100644 --- a/docs/developer-guide/Animations.asciidoc +++ b/docs/developer-guide/Animations.asciidoc @@ -116,17 +116,9 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/animations First the UI goes through an "unlayout" animation, once that completes the layout itself is performed. -// HTML_ONLY_START IMPORTANT: The `AndWait` calls needs to be invoked on the Event Dispatch Thread despite being "blocking." This is a common convention in Codename One powered by a unique capability of Codename One: `invokeAndBlock`. + You can learn more about `invokeAndBlock` in the -https://www.codenameone.com/manual/edt.html[EDT section]. -// HTML_ONLY_END -//// -//PDF_ONLY -IMPORTANT: The `AndWait` calls needs to be invoked on the Event Dispatch Thread despite being "blocking". This is a common convention in Codename One powered by a unique capability of Codename One: `invokeAndBlock`. + -You can learn more about `invokeAndBlock` in the <>. -//// The callback variant is like the `invokeAndBlock` variant but uses a more conventional callback semantic which is more familiar to some developers. It accepts a `Runnable` callback that will be invoked after the fact. For example, you can change the <> to use the callback semantics as such: @@ -220,13 +212,7 @@ Animations comprise two parts, the logic (deciding the position, etc.) and the p The separation of concerns allows you to avoid redundant painting for example, if animate didn't trigger a change return `false` to avoid the overhead related to animations. -// HTML_ONLY_START -You discuss low-level animations in more details within the https://www.codenameone.com/manual/graphics.html#clock-animation-section[animation section of the clock demo]. -// HTML_ONLY_END -//// -//PDF_ONLY You discuss low-level animations in more details within the <>. -//// === Transitions @@ -259,13 +245,7 @@ Themes define the default transitions used when showing a form, these differ bas TIP: `SlideFade` is problematic without a title area. If you have a `Form` that lacks a title area you would recommend to disable `SlideFade` at least for that `Form`. -// HTML_ONLY_START -Check out the full set of theme constants in the https://www.codenameone.com/manual/advanced-theming.html#theme-constants-section[Theme Constants Section]. -// HTML_ONLY_END -//// -//PDF_ONLY Check out the full set of theme constants in the <>. -//// ==== Replace diff --git a/docs/developer-guide/Authentication-And-Identity.asciidoc b/docs/developer-guide/Authentication-And-Identity.asciidoc index a52e7a8a63d..9e4f78804dc 100644 --- a/docs/developer-guide/Authentication-And-Identity.asciidoc +++ b/docs/developer-guide/Authentication-And-Identity.asciidoc @@ -1,3 +1,4 @@ +[[authentication-and-identity]] == Authentication and Identity This chapter covers Codename One's modern sign-in stack: OpenID Connect, Sign in with Apple, Google, Facebook, Microsoft Entra ID, Auth0 and Firebase Authentication. diff --git a/docs/developer-guide/Casual-Game-Programming.asciidoc b/docs/developer-guide/Casual-Game-Programming.asciidoc deleted file mode 100644 index c400b682a0d..00000000000 --- a/docs/developer-guide/Casual-Game-Programming.asciidoc +++ /dev/null @@ -1,80 +0,0 @@ -While game developers have traditionally used C/OpenGL to get every bit of performance out of a device, Java offers a unique opportunity for casual game developers. In this section you will build a simple card game in Java that can run unchanged on iOS, Android etc. - -Casual games are often the most influential games of all, they cross demographics such as the ubiquitous solitaire or even the chart topping Angry birds. Putting them in the same game category as 3D FPS games doesn't always make sense. - -Yes, framerates are important but ubiquity, social connectivity & gameplay are even more important for this sub genre of the game industry. The mobile aspect highlights this point further, the way app stores are built releasing often puts your game at an advantage over its competitor’s. Yet releasing to all platforms and all screen sizes becomes an issue soon enough. - -Typically a game comprises a game loop which updates UI status based on game time and renders the UI. But, with casual games constantly rendering is redundant and with mobile games it could put a major drain on the battery life. Instead you will use components to build the game elements and let Codename One do the rendering for you. - -=== The game - -You will create a poker game for 1 player that doesn't include the betting process or any of the complexities such as AI, card evaluation or validation. This allows you to fit the whole source code in 270 lines of code (more due to comments). The example also intentionally simplifies the UI for touch devices; technically it would be pretty easy to add keypad support but it would complicate the code and require more designs (for focus states). - -TIP: You can see the game running on the simulator at http://www.youtube.com/watch?v=4IQGBT3VsSQ[http://www.youtube.com/watch?v=4IQGBT3VsSQ] - -The game consists of two forms: Splash screen and the main game UI. - -==== Handling multiple device resolutions - -In mobile device programming every pixel is crucial because of the small size of the screen, but you can’t shrink down your graphics too much because it needs to be "finger friendly" (big enough for a finger) and readable. The device world has great disparity, even within the iOS family the retina iPad has more than twice the screen density of the iPad mini. This means that an image that looks good on the iPad mini will seem either small or pixelated on an iPad, but an image that looks good on the iPad would look huge (and take up too much RAM) on the iPad mini. The situation is even worse when dealing with phones and Android devices. - -Solutions exist, such as using multiple images for every density (DPI). But, this is tedious for developers who need to scale the image and copy it every time for every resolution. Codename One has a feature called `MultiImage` which implicitly scales the images to all the resolutions on the desktop and places them within the res file, in runtime you will get the image that matches your devices density. - -A catch exists though... `MultiImage` is designed for applications where you want the density to determine the size. An iPad will have the same density as an iPhone since both share the same amount of pixels per inch. This makes sense for an app since the images will be big enough to touch and clear. Furthermore, since the iPad screen is larger more data will fit on the screen! - -Game developers have a different constraint when it comes to game elements. For a game you want the images to match the device resolution and take up as much screen real estate as possible, otherwise your game would be constrained to a small portion of the tablet and look small. A solution exists though: you can determine your own DPI level when loading resources and effectively force a DPI based on screen resolution when working with game images! - -To work with such varied resolutions/DPI’s and potential screen orientation changes you need another tool in your arsenal: layout managers. - -If you're familiar with AWT/Swing this should be pretty easy, Codename One allows you to codify the logic that flows Components within the UI. You will use the layout managers to ease that logic and preserve the UI flow when the device is rotated. - -==== Resources - -To save some time/effort use the ready-made resource files linked in the On The Web section below. You can skip this section and move on to the code, but for completeness here is what was done to create these resources: - -You will need a gamedata.res file that contains all the 52 cards as multi images using the naming convention of ‘rank suite.png’ example: 10c.png (10 of clubs) or ad.png (Ace of diamonds). - -To do this you can create 52 images of 153×217 pixels for all the cards then use the designer tool and select "Quick Add MultiImages" from the menu. When prompted select HD resolution. This effectively created 52 multi-images for all relevant resolutions. - -You can also change the default theme that ships with the application in small ways to create the white over green color scheme. Open it in the designer tool by double clicking it and select the theme. - -Then press Add and select the `Form` entry with background `NONE`, background color `6600` and transparency `255`. - -Add a `Label` style with transparency `0` and foreground `255` and then copy the style to pressed/selected (since its applied to buttons too). - -Do the same for the `SplashTitle`/`SplashSubtitle` but there also set the alignment to `CENTER`, the `Font` to bold and for `SplashTitle` to `Large Font` as well. - -==== The splash screen - -The first step is creating the splash animation as you can see in the screenshots in <>. - -[[game-figure-2]] -.Animation stages for the splash screen opening animation -image::img/gaming-fig2.png[Figure 2,scaledwidth=40%] - -The animation in the splash screen and most of the following animations are achieved using the simple tool of layout animations. In Codename One components are automatically arranged into position using layout managers, but this isn't implicit unless the device is rotated. A layout animation relies on this fact, it allows you to place components in a position (whether by using a layout manager or by using `setX`/`setY`) then invoke the layout animation code so they will slide into their "proper" position based on the layout manager rules. - -You can see how you achieved the splash screen animation of the cards sliding into place in Listing 1 within the `showSplashScreen()` method. After you change the layout to a box X layout you invoke animateHierarchy to animate the cards into place. - -Notice that you use the `callSerially` method to start the actual animation. This call might not seem necessary at first until you try running the code on iOS. The first screen of the UI is important for the iOS port which uses a screenshot to speed startup. If you won’t have this callSerially invocation the screenshot rendering process won't succeed and the animation will stutter. - -You also have a cover transition defined here; it’s a simple overlay when moving from one form to another. - -==== The game UI - -Initially when entering the game form you've another animation where all the cards are laid out as you can see in <>. You then have a long sequence of animation where the cards unify into place to form a pile (with a cover background falling on top) after which dealing begins and cards animate to the rival (with back showing) or to you with the face showing. Then the instructions to swap cards fade into place. - -[[game-figure-3]] -.Game form startup animation and deal animation -image::img/game-figure-3.png[Game UI,scaledwidth=40%] - - -This animation is easy to do although it does have several stages. In the first stage you layout the cards within a grid layout (13×4), then when the animation starts (see the https://www.codenameone.com/javadoc/com/codename1/ui/util/UITimer.html[UITimer] code within `showGameUI()`) you change the layout to a layered layout, add the back card (so it will come out on top based on z-ordering) and invoke animate layout. - -Notice that here you use `animateLayoutAndWait`, which effectively blocks the calling thread until the animation is completed. This is a important and tricky subject! - -Codename One is a single threaded API, it supports working on other threads but it's your responsibility to invoke everything on the EDT (Event Dispatch Thread). Since the EDT does the entire rendering, events etc. If you block it you will effectively stop Codename One in its place! But, a trick exists: invokeAndBlock is a feature that allows you to stop the EDT and do stuff then restore the EDT without "" stopping it. Its tricky and out of scope for this article (this subject deserves an article of its own) but the gist of it's that you can’t invoke Thread.sleep() in a Codename One application (at least not on the EDT) but you can use clever methods such as `Dialog.show()`, `animateLayoutAndWait` etc. and they will block the EDT for you. This is convenient since you can write code serially without requiring event handling for every single feature. - -Now that you got that out of the way, the rest of the code is clearer. Now you understand that `animateLayoutAndWait` will wait for the animation to complete and the next lines can do the next animation. Indeed after that you invoke the `dealCard` method that hands the cards to the players. This method is also blocking (using and `wait` methods internally) it also marks the cards as draggable and adds that drag logic which you will later use to swap cards. - -In the animation department, you use a method called replace to fade in a component using a transition. diff --git a/docs/developer-guide/Events.asciidoc b/docs/developer-guide/Events.asciidoc index c45979b9be6..3f9ec37d048 100644 --- a/docs/developer-guide/Events.asciidoc +++ b/docs/developer-guide/Events.asciidoc @@ -136,13 +136,7 @@ in the Codename One AutoCompleteTextField. * https://www.codenameone.com/javadoc/com/codename1/ui/table/TableModel.html[TableModel] & https://www.codenameone.com/javadoc/com/codename1/ui/list/ListModel.html[ListModel] - the model for the https://www.codenameone.com/javadoc/com/codename1/ui/table/Table.html[Table] class notifies the view that its content has changed via this event, thus allowing the UI to refresh. -// HTML_ONLY_START -An exhaustive example of search implemented using the `DataChangedListener` appears in the https://www.codenameone.com/manual/components.html#Advanced-search-code[Toolbar section]. -// HTML_ONLY_END -//// -//PDF_ONLY -There is a exhaustive example of search that's implemented using the `DataChangedListener` in the <>. -//// +There is an exhaustive example of search that's implemented using the `DataChangedListener` in the <>. ==== FocusListener @@ -163,13 +157,7 @@ For example, in this code from the `Flickr` demo the https://www.codenameone.com include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/EventsJava009Snippet.java[tag=events-java-009,indent=0] ---- -// HTML_ONLY_START -NOTE: A better way of implementing this exact effect uses title animations https://www.codenameone.com/manual/components.html#title-animations-section[illustrated here]. -// HTML_ONLY_END -//// -//PDF_ONLY NOTE: There is a better way of implementing this exact effect using title animations <>. -//// ==== SelectionListener diff --git a/docs/developer-guide/Home.asciidoc b/docs/developer-guide/Home.asciidoc deleted file mode 100644 index d0cc1cadbe5..00000000000 --- a/docs/developer-guide/Home.asciidoc +++ /dev/null @@ -1,26 +0,0 @@ -= Codename One Developer Guide - -Welcome to the Codename One Developer Guide. This manual brings together tutorials, patterns, and reference material to help you design, build, and ship cross-platform apps with Codename One. Use the table of contents to explore the topics most relevant to your project, or follow the guide sequentially for a comprehensive tour of the toolkit. - -== Guide at a Glance - -* *Getting Started* – Installation, project creation, and first-run walkthroughs that help you configure your environment and build your first Codename One app. -* *UI & UX* – Layout managers, themes, components, and best practices for crafting responsive user interfaces across platforms. -* *Application Services* – Covers data storage, networking, push notifications, native interfaces, and other platform services you can integrate. -* *Deployment & Distribution* – Instructions for packaging, signing, and publishing to the major app stores alongside troubleshooting tips. -* *Appendices & Reference* – Supplemental material including glossary entries, configuration tables, and advanced topics for power users. - -Each section is organized to surface conceptual explanations first, followed by practical examples and deeper dives. Cross references within the guide link related topics so you can pivot between beginner-friendly introductions and advanced techniques. - -== Recommended Resources - -These resources complement the manual and are maintained by the Codename One team: - -* https://www.codenameone.com/manual/[Web edition of this guide] -* https://www.codenameone.com/files/developer-guide.pdf[Downloadable PDF release] -* https://www.codenameone.com/javadoc/index.html[Codename One JavaDoc] -* https://www.codenameone.com/how-do-i.html[How Do I? video tutorials] -* https://www.codenameone.com/blog.html[Codename One blog] -* https://www.codenameone.com/discussion-forum.html[Community discussion forum] - -For questions or improvements, open an issue or submit a pull request in the https://github.com/codenameone/CodenameOne/[Codename One GitHub repository]. diff --git a/docs/developer-guide/Index.asciidoc b/docs/developer-guide/Introduction.asciidoc similarity index 99% rename from docs/developer-guide/Index.asciidoc rename to docs/developer-guide/Introduction.asciidoc index 017953f6d2a..3ba32d08f6d 100644 --- a/docs/developer-guide/Index.asciidoc +++ b/docs/developer-guide/Introduction.asciidoc @@ -138,6 +138,7 @@ Before you proceed, this section explains some universal core concepts of mobile You can skip this section if you feel you're familiar enough with the core problems/issues in mobile app development. +[[density-and-dpi]] ==== Density Density is also known as DPI (Dots Per Inch) or PPI (pixels or points per inch). Density is confusing, unintuitive and might collide with common sense. For example, an iPhone 7 plus has a resolution of `1080x1920` pixels and a PPI of `401` for a 5-inch screen. But, an iPad 4 has `1536x2048` pixels with a PPI of `264` on a `9.7` inch screen... Smaller devices can have higher resolutions! @@ -317,6 +318,7 @@ image::img/codenameone-hello-world-title-label.png[Title and Label in the UI,sca Some complex ideas appear within this short snippet that this chapter addresses later when talking about layout. The gist of it's that you create and show a `Form`. `Form` is the top level UI element, it takes over the whole screen. You can add UI elements to that `Form` object, in this case the `Label`. You use the `BoxLayout` to arrange the elements within the `Form` from top to the bottom vertically. +[[ApplicationLifecycle]] .Application Lifecycle **** A few years ago Romain Guy (a senior Google Android engineer) was on stage at the Google IO conference. He asked for a show of hands of people who understand the `Activity` lifecycle (`Activity` is like a Codename One main class). He then proceeded to jokingly call the audience members who lifted their hands "`liars`" claiming that after all his years in Google he still doesn't understand it... @@ -478,7 +480,7 @@ image::img/build-server-results.png[Build Results,scaledwidth=80%] TIP: On iOS make sure you use Safari when installing, as 3rd party browsers might have issues -Once you go through those steps you should have the #HelloWorld# app running on your device. This process is non-trivial when starting so if you run into difficulties don't despair and seek help at the discussion forum (https://www.codenameone.com/discussion-forum.html) or stack overflow (https://stackoverflow/tags/codenameone/). Once you go through signing and installation, it becomes easier. +Once you go through those steps you should have the #HelloWorld# app running on your device. This process is non-trivial when starting so if you run into difficulties don't despair and seek help at the discussion forum (https://www.codenameone.com/discussion-forum/) or stack overflow (https://stackoverflow.com/questions/tagged/codenameone). Once you go through signing and installation, it becomes easier. TIP: You can also install the application either by emailing the installation link to your account (using the #e-mail Link# button) diff --git a/docs/developer-guide/MCP-Headless-API.asciidoc b/docs/developer-guide/MCP-Headless-API.asciidoc index fb4e6a1e0b7..5877340c591 100644 --- a/docs/developer-guide/MCP-Headless-API.asciidoc +++ b/docs/developer-guide/MCP-Headless-API.asciidoc @@ -1,4 +1,4 @@ -= MCP Headless API +== MCP Headless API The Model Context Protocol (MCP) headless API lets an application expose itself to a large language model agent. An agent such as Claude Desktop, Claude Code, Codex, or opencode can read the current screen, drive the user interface, and call tools the application publishes. @@ -6,7 +6,7 @@ The API reuses the accessibility semantics tree. The same immutable tree that de The socket transport runs anywhere the port can bind the loopback interface, which includes an application running on a device, so an agent can attach to a build on a phone as well as to the simulator. It's blocked on a release build; see <>. The stdio transport needs process standard input and so is supported by the JavaSE port, which powers the simulator and the desktop tooling. -== The MCP menu +=== The MCP menu Every desktop Codename One tool, including the simulator and Codename One Settings, gets a native `MCP` pull-down menu. The menu is added by the JavaSE port, so a tool gets it without any code of its own. It's the main way a user turns a tool into something an agent can drive. @@ -20,7 +20,7 @@ The menu has these items: Install writes a command that launches `MCPStdioLauncher`, a small bridge that relays the host's standard input and output to the running tool's socket. Hosts speak stdio and the tool serves a socket, so the bridge lets a stdio host such as Claude Desktop drive the already-running, human-visible tool. -== Starting the server +=== Starting the server Invoking the API is the switch. There is no build hint or property to set. The socket server lets an agent attach to a session a person is watching, which is the usual choice in the simulator: @@ -35,7 +35,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/M The stdio transport is the standard MCP local transport, exchanging newline delimited JSON-RPC messages. While it runs, application logging is redirected away from standard output so it can't corrupt the protocol stream. The stdio transport lives in the JavaSE port because it needs process standard input, which isn't available on every target. [[development-builds-only]] -== Development builds only +=== Development builds only The socket server refuses to bind on a release build and throws an `IllegalStateException` instead. @@ -59,7 +59,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/M Treat that call the way you'd treat any other decision to expose a control surface, because the device itself becomes the boundary. -== Built-in user interface tools +=== Built-in user interface tools Every server registers a small set of tools that read and drive the screen through the accessibility tree. An agent calls `ui_snapshot` to get the semantics tree of the current form as JSON, including the identifier, role, label, value, and state of each node, and the identifiers of the actions each node supports. @@ -67,7 +67,7 @@ The agent drives the screen with `ui_perform_action`, which performs an action s Actions run on the Codename One EDT, so an agent never touches the live component tree directly. Each action returns whether it succeeded together with a fresh snapshot. -== Publishing application tools +=== Publishing application tools An application publishes its own data and actions as MCP tools. A `Tool` has a name, a description, a JSON schema for its parameters, and a handler: @@ -76,13 +76,13 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/M The server merges these tools with the built-in tools when a host lists the available tools, and routes each call to the matching handler. The same `Tool` type is used by the Codename One AI client, so a tool defined once serves both a hosted agent and an in-application model. -== Screenshots and the simulator +=== Screenshots and the simulator The server exposes a screenshot of the current form as an MCP image resource, so a vision capable model can see the screen alongside the semantic tree. The resource is enabled by default and can be disabled per server. The JavaSE simulator drives the same MCP menu described above, so an application can be exposed and driven from the running simulator during development. -== Debug logging +=== Debug logging Because an agent drives the tool on its own, it helps to watch what it does. The server echoes the MCP conversation to the Codename One log at a level chosen through the menu's *Debug Logging* item or in code: @@ -91,7 +91,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/M The levels of `MCPVerbosity` are, from quietest to loudest: `OFF`, `ERRORS` (only failed calls), `SUMMARY` (one line per call), and `FULL` (every request and response). Each level includes the one below it. -== Registering with installed hosts +=== Registering with installed hosts The Install and Remove items in the MCP menu call `MCPClientRegistrar`, which detects the MCP hosts installed on the machine and writes a server entry into each host configuration, so an end user doesn't edit configuration by hand. Detection and registration are available to any Codename One tool, and they run inside the runtime because they use the portable `FileSystemStorage`. diff --git a/docs/developer-guide/Maven-Project-Templates.adoc b/docs/developer-guide/Maven-Project-Templates.adoc index 6b9f80ade3d..f047013695c 100644 --- a/docs/developer-guide/Maven-Project-Templates.adoc +++ b/docs/developer-guide/Maven-Project-Templates.adoc @@ -36,7 +36,4 @@ See <> for a more concrete example of the `gen You can test your project template by using it as the `sourceProject` parameter for the `generate-app-project` goal. See <>. -=== Add your template to Codename One intializr - -If you have a project template that you want to share with the community, please file an issue in the https://github.com/codenameone/CodenameOne/issues[Codename One issue tracker] with a link to a GitHub Repository of your project template, and request to have it added https://www.codenameone.com/initializr[Codename One initializr]. diff --git a/docs/developer-guide/Media-And-Audio.asciidoc b/docs/developer-guide/Media-And-Audio.asciidoc index 21bbec9c221..382a5c63c0b 100644 --- a/docs/developer-guide/Media-And-Audio.asciidoc +++ b/docs/developer-guide/Media-And-Audio.asciidoc @@ -1,16 +1,10 @@ [[media-and-audio-section]] -= Media and Audio +== Media and Audio [[media-audio-mediamanager-section]] -== MediaManager and MediaPlayer +=== MediaManager and MediaPlayer -// HTML_ONLY_START -IMPORTANT: `MediaPlayer` is a *peer component*, understanding this is crucial if your application depends on such a component. You can learn about peer components and their issues https://www.codenameone.com/manual/advanced-topics.html#native-peer-components[here]. -// HTML_ONLY_END -//// -//PDF_ONLY IMPORTANT: `MediaPlayer` is a *peer component*, understanding this is crucial if your application depends on such a component. You can learn about peer components and their issues <>. -//// The https://www.codenameone.com/javadoc/com/codename1/components/MediaPlayer.html[MediaPlayer] allows you to control video playback. To use the `MediaPlayer` you need to first load the `Media` object from the https://www.codenameone.com/javadoc/com/codename1/media/MediaManager.html[MediaManager]. @@ -34,7 +28,7 @@ image::img/components-mediaplayer-android.png[Video playback running on an Andro IMPORTANT: Video playback in the simulator will work with JavaFX enabled. This is the default for Java 8 or newer so recommend using that. [[pcm-audio-section]] -== PCM Audio Buffers, Mixing, and Effects +=== PCM Audio Buffers, Mixing, and Effects `AudioBuffer` stores raw interleaved float PCM samples in the `[-1, 1]` range, and `WAVWriter` writes those samples to a WAV file. diff --git a/docs/developer-guide/Miscellaneous-Features.asciidoc b/docs/developer-guide/Miscellaneous-Features.asciidoc index 70b5547b568..2da9ce7128b 100644 --- a/docs/developer-guide/Miscellaneous-Features.asciidoc +++ b/docs/developer-guide/Miscellaneous-Features.asciidoc @@ -450,13 +450,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/g .Captured photos previewed in the ImageViewer image::img/capture-photo.png[Captured photos previewed in the ImageViewer,scaledwidth=20%] -// HTML_ONLY_START -You show video capture in the https://www.codenameone.com/manual/components.html#mediamanager-section[MediaManager section]. -// HTML_ONLY_END -//// -//PDF_ONLY You show video capture in the <>. -//// The sample below captures audio recordings (using the 'Capture' API) and copies them locally under unique names. It also demonstrates the storage and organization of captured audio: diff --git a/docs/developer-guide/SVG-Transcoder.asciidoc b/docs/developer-guide/SVG-Transcoder.asciidoc index 4559d165ed0..9414f8fddfc 100644 --- a/docs/developer-guide/SVG-Transcoder.asciidoc +++ b/docs/developer-guide/SVG-Transcoder.asciidoc @@ -1,5 +1,4 @@ -= Build-Time Vector & Animation Images -:source-highlighter: highlight.js +== Build-Time Vector & Animation Images The build-time vector transcoder lets you author UI icons and illustrations as SVG or Lottie / Bodymovin JSON and have them rendered @@ -15,7 +14,7 @@ the SVG transcoder's model, the same `JavaCodeGenerator` emits a covers SVG in detail; Lottie gets its own section at the end that only calls out the parts that differ. -== Motivation +=== Motivation Codename One's older `Image.createSVG()` API depends on a per-platform native SVG renderer that ships only on a couple of backends (J2ME and @@ -34,7 +33,7 @@ emitted as a Java class that subclasses `com.codename1.ui.GeneratedSVGImage`, and rendered through the standard `Graphics` shape API. The same vector source produces pixel-perfect output at any size on every port. -== Quick start +=== Quick start . Drop your SVG next to `theme.css` in `src/main/css/`: + @@ -69,7 +68,7 @@ present, and the per-port build wiring (`IPhoneBuilder`, returns the transcoded image; CSS rules that reference the SVG by URL pick it up via the same registry. -== Why millimeters +=== Why millimeters `cn1-svg-width` / `cn1-svg-height` are the sizing knob you should reach for first. @@ -104,7 +103,7 @@ treated as design pixels at `DENSITY_MEDIUM`. If both keys appear on the same rule, `cn1-svg-width` / `cn1-svg-height` wins. -== How the build flow works +=== How the build flow works The `cn1app` archetype binds the `transcode-svg` goal to the `generate-sources` phase: @@ -139,7 +138,7 @@ in the user's compile output and weave `installGlobal()` into the generated `Stub` right before the first `init(Object)`; a project with no SVGs gets no weaving. -== Calling the registry yourself +=== Calling the registry yourself If you don't use `theme.css` but still want a transcoded SVG, construct the generated class directly: @@ -154,7 +153,7 @@ the one to prefer for the reasons in the previous section. requested dimensions from `getWidth()` / `getHeight()` and shares the animation clock with its source. -== SVG feature coverage +=== SVG feature coverage The transcoder targets the SVG 1.1 static-shape vocabulary plus the SMIL animation subset: @@ -187,7 +186,7 @@ with `Timeline`, you must register the image with a `Form`'s animation manager (or set it as a `Component.setIcon` with `isAnimation()` true) for the repaint loop to tick the SMIL clock. -== Lottie animations +=== Lottie animations Lottie / Bodymovin JSON files are picked up by the same `transcode-svg` goal. Drop them next to your CSS (or under `src/main/lottie/`) and the @@ -216,7 +215,7 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/g forward compatibility, but the archive container isn't yet extracted -- export your animation as a plain Bodymovin JSON for now. -=== Lottie feature coverage +==== Lottie feature coverage The parser targets the subset of Bodymovin a "spinner" or "pulse" animation typically uses. Anything outside the subset is dropped @@ -243,12 +242,12 @@ For animations that need higher fidelity than the subset above, export the relevant frame as an SVG and use the SVG transcoder path directly -- the runtime classes are identical. -== Troubleshooting +=== Troubleshooting `Resources.getImage("name.svg")` returns null or a 1×1 transparent PNG:: The transcoder didn't run, or it ran with zero source files. Confirm the asset lives under `src/main/css/` (or `src/main/svg/` / - `src/main/lottie/` for the dedicated dirs) and that the + `src/main/lottie/` for the dedicated directories) and that the `transcode-svg` goal is bound in the project POM. The same goal handles `.svg`, `.json`, and `.lottie` -- one goal, both formats. For arbitrary Resources bundles loaded outside the global slot, call diff --git a/docs/developer-guide/Testing-with-JUnit.adoc b/docs/developer-guide/Testing-with-JUnit.adoc index 4b8ea6e114f..0114f2b0d22 100644 --- a/docs/developer-guide/Testing-with-JUnit.adoc +++ b/docs/developer-guide/Testing-with-JUnit.adoc @@ -174,5 +174,5 @@ The UI driving (`TestUtils.*`) is identical -- `TestUtils` is independent of the === Cross-reference -* For the `AbstractTest` framework's full API surface (`TestUtils` helpers, `screenshotTest` tolerance algorithm, baseline management), see <> in the performance chapter. +* For the `AbstractTest` framework's full API surface -- the https://www.codenameone.com/javadoc/com/codename1/testing/TestUtils.html[TestUtils] helpers, the `screenshotTest` tolerance algorithm and baseline management -- see the https://www.codenameone.com/javadoc/com/codename1/testing/package-summary.html[com.codename1.testing Javadoc]. * For the `cn1:test` Maven goal, see <>. diff --git a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc index 31565240a59..13c8c180b98 100644 --- a/docs/developer-guide/The-Components-Of-Codename-One.asciidoc +++ b/docs/developer-guide/The-Components-Of-Codename-One.asciidoc @@ -13,13 +13,7 @@ image::img/component-uml.png[Component-Container relationship expressed as UML,s Components are arranged in containers with layout managers. A layout manager decides how to arrange components inside the container. -// HTML_ONLY_START -You can read more about layout managers in the https://www.codenameone.com/manual/basics.html#component-container-hierarchy[basics section]. -// HTML_ONLY_END -//// -//PDF_ONLY -You can read more about layout managers in the <>. -//// +You can read more about layout managers in the <>. ==== Composite components @@ -44,13 +38,7 @@ This means a single `Component` can contain multiple nested `UIID`s. For example The lead component also handles events from a single source. Clicking another component in the hierarchy sends the event to the leading `Button`, which can make action events route to a different target than the apparent click target. That's why `getActualComponent()` exists. -// HTML_ONLY_START -You can learn more about lead components in https://www.codenameone.com/manual/misc-features.html#lead-component-section[here]. -// HTML_ONLY_END -//// -//PDF_ONLY You can learn more about lead components in <>. -//// **** === Form @@ -165,13 +153,7 @@ Notice that during the `show` call above the execution of the next line was "pau IMPORTANT: All usage of `Dialog` must be within the Event Dispatch Thread (the default thread of Codename One). This is true for modal dialogs. The `Dialog` class knows how to "block the EDT" without blocking it. -// HTML_ONLY_START -To learn more about `invokeAndBlock` which is the workhorse behind the modal dialog functionality check out https://www.codenameone.com/manual/edt.html[the EDT section]. -// HTML_ONLY_END -//// -//PDF_ONLY To learn more about `invokeAndBlock` which is the workhorse behind the modal dialog functionality check out <>. -//// The `Dialog` class contains many static helper methods to show user notifications, but also allows a developer to create a `Dialog` instance, add information to its content pane and show the dialog. @@ -1452,13 +1434,7 @@ indicator chains cleanly. [[mediamanager-section]] === MediaManager & MediaPlayer -// HTML_ONLY_START -IMPORTANT: `MediaPlayer` is a *peer component*, understanding this is crucial if your application depends on such a component. You can learn about peer components and their issues https://www.codenameone.com/manual/advanced-topics.html#native-peer-components[here]. -// HTML_ONLY_END -//// -//PDF_ONLY IMPORTANT: `MediaPlayer` is a *peer component*, understanding this is crucial if your application depends on such a component. You can learn about peer components and their issues <>. -//// The https://www.codenameone.com/javadoc/com/codename1/components/MediaPlayer.html[MediaPlayer] allows you to control video playback. To use the `MediaPlayer` you need to first load the `Media` object from the https://www.codenameone.com/javadoc/com/codename1/media/MediaManager.html[MediaManager]. @@ -1670,13 +1646,7 @@ In the first line you create a style animation that will translate the style fro === BrowserComponent & WebBrowser -// HTML_ONLY_START -IMPORTANT: `BrowserComponent` is a *peer component*, understanding this is crucial if your application depends on such a component. You can learn about peer components and their issues https://www.codenameone.com/manual/advanced-topics.html#native-peer-components[here]. -// HTML_ONLY_END -//// -//PDF_ONLY IMPORTANT: `BrowserComponent` is a *peer component*, understanding this is crucial if your application depends on such a component. You can learn about peer components and their issues <>. -//// The https://www.codenameone.com/javadoc/com/codename1/components/WebBrowser.html[WebBrowser] component shows the native device web browser when supported by the device and the https://www.codenameone.com/javadoc/com/codename1/ui/html/HTMLComponent.html[HTMLComponent] when the web browser isn't supported on the given device. If you intend to target smartphones diff --git a/docs/developer-guide/Video-Capture-Constraints.asciidoc b/docs/developer-guide/Video-Capture-Constraints.asciidoc index 9a5595d0459..cb1121acd7e 100644 --- a/docs/developer-guide/Video-Capture-Constraints.asciidoc +++ b/docs/developer-guide/Video-Capture-Constraints.asciidoc @@ -14,18 +14,30 @@ Support for these constraints vary by platform and device, but the API allows yo Suppose you want to allow the user to capture a short (5 second) clip, in a low resolution, appropriate for sharing on a social media platform. You create your `VideoCaptureConstraints` object as follows: +[source,java] +---- +include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava001Snippet.java[tag=video-capture-constraints-java-001,indent=0] +---- This constraint can then be passed to `Capture.captureVideo()` to get the captured file: +[source,java] +---- +include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava002Snippet.java[tag=video-capture-constraints-java-002,indent=0] +---- === Not all platforms support all constraints -how do you know if your constraints will be obeyed? If the platform doesn't support the max length, constraint, you may want to do something different. You can find out if a constraint is supported by asking out constraint object. +How do you know whether your constraints will be honored? When the platform doesn't support the maximum length, you may want to take a different path. Ask the constraint object whether it's supported. For example: +[source,java] +---- +include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava003Snippet.java[tag=video-capture-constraints-java-003,indent=0] +---- -You can probe a constraint to see whether the entire constraint is supported (i.e will be obeyed), or whether any particular aspect of it will be supported using the following methods: +You can probe a constraint to see whether the entire constraint is supported (that is, whether it will be obeyed), or whether any particular aspect of it will be supported using the following methods: * `isSupported()` - True if all preferred constraints are supported. * `isQualitySupported()` - True if the preferred quality setting is supported. @@ -42,10 +54,14 @@ Suppose you want to capture a video with resolution 320×240. You would begin wi include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava004Snippet.java[tag=video-capture-constraints-java-004,indent=0] ---- -Explicit width and height constraints aren't well supported across platforms. Android doesn't support them at all. iOS supports 3 specific sizes. JavaScript supports it when running on a desktop browser or on Android - but not on iOS. Etc. +Explicit width and height constraints aren't well-supported across platforms. Android doesn't support them at all. iOS supports 3 specific sizes. JavaScript supports it when running on a desktop browser or on Android - but not on iOS. Etc. Find out if this constraint will be obeyed: +[source,java] +---- +include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/VideoCaptureConstraintsJava005Snippet.java[tag=video-capture-constraints-java-005,indent=0] +---- === Constraint support by platform @@ -58,7 +74,7 @@ Find out if this constraint will be obeyed: | Simulator/Java SE | No | No | No | No | JavaScript (Desktop) | Yes | Yes | Yes | No | JavaScript (Android) | Yes | Yes | Yes | No -| JavaScript (iOS) | Yes | Yes | Yes | No +| JavaScript (iOS) | No | No | No | No |==================== `*` If size is specified, the platform will try to translate to the appropriate quality constraint. diff --git a/docs/developer-guide/Wearables.asciidoc b/docs/developer-guide/Wearables.asciidoc index b320ecda4ce..06c33ff15e1 100644 --- a/docs/developer-guide/Wearables.asciidoc +++ b/docs/developer-guide/Wearables.asciidoc @@ -103,8 +103,8 @@ NOTE: `isWatch()` describes the device form factor, not the screen shape. A Wear OS device can be round or square; query the display safe-area insets (see <>) rather than assuming a rectangle. -=== Designing for the Watch [[designing-for-the-watch]] +=== Designing for the Watch A watch screen is small and is frequently round. A few practical guidelines: @@ -119,8 +119,8 @@ A watch screen is small and is frequently round. A few practical guidelines: without forking your code (the override layer activates on watch devices the same way platform overrides do elsewhere). -=== Sharing Data Between the Phone and the Watch [[wearable-data]] +=== Sharing Data Between the Phone and the Watch The two apps share no storage. `Storage`, `Preferences` and the SQLite database are per device, and there's no container that spans the pair, so a value written @@ -234,8 +234,8 @@ has no such gap. Gate a wearable feature on those rather than on `isSupported()` or you will offer it to someone holding a phone and nothing else. Add a `WearableStateListener` rather than polling. -=== Complications and Tiles [[watch-complications]] +=== Complications and Tiles A complication -- the small live readout on a watch face -- is the same idea as a home-screen widget: content-driven, rendered while your app isn't running, fed @@ -276,8 +276,8 @@ home here, because most complications are a gauge, a dial or a ring. Design for a glance. A complication is a few dozen pixels someone reads in under a second, so one number or one gauge beats any layout that has to be read. -==== What a Watch Face Actually Shows [[watch-complication-fidelity]] +==== What a Watch Face Actually Shows This is the part that surprises people, so it's worth stating plainly: **a complication isn't a small widget.** A watch face asks your data source for one @@ -348,7 +348,6 @@ image::img/wearables/apple-watch-simulator.png[Codename One running on the Apple [[watch-distribution]] ==== What the Watch App Runs Today -[[watch-entry-point]] `codename1.watchMain` is the watch app's entry point on both platforms. The watchOS build writes a stub of its own for that class and runs a second @@ -377,8 +376,8 @@ from the phone. None of this affects building, running or testing on the simulator or a device. -==== Native Code and the Watch Slice [[watch-native-code]] +==== Native Code and the Watch Slice Your Objective-C is compiled for the watch as well as the phone. The translator copies native sources through to every slice it produces, so a `.m` that imports @@ -400,8 +399,8 @@ no build hint for this and no attempt to infer it: which of your native sources can compile for watchOS is a question about that source, and the preprocessor is where it's answered. -==== Supported and Unsupported APIs on watchOS [[watch-supported-apis]] +==== Supported and Unsupported APIs on watchOS Because watchOS lacks UIKit views, GPU rendering and several iOS frameworks, the APIs that depend on them aren't available on the watch slice. They're guarded @@ -432,8 +431,8 @@ usual. Cloud builds generate the watch target through the same iOS build -- declare the watch main class and build for iOS -- and the same applies there, so a standalone cloud build returns the iOS archive. -=== Android (Wear OS) [[wear-os-android]] +=== Android (Wear OS) A Wear OS app is a regular Android app. The Codename One Android port renders the UI with the same pipeline it uses on phones, so no special rendering backend is @@ -499,8 +498,8 @@ dependency and the listener service automatically. The `android.playService.wearable` hint remains for apps that want to call the Data Layer APIs directly. -=== Feeding a Complication from the Phone [[watch-complication-mirror]] +=== Feeding a Complication from the Phone A watch app has its own storage. Nothing the phone writes is visible there, on either platform -- on Apple the App Group identifier is the same string but diff --git a/docs/developer-guide/Working-With-CodenameOne-Sources.asciidoc b/docs/developer-guide/Working-With-CodenameOne-Sources.asciidoc index 319d955ac1b..6242e2df1a7 100644 --- a/docs/developer-guide/Working-With-CodenameOne-Sources.asciidoc +++ b/docs/developer-guide/Working-With-CodenameOne-Sources.asciidoc @@ -91,7 +91,6 @@ Building the SDK yourself gives you: * Immediate access to fixes and features before they reach a release. * The ability to inspect, debug, and change the framework when you need custom behavior. -* A path to contribute improvements back to the Codename One core. Once you're comfortable with the baseline build, continue with the scripts in `scripts/` or the `BUILDING.md` guide to compile specific ports (Android or diff --git a/docs/developer-guide/Working-With-iOS.asciidoc b/docs/developer-guide/Working-With-iOS.asciidoc index ff327851b20..72f27e52fd4 100644 --- a/docs/developer-guide/Working-With-iOS.asciidoc +++ b/docs/developer-guide/Working-With-iOS.asciidoc @@ -20,6 +20,7 @@ If you've access to a Mac, connect the device, open Xcode, and use the device ex - Check that the `ios.includePush` build hint matches your iOS provisioning. It must be false if your provisioning profile doesn't include push. [[section-ios-launch-screen]] +[[ios-launch-storyboard]] === Launch screen storyboard best practices Launch screen storyboards are the default approach for Codename One iOS builds. Apple requires a storyboard-based launch experience for modern devices, so the legacy screenshot generator was removed in favor of a single adaptive layout. You can still opt back into the old behavior by setting the `ios.generateSplashScreens=true` build hint, but it's best to use a storyboard unless your use case can't be expressed with Auto Layout. diff --git a/docs/developer-guide/appendix_goal_test.adoc b/docs/developer-guide/appendix_goal_test.adoc index 653c7895e44..06c18b3f523 100644 --- a/docs/developer-guide/appendix_goal_test.adoc +++ b/docs/developer-guide/appendix_goal_test.adoc @@ -1,3 +1,4 @@ +[[appendix-goal-test]] === Run tests (`test`) Runs Codename One unit tests. diff --git a/docs/developer-guide/basics.asciidoc b/docs/developer-guide/basics.asciidoc index 74ebc1d0365..5365b9d1754 100644 --- a/docs/developer-guide/basics.asciidoc +++ b/docs/developer-guide/basics.asciidoc @@ -33,6 +33,7 @@ image::img/codenameone-form.png[Structure of a Form,scaledwidth=50%] Now that the structure is clear, open the Java file `TodoApp.java` in the project you created. You should see the lines that set up the UI in the `start()` method: +[[layout-managers]] ==== Layout managers A layout manager decides the size and location of components within a `Container`. Every `Container` has a layout manager. The default layout manager is `FlowLayout`. diff --git a/docs/developer-guide/cn1libs.asciidoc b/docs/developer-guide/cn1libs.asciidoc deleted file mode 100644 index 539b92ccc0c..00000000000 --- a/docs/developer-guide/cn1libs.asciidoc +++ /dev/null @@ -1,3 +0,0 @@ -=== cn1libs - -This section is under construction diff --git a/docs/developer-guide/component-selector.asciidoc b/docs/developer-guide/component-selector.asciidoc index fdbc62f8af0..98806005b37 100755 --- a/docs/developer-guide/component-selector.asciidoc +++ b/docs/developer-guide/component-selector.asciidoc @@ -2,13 +2,13 @@ The `ComponentSelector` class is a new class that brings the power of jQuery to Codename One. While it isn't *actually* jQuery, it's influenced by it. If you're not familiar with jQuery, here is the 10 second intro. -jQuery is a JavaScript library, created by John Resig in 2006, that has become a staple of browser-based UI development. As of March 2017, over 70% of web sites are using jQuery. The initial problem that jQuery solved was browser incompatibility issues. It provided a consistent API for most useful DOM methods so that the developer didn't have to spend all their days and nights fighting with browser compatibility issues. In a way, it did for JavaScript, what Codename One does for mobile apps. +jQuery is a JavaScript library, created by John Resig in 2006, that has become a staple of browser-based UI development. As of March 2017, over 70% of websites are using jQuery. The initial problem that jQuery solved was browser incompatibility issues. It provided a consistent API for most useful DOM methods so that the developer didn't have to spend all their days and nights fighting with browser compatibility issues. In a way, it did for JavaScript, what Codename One does for mobile apps. -The other thing that jQuery did, was provide an elegant way to select and manipulate DOM elements (that is, HTML tags in a web page). It enabled developers to form sets of elements using a CSS-like syntax, and to operate on all elements of those sets, as if they were single elements, and they provided a fluent API to enable developers to chain multiple calls together, and delay onset of carpel tunnel for at least a few extra years. +The other thing jQuery did was provide an elegant way to select and manipulate DOM elements (that is, HTML tags in a web page). It enabled developers to form sets of elements using a CSS-like syntax, and to operate on all elements of those sets, as if they were single elements, and they provided a fluent API to enable developers to chain multiple calls together, and delay onset of carpel tunnel for at least a few extra years. With the new `ComponentSelector` class, you've adopted the following aspects of jQuery: -1. **CSS-like Selection Sytax** - Support for a CSS-like syntax for "selecting" Components to be included in a set. +1. **CSS-like Selection Syntax** - Support for a CSS-like syntax for "selecting" Components to be included in a set. 2. **Fluent API** - The API is fluent, meaning you can chain multiple method calls together and reduce typing. 3. **Working on Sets** - Methods of this class operate on sets of components as if they're a single component. As you'll see, this can be incredibly powerful. 4. **Effects** - Support for common effects on components such as fadeIn(), fadeOut(), slideDown(), and slideUp(). @@ -59,7 +59,7 @@ Finally, ComponentSelector provides a `find()` method that implicitly uses the c ==== Selector syntax -far You've glossed over the selector syntax by saying it's `like CSS`. Though it's *like* CSS selectors, it's necessarily different to accommodate the differences between Codename One's component model and JavaScript's DOM. Rather than go into a technical language definition, You'll use some examples to illustrate the capabilities of your syntax. +Until now the selector syntax has only been described as `like CSS`. It's *like* CSS, but it differs where Codename One's component model differs from the JavaScript DOM. Rather than a formal grammar, the examples below show what the syntax can express. . `$("Label")` - The set of all components on the form with UIID "Label" . `$("#MyField")` - The set of all components on the form with Name `MyField`. @@ -103,7 +103,7 @@ Were you setting these values on the "selected" style, the "unselected" style, t include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava004Snippet.java[tag=component-selector-java-004,indent=0] ---- -If a component was in "selected" state, then this would changed the selected style. If it was in pressed state, then it would change the "pressed" style. Etc. What if you wanted to specifically change the styles in the "pressed" state. Then you would call `selectPressedStyle()` prior calling your style mutation methods. For example: +If a component was in "selected" state, then this would change the selected style. If it was in pressed state, then it would change the "pressed" style. Etc. What if you wanted to specifically change the styles in the "pressed" state. Then you would call `selectPressedStyle()` prior calling your style mutation methods. For example: [source,java] ---- @@ -142,6 +142,10 @@ Also to these basic effects, ComponentSelector wraps all the existing animation For example, Consider this example, that shows a button that replaces itself and all siblings with replacement labels, and then replaces them back: +[source,java] +---- +include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/generated/ComponentSelectorJava007Snippet.java[tag=component-selector-java-007,indent=0] +---- <1> Finds all siblings of the source button <2> Call `replaceAndWait()` with a mapping function to define the component that should replace each component. This will replace each component in the set with a replacement component in its respective container. This will also return a new ComponentSelector with the set of replacement components. <3> In your "mapper" callback, you will return a new Label component to replace each existing component. @@ -165,9 +169,9 @@ This can get interesting when you start combining these methods. For example, `$ === More demos -you've posted a demo app that demonstrates a few of the things that you discuss https://github.com/shannah/cn1-component-selector-demo[here]. The file containing most relevant source code is https://github.com/shannah/cn1-component-selector-demo/blob/master/src/com/codename1/tests/stylebuilder/StyleBuilderDemo.java[here]. +A https://github.com/shannah/cn1-component-selector-demo[demo app] exercises several of the features covered here. Most of the interesting code is in https://github.com/shannah/cn1-component-selector-demo/blob/master/src/com/codename1/tests/stylebuilder/StyleBuilderDemo.java[StyleBuilderDemo.java]. -you've also posted a short screencast of the demo app on youtube: +A short screencast of the demo app is on YouTube: video::Cue0fnJdB4U[youtube] diff --git a/docs/developer-guide/developer-guide.asciidoc b/docs/developer-guide/developer-guide.asciidoc index f4097901b87..1b61a722511 100644 --- a/docs/developer-guide/developer-guide.asciidoc +++ b/docs/developer-guide/developer-guide.asciidoc @@ -43,34 +43,48 @@ toc::[] include::About-This-Guide.asciidoc[] += Getting started + +include::Introduction.asciidoc[] + include::Maven-Project-Workflow.asciidoc[] -include::Index.asciidoc[] += Core concepts -include::basics.asciidoc[] +include::The-EDT---Event-Dispatch-Thread.asciidoc[] -include::Advanced-Theming.asciidoc[] +include::Events.asciidoc[] -include::Native-Themes.asciidoc[] +include::Device-Input-And-Form-Factors.asciidoc[] -include::css.asciidoc[] += User interface + +include::basics.asciidoc[] include::The-Components-Of-Codename-One.asciidoc[] +include::component-selector.asciidoc[] + include::Rich-Text-And-Code-Editing.asciidoc[] include::Accessibility-Semantics.asciidoc[] -include::MCP-Headless-API.asciidoc[] +include::Animations.asciidoc[] -include::Media-And-Audio.asciidoc[] += Theming and styling -include::Animations.asciidoc[] +include::Advanced-Theming.asciidoc[] -include::The-EDT---Event-Dispatch-Thread.asciidoc[] +include::Native-Themes.asciidoc[] + +include::css.asciidoc[] + += Graphics and games include::graphics.asciidoc[] +include::SVG-Transcoder.asciidoc[] + include::3D-Graphics.asciidoc[] include::Augmented-Reality.asciidoc[] @@ -83,12 +97,26 @@ include::Game-Builder.asciidoc[] include::Game-Assets.asciidoc[] -include::Events.asciidoc[] - -include::Device-Input-And-Form-Factors.asciidoc[] += Data, media and networking include::io.asciidoc[] +include::Network-Connectivity.asciidoc[] + +include::Annotation-JSON-XML-Mapping.asciidoc[] + +include::Annotation-Component-Binding.asciidoc[] + +include::Annotation-SQLite-ORM.asciidoc[] + +include::Media-And-Audio.asciidoc[] + +include::Video-IO.asciidoc[] + +include::Video-Capture-Constraints.asciidoc[] + += Device and platform services + include::Push-Notifications.asciidoc[] include::Notifications-And-Background-Execution.asciidoc[] @@ -103,33 +131,39 @@ include::In-Car-Experiences.asciidoc[] include::Motion-Sensors.asciidoc[] -include::Miscellaneous-Features.asciidoc[] +include::Near-Field-Communication.asciidoc[] -include::Video-IO.asciidoc[] +include::Bluetooth.asciidoc[] -include::performance.asciidoc[] +include::Nearby-Devices.asciidoc[] -include::Testing-with-JUnit.adoc[] +include::Call-Management.asciidoc[] -include::Advertising.asciidoc[] +include::VPN.asciidoc[] -include::Crash-Protection.asciidoc[] +include::Health.asciidoc[] -include::Analytics.asciidoc[] +include::Smart-Home.asciidoc[] -include::Commerce.asciidoc[] +include::Printing.asciidoc[] +include::Deep-Links-Routing.asciidoc[] -include::Monetization.asciidoc[] +include::App-Intents.asciidoc[] -include::App-Review.asciidoc[] +include::Document-Provider.asciidoc[] include::Apple-Wallet-Extension.asciidoc[] -include::Document-Provider.asciidoc[] +include::Miscellaneous-Features.asciidoc[] -include::Advanced-Topics-Under-The-Hood.asciidoc[] += AI and agents + +include::Ai-And-Speech.asciidoc[] +include::MCP-Headless-API.asciidoc[] + += Security and identity include::security.asciidoc[] @@ -143,43 +177,39 @@ include::Authentication-And-Identity.asciidoc[] include::Phone-Number-Verification.asciidoc[] -include::Deep-Links-Routing.asciidoc[] - -include::App-Intents.asciidoc[] - -include::Annotation-JSON-XML-Mapping.asciidoc[] += Monetization and analytics -include::Annotation-Component-Binding.asciidoc[] +include::Commerce.asciidoc[] -include::Annotation-SQLite-ORM.asciidoc[] +include::Monetization.asciidoc[] -include::Ai-And-Speech.asciidoc[] +include::Advertising.asciidoc[] -include::Near-Field-Communication.asciidoc[] +include::Analytics.asciidoc[] -include::Bluetooth.asciidoc[] +include::App-Review.asciidoc[] -include::Nearby-Devices.asciidoc[] +include::Crash-Protection.asciidoc[] -include::Call-Management.asciidoc[] += Testing, performance and debugging -include::VPN.asciidoc[] +include::Testing-with-JUnit.adoc[] -include::Health.asciidoc[] +include::performance.asciidoc[] -include::Smart-Home.asciidoc[] +include::On-Device-Debugging.asciidoc[] -include::Printing.asciidoc[] +include::On-Device-Debugging-Android.asciidoc[] -include::Network-Connectivity.asciidoc[] += Build, sign and ship include::signing.asciidoc[] -include::Working-With-iOS.asciidoc[] +include::App-Store-Submission.asciidoc[] -include::On-Device-Debugging.asciidoc[] += Platform guides -include::On-Device-Debugging-Android.asciidoc[] +include::Working-With-iOS.asciidoc[] include::Working-With-Javascript.asciidoc[] @@ -187,23 +217,28 @@ include::Working-with-Mac-OS-X.asciidoc[] include::Working-with-Mac-Catalyst.asciidoc[] -include::App-Store-Submission.asciidoc[] +include::Working-With-Windows.asciidoc[] + +include::Working-With-Linux.asciidoc[] include::Desktop-Integration.asciidoc[] include::Desktop-Windows.asciidoc[] -include::Working-With-Windows.asciidoc[] -include::Working-With-Linux.asciidoc[] - include::Wearables.asciidoc[] include::TVPlatforms.asciidoc[] += Under the hood + +include::Advanced-Topics-Under-The-Hood.asciidoc[] + include::Working-With-CodenameOne-Sources.asciidoc[] include::Skin-Designer.asciidoc[] += Appendices + include::Maven-Appendix-Archetypes.adoc[] include::Maven-Appendix-Goals.adoc[] diff --git a/docs/developer-guide/img/game-figure-3.png b/docs/developer-guide/img/game-figure-3.png deleted file mode 100644 index 59c74d46d59..00000000000 Binary files a/docs/developer-guide/img/game-figure-3.png and /dev/null differ diff --git a/docs/developer-guide/img/gaming-fig2.png b/docs/developer-guide/img/gaming-fig2.png deleted file mode 100644 index fb53fd69f7b..00000000000 Binary files a/docs/developer-guide/img/gaming-fig2.png and /dev/null differ diff --git a/docs/developer-guide/io.asciidoc b/docs/developer-guide/io.asciidoc index efea84b16ca..43a688bb488 100644 --- a/docs/developer-guide/io.asciidoc +++ b/docs/developer-guide/io.asciidoc @@ -97,13 +97,7 @@ The `FileSystemStorage` API provides a `getRoots()` call to list the root direct To simplify the process of creating/reading files Codename One provides the `getAppHomePath()` method. This method allows you to get the path to a directory where files can be stored/read. -// HTML_ONLY_START -You can use this directory to place an image to share as you did in the https://www.codenameone.com/manual/components.html#sharebutton-section[share sample]. -// HTML_ONLY_END -//// -//PDF_ONLY You can use this directory to place an image to share as you did in the <>. -//// WARNING: A common Android hack is to write files to the SDCard storage to share them among apps. Android 4.x disabled the ability to write to arbitrary directories on the SDCard even when the appropriate permission was requested. @@ -775,14 +769,7 @@ The simplest usage of `XMLParser` looks a bit like this: The https://www.codenameone.com/javadoc/com/codename1/xml/Element.html[Element] contains children and attributes. It represents a tag within the XML document and even the root document itself. You can iterate over the XML tree to extract the data from within the XML file. -// HTML_ONLY_START -You've had a great sample of working with `XMLParser` in the -https://www.codenameone.com/manual/components.html#tree-section[Tree Section] of this guide. -// HTML_ONLY_END -//// -//PDF_ONLY You've had a great sample of working with `XMLParser` in the <> of this guide. -//// `XMLParser` has the complimentary https://www.codenameone.com/javadoc/com/codename1/xml/XMLWriter.html[XMLWriter] class which can generate XML from the `Element` hierarchy. This allows developers to mutate (change) the elements and save them to a writer stream. @@ -1479,7 +1466,7 @@ You ignored functions, joins, transactions and a lot of other SQL capabilities. You can use SQL directly to use all these capabilities for example: if you begin a transaction before inserting/updating or deleting this will work as advertised but if a rollback occurs your mapping will be unaware of that so you will need to re-fetch the data. -You will notice you mapped autoincrement so you will try to map things that make sense for various use cases, if you've such a use case you'd appreciate pull requests and feedback on the implementation. +The mapping covers autoincrement and the cases that map cleanly onto a table; a use case that needs more than that subset is better served by dropping to SQL directly. ====== Caching/Collision diff --git a/docs/developer-guide/languagetool-accept.txt b/docs/developer-guide/languagetool-accept.txt index 3431b61c540..5b9d2aeaa75 100644 --- a/docs/developer-guide/languagetool-accept.txt +++ b/docs/developer-guide/languagetool-accept.txt @@ -722,3 +722,24 @@ dp # One of the SMS services an application's own server might send the code # through, named alongside Twilio and AWS SNS. Vonage + +# ----------------------------------------------------------------------------- +# ComponentSelector (component-selector.asciidoc). +# ----------------------------------------------------------------------------- +# The author of jQuery, named where the chapter explains where the API's ideas +# came from. +Resig +# A method that changes an object's state, as opposed to an accessor. Standard +# API-design vocabulary, and the word the chapter needs when it contrasts the +# two. +mutator + +# ----------------------------------------------------------------------------- +# Vector and animation images (SVG-Transcoder.asciidoc). +# ----------------------------------------------------------------------------- +# The After Effects plugin whose JSON export the Lottie format is defined by; +# the transcoder reads files it produces. +Bodymovin +# A point in an animation where a property's value is pinned, with the values in +# between interpolated. The universal term across every animation toolchain. +keyframes? diff --git a/docs/developer-guide/performance.asciidoc b/docs/developer-guide/performance.asciidoc index 7d118c6f1d0..fa258c13afc 100644 --- a/docs/developer-guide/performance.asciidoc +++ b/docs/developer-guide/performance.asciidoc @@ -449,20 +449,8 @@ For this purpose the Codename One simulator allows you to slow down networking o When you debug your app with your source code you can place breakpoints deep within Codename One and gain unique insight. You can also use the profilers and profile into Codename One to gain similar performance specific insight. -When you run into a bug or a missing feature you can push that feature/fix back to https://www.codenameone.com/[Codename One] using a pull request. GitHub makes that process trivial and in this new video and slides below you show you how. -The steps to use the code are: - -. Signup for GitHub -. Fork http://github.com/codenameone/CodenameOne and - http://github.com/codenameone/codenameone-skins - (also star and watch the projects for good measure). -. Clone the git URLs from the projects into the IDE using the #Team# -> #Git# -> #Clone# menu option. Notice that you must deselect projects in the IDE for the menu to appear. - -. Download the cn1-binaries project from GitHub https://github.com/codenameone/cn1-binaries/archive/master.zip[here]. -. Unzip the cn1-binaries project and make sure the directory has the name cn1-binaries. Verify that cn1-binaries, CodenameOne and codenameone-skins are within the same parent directory. -.In your own project remove the jars both in the build & run libraries section. Replace the build libraries with the `CodenameOne/CodenameOne` project. Replace the runtime libraries with the `CodenameOne/Ports/JavaSEPort` project. - -This allows you to run the existing Codename One project with the Codename One source code and debug into Codename One. You can now also commit, push and send a pull request with the changes. +Running against the framework sources rather than the released jars is covered in +<>. === Device testing Framework/Unit testing diff --git a/docs/developer-guide/security.asciidoc b/docs/developer-guide/security.asciidoc index 043250ecb88..2fc728c5cbd 100644 --- a/docs/developer-guide/security.asciidoc +++ b/docs/developer-guide/security.asciidoc @@ -61,7 +61,6 @@ include::../demos/common/src/main/java/com/codenameone/developerguide/snippets/g This allows you to type in the first text field and the second text area shows the encoded result. A text area is used so copy/paste is easy. -For your convenience this app can be accessed here: https://www.codenameone.com/demos/StringEncoder/index.html === Storage encryption @@ -193,7 +192,7 @@ The trustworthy way to verify device and app integrity is hardware-backed attest Enable it with a build hint, which bundles the SDK (Android) or links the entitlement (iOS): -* `android.playIntegrity=true` -- bundles the Play Integrity SDK and enables the runtime token API. Optionally add `android.playIntegrity.verifyUrl=https://your-backend/integrity` to *also* attest at launch on a background thread and exit if your backend rejects the token. `android.playIntegrityVersion` overrides the bundled SDK version. +* `android.playIntegrity=true` -- bundles the Play Integrity SDK and enables the runtime token API. Optionally add `android.playIntegrity.verifyUrl=https://backend.example.com/integrity` to *also* attest at launch on a background thread and exit if your backend rejects the token. `android.playIntegrityVersion` overrides the bundled SDK version. * `ios.appAttest=true` -- enables App Attest (DeviceCheck.framework) and the runtime token API. `ios.appAttest.environment` is `development` (debug builds) or `production` (release) by default. The runtime API is identical on both platforms -- request a token bound to a fresh server nonce, then POST it to your backend for verification: diff --git a/maven/core-unittests/src/test/java/com/codename1/capture/VideoCaptureConstraintsTest.java b/maven/core-unittests/src/test/java/com/codename1/capture/VideoCaptureConstraintsTest.java index 7ed8d417e29..b1d4ea1685c 100644 --- a/maven/core-unittests/src/test/java/com/codename1/capture/VideoCaptureConstraintsTest.java +++ b/maven/core-unittests/src/test/java/com/codename1/capture/VideoCaptureConstraintsTest.java @@ -81,6 +81,35 @@ public void testMaxLengthSupportedWhenNoLimitRequested() { Assertions.assertTrue(vcc.isSupported()); } + /// A support predicate must resolve the constraint before it answers. These two + /// did not, so asking one of them FIRST -- before any getter had triggered + /// build() -- compared the caller's preference against a field the platform had + /// never filled in. isSupported() hid it, because isSizeSupported() runs first + /// and does build. The call order in each case below is the whole point. + @FormTest + public void testSupportPredicatesResolveBeforeAnswering() { + try { + VideoCaptureConstraints.init(new VideoCaptureConstraints.Compiler() { + public VideoCaptureConstraints compile(VideoCaptureConstraints cnst) { + // A platform that honours everything it is handed. + return new VideoCaptureConstraints(cnst); + } + }); + + VideoCaptureConstraints quality = new VideoCaptureConstraints() + .preferredQuality(VideoCaptureConstraints.QUALITY_HIGH); + Assertions.assertTrue(quality.isQualitySupported(), + "isQualitySupported() must resolve before comparing"); + + VideoCaptureConstraints fileSize = new VideoCaptureConstraints() + .preferredMaxFileSize(1024); + Assertions.assertTrue(fileSize.isMaxFileSizeSupported(), + "isMaxFileSizeSupported() must resolve before comparing"); + } finally { + VideoCaptureConstraints.init(null); + } + } + /// Partial support: the platform limits duration but not to the requested value. /// Installing a compiler is safe to undo because Java SE never registers one. @FormTest