# Codename One

> 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.

- Skill: `eugenp/codename-one` (Agent Skill, multi-file: 19 files)
- Install (CLI): `npx skillmds@latest add eugenp/codename-one`
- Raw SKILL.md: https://api.skillmd.com/api/skills/eugenp/codename-one/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: eugenp (https://skillmd.com/u/eugenp)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/eugenp/codename-one

---


# 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.
- `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/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, `Stream`s

**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:

```java
public class MyAppName extends Lifecycle {
    @Override
    public void init(Object context) {
        // Called once on the EDT. The Lifecycle base class already installs
        // the theme; reach for the cached global resources instance from
        // here on (Resources.getGlobalResources() returns the in-RAM copy,
        // no disk re-read).
    }

    @Override
    public void runApp() {
        // Build and show the first form.
        Form f = new Form("Hello", new BorderLayout());
        f.add(BorderLayout.CENTER, new Label("Welcome"));
        f.show();
    }

    @Override
    public void stop() { /* App backgrounded */ }

    @Override
    public void destroy() { /* App killed */ }
}
```

## Minimal "first screen" pattern

```java
import static com.codename1.ui.CN.*;       // Convenience statics: callSerially, etc.
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:

```css
Form {
    background-color: #0f172a;        /* hex, rgb(), or named colors */
    padding: 2mm;                     /* mm is the recommended unit */
}

Button {
    background-color: #1d4ed8;
    color: #ffffff;
    border: 1px solid #1d4ed8;
    border-radius: 3mm;
    padding: 2mm 4mm;
}

Button.pressed {                      /* state pseudo-class baked as UIID */
    background-color: #1e3a8a;
}

#Constants {
    useLargerTextScaleBool: true;     /* theme constants, not standard CSS */
}
```

**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:

1. **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`.
2. **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.

```java
// Legacy AbstractTest -- compiles under the device subset, runs via `cn1:test`.
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");
    }
}

// JUnit 5 -- simulator-only, runs via `mvn test` / Surefire.
@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:

```bash
# Run in the desktop simulator (requires JDK 11–25 at runtime; build still uses JDK 17 source level)
mvn -pl common cn1:run

# Run with breakpoints
mvn -pl common cn1:debug

# Execute the CN1 test runner
mvn -pl common cn1:test

# Cloud build for Android/iOS/JS (requires CN1 build server creds)
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:

1. Run `mvn -pl common cn1:run` in the simulator and click through the changed flow.
2. Inspect at least one screenshot (capture via the simulator menu → Save Screenshot, or generate via a test).
3. Resize the simulator window or toggle a different skin to confirm the layout doesn't break on a different form factor.
4. 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>` |

