| 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), 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/css.md — CSS capabilities and (important) limitations. Selectors, supported properties, 9-patch borders, theme constants.
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.
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:compliance-check 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 |
| "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 |
| "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> |