| name | codename-one |
| description | Build and modify Codename One cross-platform mobile apps (Java 17, Maven, ParparVM/Android/iOS/JavaScript). Use when the project contains a `common/codenameone_settings.properties`, depends on `com.codenameone:codenameone-core`, edits CSS files under `common/src/main/css/`, calls `cn1:run`, `cn1:test`, `cn1:build`, references `com.codename1.ui.*` / `com.codename1.testing.*`, or when the user asks to build a UI, write screen tests, generate screenshots, or compare to Swing/HTML. |
| metadata | {"type":"skill"} |
Codename One — App and UI Authoring Skill
This skill teaches you how to write code for a Codename One (CN1) cross-platform mobile project. Codename One compiles Java/Kotlin bytecode to native iOS, Android, desktop and web. It looks like Java AWT/Swing, behaves like a mobile UI toolkit, and styles with a subset of CSS.
Use this skill when:
- A file you are editing imports
com.codename1.ui.*, com.codename1.io.*, com.codename1.testing.*, or extends com.codename1.system.Lifecycle.
- You are editing a file in
common/src/main/css/ (CN1 CSS).
- You are running
cn1:run, cn1:debug, cn1:test, or cn1:build Maven goals.
- The user asks for a UI screen, a screenshot test, a responsive layout, or wants to convert a Swing/HTML snippet to CN1.
How this skill is organized
SKILL.md (this file) is the top-level cheat sheet. Deeper reference material lives under references/ — pull the relevant file in only when you need it:
references/build-and-run.md — Local vs cloud builds, JDK matrix, Maven goals, codenameone_settings.properties, running the simulator, building for iOS/Android/Web, automated (Enterprise) cloud builds in CI.
references/build-hints.md — Curated index of codename1.arg.* build hints (iOS, Android, push, web).
references/java-api-subset.md — How to inspect the supported Java API subset, IO (Storage, FileSystemStorage), networking (ConnectionRequest, Rest), OAuth/OpenID Connect (OidcClient), WebSockets (cn1lib), concurrency, dates, SQLite. Read this whenever the compliance check fails or when you reach for a java.* API.
references/ui-components.md — Form, Toolbar, Container layouts (Border/Box/Flow/Grid/Layered), common components, navigation, dialogs.
references/binding-and-validation.md — @Bindable / @Bind annotation binding and annotation-driven validation (@Required, @Length, @Regex, @Email, @Url, @Numeric, @ExistIn, @Validate). Read this whenever you see one of those annotations, wire a model to a form, or need to gate a submit button on validation.
references/css.md — CSS capabilities and (important) limitations. Selectors, supported properties, 9-patch borders, theme constants, and the build-time vector transcoder that compiles SVG and Lottie / Bodymovin JSON referenced via url(...) into GeneratedSVGImage subclasses.
references/swing-comparison.md — Mapping Swing concepts and code to Codename One. Read this when porting Swing code.
references/html-css-cheatsheet.md — Converting common HTML/CSS snippets to CN1 components + CSS.
references/android-to-cn1.md — Porting Android (XML + Kotlin/Java) screens to Codename One.
references/testing-and-screenshots.md — AbstractTest, TestUtils, screenshotTest, the cn1:test Maven goal, the screenshot tolerance algorithm.
references/junit-testing.md — Standard JUnit 5 tests against the simulator via @CodenameOneTest. Annotations (@RunOnEdt, @Theme, @DarkMode, @LargerText, @Orientation, @RTL, @SimulatorProperty), how it coexists with cn1:test, and why a headless CI runner has to be configured with Xvfb (or accepts that JUnit test classes will be skipped).
references/mobile-adaptability.md — Density-independent units (mm), convertToPixels, LayeredLayout for responsive design, Display.isTablet(), font scaling.
references/native-interfaces.md — Authoring native interfaces for iOS/Android/JavaScript/Desktop with cn1:generate-native-interfaces and platform callbacks.
references/cn1libs.md — Creating, packaging, and consuming Codename One libraries (Maven and legacy .cn1lib).
references/ai-and-speech.md — LLM client (com.codename1.ai), ChatView, SpeechRecognizer, TextToSpeech, non-prompting SecureStorage overloads, the ML Kit cn1libs, and the simulator's offline Ollama redirect. Read this when the user asks for chat, voice, embeddings, image generation, barcode/document/face detection, or wants to store an LLM API key.
references/snapshot-builds.md — Edge case: compiling against a Codename One SNAPSHOT from git.
references/debugging.md — jdb-attach workflow for an agent: start the simulator paused, set breakpoints, dump locals, drive the session non-interactively from a script.
tools/ — runnable Java 17 single-file utilities. tools/IsApiSupported.java answers "is this java.* class in the CN1 subset?"; tools/IsCssValid.java answers "does this theme.css compile?". Run with java tools/<Name>.java <args>.
When the user's task hits any one of those topics, read the matching reference before generating code. Do not paste large snippets without checking.
Project layout (multi-module Maven)
A CN1 project generated by the initializr has these modules:
my-app/
├── pom.xml # Aggregator. cn1.plugin.version + cn1.version pinned here.
├── common/ # Cross-platform Java/Kotlin source. THIS IS WHERE THE APP LIVES.
│ ├── pom.xml # <source>17</source> <target>17</target> by default
│ ├── codenameone_settings.properties
│ └── src/main/
│ ├── java/<pkg>/<MainClass>.java
│ ├── css/theme.css # CN1 CSS (NOT regular web CSS - see references/css.md)
│ ├── l10n/ # i18n bundles (NOT src/main/resources!)
│ └── guibuilder/ # Optional GUI builder XML
├── javase/ # Desktop simulator port
├── android/ # Android wrapper (built via build server or local Gradle)
├── ios/ # iOS wrapper (ParparVM)
└── javascript/ # TeaVM-based web port
Only edit common/. The platform modules are thin wrappers — touching them is almost always wrong unless you are intentionally writing a native interface.
Java version and language features
This project targets Java 17 (<source>17</source> / <target>17</target> in common/pom.xml, plus codename1.arg.java.version=17 in codenameone_settings.properties). Use:
var for local variable type inference
- Text blocks (
"""...""")
- Records
- Pattern matching for
instanceof
switch expressions
- Lambdas, method references,
Streams
Caveat — the build server cross-compiles to bytecode that ParparVM/TeaVM can consume. Codename One ships a curated subset of the JDK, not the full java.* namespace. The cn1:bytecode-compliance Maven goal runs on every compile and fails the build if you call an unsupported API. The most common gotchas:
- No
java.nio.file.* — use com.codename1.io.FileSystemStorage and Storage.
- No
java.net.http.* / java.net.URLConnection — use com.codename1.io.rest.Rest (preferred) or ConnectionRequest.
- No
java.util.concurrent.locks.* beyond simple synchronized — use Display.getInstance().callSerially(...) or Display.startThread(...).
- No
java.awt.* / javax.swing.* — CN1 has its own UI stack. See references/swing-comparison.md.
- No
java.lang.reflect.* on production builds — works in the simulator only.
- No threads spawned with
new Thread(...).start() for UI work — always go through Display.callSerially or Display.startThread(...).
For the authoritative subset list and IO/networking patterns, read references/java-api-subset.md (which also shows how to grep the java-runtime jar to verify any specific class/method).
The Event Dispatch Thread (EDT)
CN1 has a single EDT, exactly like Swing. All UI mutation must happen on it.
- Inside event listeners and lifecycle callbacks (
start, stop, init) you are already on the EDT.
- From a background thread, hop back with
Display.getInstance().callSerially(() -> { ... }) (or callSeriallyAndWait if you need to block).
- Use
Display.getInstance().startThread(runnable, "name").start() instead of new Thread(...) so cleanup happens correctly across platforms.
references/swing-comparison.md contains a Swing→CN1 EDT idiom table.
The Lifecycle main class
Every CN1 app extends com.codename1.system.Lifecycle (or com.codename1.ui.util.Lifecycle in older code). The four methods you may override:
public class MyAppName extends Lifecycle {
@Override
public void init(Object context) {
}
@Override
public void runApp() {
Form f = new Form("Hello", new BorderLayout());
f.add(BorderLayout.CENTER, new Label("Welcome"));
f.show();
}
@Override
public void stop() { }
@Override
public void destroy() { }
}
Minimal "first screen" pattern
import static com.codename1.ui.CN.*;
import com.codename1.ui.*;
import com.codename1.ui.layouts.*;
Form f = new Form("Profile", BoxLayout.y());
f.getToolbar().addCommandToRightBar("Save", null, e -> save());
f.add(new Label("Name"))
.add(new TextField())
.add(new Button("Submit"));
f.show();
BoxLayout.y() (vertical) and BoxLayout.x() (horizontal) are the most common layouts. Wrap a Form content pane in BorderLayout when you want a header/footer/center split. See references/ui-components.md for the full layout matrix.
CSS in Codename One
CN1 ships with a CSS compiler that bakes common/src/main/css/theme.css into the binary theme resource (theme.res). It supports a deliberate subset of web CSS:
Form {
background-color: #0f172a;
padding: 2mm;
}
Button {
background-color: #1d4ed8;
color: #ffffff;
border: 1px solid #1d4ed8;
border-radius: 3mm;
padding: 2mm 4mm;
}
Button.pressed {
background-color: #1e3a8a;
}
#Constants {
useLargerTextScaleBool: true;
}
Key differences from web CSS (read references/css.md before authoring more):
- Selectors target UIIDs (Codename One component style names), not arbitrary HTML elements.
Button, Form, Label, Toolbar, Title are the most common.
- No descendant combinator, no
:hover, no media queries. State variants are baked: .pressed, .disabled, .selected.
- Units: prefer
mm (millimeters) over px. CN1 converts mm to device pixels via Display.convertToPixels. 1mm ≈ 6-9 px depending on density.
border-radius works but is rasterized at compile time — animating it at runtime requires programmatic styling.
- No
transform, no flex, no grid. Use CN1 Java layouts for arrangement; CSS is only for styling.
- Bundled named colors are limited:
pink, orange, purple, yellow, gray/grey are translated to hex by the initializr, anything else you must specify as hex.
references/html-css-cheatsheet.md shows how to map "I want a flexbox row" / "I want a hero section" / "I want a card" to CN1 idioms.
Adaptability and responsive design
Mobile screens vary wildly. CN1 gives you:
- Density-independent units:
1mm always renders ~1mm tall regardless of pixel density. Always size in mm, not px.
Display.getInstance().convertToPixels(2.5f) — convert millimeters to current device pixels programmatically.
Display.getInstance().isTablet(), Display.getInstance().isPortrait(), Display.getInstance().getDisplayWidth/Height() — branch on form factor.
LayeredLayout with LayeredLayoutConstraint for precise responsive positioning (percent-based insets).
Toolbar automatically reshapes to platform conventions (Android side menu / iOS tab bar).
See references/mobile-adaptability.md for patterns: phone-vs-tablet master-detail, orientation listeners, dynamic font scaling.
Testing
CN1 supports two compatible test styles in the same project:
- Legacy
AbstractTest + cn1:test. Required for tests that must also run on a device (mvn cn1:test -Dtarget=ios). Compiles under the device subset (no reflection, no JavaSE APIs). See references/testing-and-screenshots.md.
- Standard JUnit 5 +
@CodenameOneTest. Runs only in the simulator JVM via Surefire, so you get reflection, Mockito, AssertJ, IDE green-bar integration, -Dtest=Foo#bar filtering. Faster startup. See references/junit-testing.md.
Both runners coexist — cn1:test discovers UnitTest implementers, Surefire discovers @Test methods, they don't trip over each other. Pick per test class.
public class LoginFormTest extends AbstractTest {
@Override public boolean shouldExecuteOnEDT() { return true; }
@Override public boolean runTest() throws Exception {
new MyAppName().runApp();
TestUtils.waitForFormTitle("Login");
TestUtils.setText("usernameField", "alice");
TestUtils.clickButtonByLabel("Sign In");
TestUtils.waitForFormTitle("Home");
return screenshotTest("home-screen-baseline");
}
}
@CodenameOneTest
class GreetingFormTest {
@Test
@RunOnEdt
void formShowsExpectedTitle() {
new Form("Hello").show();
assertEquals("Hello", Display.getInstance().getCurrent().getTitle());
}
}
Run with mvn -pl common cn1:test (cn1:test runner only) or mvn test (both runners). The cn1app archetype already wires up Surefire + JUnit Jupiter in the generated POMs.
screenshotTest(name) captures the current form, compares against a stored baseline under Storage, and returns true if within tolerance. First run records the baseline. See references/testing-and-screenshots.md for the tolerance algorithm and how to validate UI you just wrote.
Important: a "screenshot matches baseline" only proves consistency, not correctness. If you just generated the baseline yourself, you have not validated the screen — visually inspect at least once before treating that baseline as ground truth.
Headless caveat: any simulator-driven test (both flavors) needs an X server / Xvfb to construct the simulator's JFrame. The @CodenameOneTest extension auto-aborts the class on a headless JVM so you get "skipped" instead of "errored"; the cn1:test runner needs you to skip with -DskipTests or run under xvfb-run.
Build and run commands
From the project root:
mvn -pl common cn1:run
mvn -pl common cn1:debug
mvn -pl common cn1:test
mvn -pl android package -Dcodename1.platform=android -Dcodename1.buildTarget=android-device
mvn -pl ios package -Dcodename1.platform=ios -Dcodename1.buildTarget=ios-device
mvn -pl javascript package -Dcodename1.platform=javascript -Dcodename1.buildTarget=javascript
See references/build-and-run.md for the local-vs-cloud matrix, automated-build mode (Enterprise), iOS local-build prerequisites, and the complete goal list. The full codename1.arg.* index lives in references/build-hints.md.
What NOT to do
- Don't use
java.awt.Color / java.awt.Font / javax.swing.* — CN1 has its own Color constants (just int ARGB), Font.createTrueTypeFont, and Component hierarchy.
- Don't add CSS that references web-only properties (
display, flex, position, transform, @media) — the CN1 CSS compiler will silently ignore them or fail.
- Don't put localization bundles under
common/src/main/resources/. The CN1 plugin scans common/src/main/l10n/ (or common/src/main/i18n/); bundles placed anywhere else are NOT baked into theme.res and Resources.getL10N("messages", lang) returns null at runtime.
- Don't spin up
new Thread(...) for UI work — use Display.getInstance().callSerially(...) or Display.startThread(...).
- Don't mutate UI off the EDT. Symptoms: random repaint glitches, native crashes on iOS.
- Don't write screenshot tests where the baseline was just generated by the same code you are validating — that proves nothing.
Sanity-check loop before reporting "done"
For any UI-altering change:
- Run
mvn -pl common cn1:run in the simulator and click through the changed flow.
- Inspect at least one screenshot (capture via the simulator menu → Save Screenshot, or generate via a test).
- Resize the simulator window or toggle a different skin to confirm the layout doesn't break on a different form factor.
- If you wrote a
screenshotTest, delete the auto-generated baseline once if the screen has changed, then re-run twice — the second run should pass with true.
If you cannot run the simulator (e.g. headless environment), say so explicitly in the response rather than claiming the UI works.
Reference quick-look index
| If the user asks for... | Open this reference |
|---|
| "Add a screen with a list / form / dialog" | references/ui-components.md |
"Wire this form to a model" / "Validate this form" / @Bindable, @Required, @Email, ... | references/binding-and-validation.md |
| "Make this look like X" / CSS tweaks | references/css.md |
| "Port this from Swing" / Swing idioms | references/swing-comparison.md |
| "I have HTML/CSS, convert it" | references/html-css-cheatsheet.md |
| "I have Android XML/Kotlin/Java, convert it" | references/android-to-cn1.md |
| "Write a test for this screen" / "Compare to a baseline" | references/testing-and-screenshots.md |
| "Make it look right on tablet/landscape" | references/mobile-adaptability.md |
| "How do I run/build/deploy" | references/build-and-run.md |
"What's the right codename1.arg.* for X" / native config | references/build-hints.md |
| "Why does the compliance check fail" / Java/IO/networking | references/java-api-subset.md |
| "I need to call a native iOS/Android/JS/desktop API" | references/native-interfaces.md |
| "How do I create / consume a cn1lib" | references/cn1libs.md |
| "Add a chatbot" / "Integrate OpenAI/Ollama/Anthropic" / "Stream LLM tokens" / "Generate an image" / "Embed text" | references/ai-and-speech.md |
| "Read voice input" / "Speak text aloud" / "Add a voice button to my chat" | references/ai-and-speech.md |
| "Scan a barcode" / "Detect a face" / "Crop a document photo" via ML Kit | references/ai-and-speech.md |
| "Store an LLM API key" / non-prompting SecureStorage | references/ai-and-speech.md |
| "Build against a Codename One SNAPSHOT from git" | references/snapshot-builds.md |
"Debug a faulty screen — attach jdb to the simulator" | references/debugging.md |
Quick yes/no check: "is this java.* class supported", "does my theme.css compile" | tools/ directory — java tools/IsApiSupported.java <class> / java tools/IsCssValid.java <file> |