diff --git a/.github/workflows/ant.yml b/.github/workflows/ant.yml index cc2440d66a5..5ce59f973b9 100644 --- a/.github/workflows/ant.yml +++ b/.github/workflows/ant.yml @@ -46,24 +46,44 @@ jobs: - name: Install dependencies run: bash scripts/ci/apt-get-install.sh xvfb - name: Build with Maven (core + in-tree archetypes) + # Every other Maven step in this repository goes through the shared retry + # helper because Maven Central answers 403/429 from the runner CDN edge + # often enough to kill a step outright -- it dies resolving a dependency + # POM, before a line is compiled, so nothing about the branch is being + # tested when it happens. This workflow was the one that never did, and it + # is a required check. RETRY_ONLY_MATCHING keeps every other failure + # failing on the first attempt, so a re-run cannot launder a flaky test + # into a pass. + env: + # These two steps only download and build, so a fetch that never reached + # its host is retried here as well -- the skins zip comes from github.com + # over the same runner network, and a DNS failure there killed the branch + # while Ant's own was still inside the outage. NOT added to + # the test step below, where retrying a network-dependent test would + # launder exactly the flake this repository requires to be root-caused. + RETRY_ONLY_MATCHING: 'status( code)?: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Could not collect dependencies|UnknownHostException|Unknown host|Connection timed out|Connection reset|Premature end of Content-Length|Error getting https' run: | # The cn1{app,lib}-archetype modules are part of the maven/ reactor, # so this single install also stages them into the local repo. # -Darchetype.test.skip=true keeps the build fast; the heavier # archetype ITs run in the release workflow. cd maven - xvfb-run -a mvn install -Plocal-dev-javase -Darchetype.test.skip=true + bash ../scripts/ci/retry.sh xvfb-run -a mvn install -Plocal-dev-javase -Darchetype.test.skip=true - name: Refresh archetype catalog + env: + RETRY_ONLY_MATCHING: 'status( code)?: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Could not collect dependencies|UnknownHostException|Unknown host|Connection timed out|Connection reset|Premature end of Content-Length|Error getting https' run: | cd maven - xvfb-run -a mvn archetype:update-local-catalog -Plocal-dev-javase - xvfb-run -a mvn archetype:crawl -Plocal-dev-javase + bash ../scripts/ci/retry.sh xvfb-run -a mvn archetype:update-local-catalog -Plocal-dev-javase + bash ../scripts/ci/retry.sh xvfb-run -a mvn archetype:crawl -Plocal-dev-javase - name: Run Maven Unit Tests + env: + RETRY_ONLY_MATCHING: 'status( code)?: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Could not collect dependencies' run: | pwd - xvfb-run -a bash tests/all.sh + bash scripts/ci/retry.sh xvfb-run -a bash tests/all.sh cd maven/integration-tests - xvfb-run -a bash all.sh + bash ../../scripts/ci/retry.sh xvfb-run -a bash all.sh diff --git a/.github/workflows/archetype-smoke.yml b/.github/workflows/archetype-smoke.yml index d2dab9f6bc2..52e5d0efb8d 100644 --- a/.github/workflows/archetype-smoke.yml +++ b/.github/workflows/archetype-smoke.yml @@ -64,7 +64,7 @@ jobs: # before it had installed anything, one of several jobs Maven Central refused on this # branch in a day. A build failure in our own code still fails on the first attempt. env: - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' RETRY_ATTEMPTS: '5' RETRY_DELAY_SECONDS: '60' run: | diff --git a/.github/workflows/designer.yml b/.github/workflows/designer.yml index 3659f5985e9..1e717dde99f 100644 --- a/.github/workflows/designer.yml +++ b/.github/workflows/designer.yml @@ -86,7 +86,7 @@ jobs: # without it, so a test that failed once and passed on a later attempt would take # this gate green and hide the race that produced it. The wrapper's own docs # require this filter for test-running commands. - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' run: | cd maven bash $GITHUB_WORKSPACE/scripts/ci/retry.sh mvn -B -pl designer -am -DunitTests=true -Dcodename1.platform=javase \ diff --git a/.github/workflows/developer-guide-docs.yml b/.github/workflows/developer-guide-docs.yml index 6fa6502001c..34c2541398e 100644 --- a/.github/workflows/developer-guide-docs.yml +++ b/.github/workflows/developer-guide-docs.yml @@ -8,6 +8,14 @@ on: - 'docs/demos/**' - 'scripts/developer-guide/**' - '.github/workflows/developer-guide-docs.yml' + # The build hint table is rendered from the catalog rather than committed, + # so a change to either the catalog or the renderer changes what this guide + # contains without touching a single file under docs/. While the table was + # checked in that edit showed up as a docs diff and triggered this workflow + # for free; generating it on the fly took that away, and a malformed table + # would then have merged and surfaced in the release documentation build. + - 'maven/build-hint-catalog/**' + - 'scripts/gen-build-hint-table.sh' release: types: [published] workflow_dispatch: @@ -39,6 +47,11 @@ jobs: - 'scripts/developer-guide/migrate-inline-guide-snippets.py' - 'scripts/developer-guide/validate-guide-snippets.py' - '.github/workflows/developer-guide-docs.yml' + # Triggering the workflow is not enough on its own: the HTML and PDF + # build and the steps beside it are gated on this filter, so the + # inputs the table is rendered from have to satisfy it too. + - 'maven/build-hint-catalog/**' + - 'scripts/gen-build-hint-table.sh' workflow: - '.github/workflows/developer-guide-docs.yml' @@ -48,6 +61,15 @@ jobs: distribution: 'temurin' java-version: '17' + # Before anything that reads the guide. The build hint table is rendered + # from maven/build-hint-catalog rather than checked in, so the lint, the + # image and snippet checks, the HTML and PDF build and Vale all need it on + # disk -- and asciidoctor reports a missing include as an error, so getting + # this order wrong fails loudly rather than dropping the table quietly. + # Unconditional, because every one of those steps is not. + - name: Render the build hint table + run: scripts/gen-build-hint-table.sh + - name: Install local Codename One Maven artifacts if: github.event_name != 'pull_request' || steps.changes.outputs.docs == 'true' || steps.changes.outputs.demos == 'true' || steps.changes.outputs.workflow == 'true' run: | diff --git a/.github/workflows/identity-stack.yml b/.github/workflows/identity-stack.yml index 104e0d4c4be..175925a388a 100644 --- a/.github/workflows/identity-stack.yml +++ b/.github/workflows/identity-stack.yml @@ -127,7 +127,7 @@ jobs: # without it, so a test that failed once and passed on a later attempt would take # this gate green and hide the race that produced it. The wrapper's own docs # require this filter for test-running commands. - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' run: | set -euo pipefail # Targeted run: OidcCoreTest is the new suite; the *Connect / Login / diff --git a/.github/workflows/parparvm-tests-windows.yml b/.github/workflows/parparvm-tests-windows.yml index 9da29f706a9..6a587c969a9 100644 --- a/.github/workflows/parparvm-tests-windows.yml +++ b/.github/workflows/parparvm-tests-windows.yml @@ -229,7 +229,7 @@ jobs: # exists for. A blanket loop lets an intermittent product regression pass on # attempt two and turns a blocking gate green -- which is the opposite of what # a gate is for, and worse than the flake it was hiding. - $resolutionFailure = 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Could not resolve dependencies' + $resolutionFailure = 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Could not resolve dependencies' $ok = $false foreach ($delay in 0, 30, 90, 180, 300) { if ($delay -gt 0) { diff --git a/.github/workflows/parparvm-tests.yml b/.github/workflows/parparvm-tests.yml index 6b2b17a02c5..e1938be54d1 100644 --- a/.github/workflows/parparvm-tests.yml +++ b/.github/workflows/parparvm-tests.yml @@ -124,7 +124,7 @@ jobs: retry mvn -B clean package -pl JavaAPI -am -DskipTests retry mvn -B test -pl tests -am -DexcludedGroups=benchmark env: - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' JDK_8_HOME: ${{ env.JDK_8_HOME }} JDK_11_HOME: ${{ env.JDK_11_HOME }} JDK_17_HOME: ${{ env.JDK_17_HOME }} @@ -139,7 +139,7 @@ jobs: # without it, so a test that failed once and passed on a later attempt would take # this gate green and hide the race that produced it. The wrapper's own docs # require this filter for test-running commands. - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' JDK_8_HOME: ${{ env.JDK_8_HOME }} JDK_11_HOME: ${{ env.JDK_11_HOME }} JDK_17_HOME: ${{ env.JDK_17_HOME }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index dcc8f9990c1..f46993920c3 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -27,6 +27,16 @@ on: - 'scripts/ci/retry.sh' - 'scripts/ci/apt-get-update.sh' - 'scripts/ci/apt-get-install.sh' + # The build hint gates are run from this workflow and nowhere else, and one + # of them holds an empty baseline. Ignoring the whole directory meant a + # change that breaks a gate, or that adds a line to the baseline, could + # merge without the gate it weakens ever running. + - 'scripts/check-build-hint-catalog.sh' + - 'scripts/check-build-hint-catalog.py' + - 'scripts/build_hint_miner.py' + - 'scripts/build-hint-catalog-baseline.txt' + - 'scripts/build-hint-computed-sites.txt' + - 'scripts/gen-build-hint-annotations.sh' - '!docs/**' - '!**/*.md' - '!.github/workflows/developer-guide-docs.yml' @@ -59,6 +69,16 @@ on: - 'scripts/ci/retry.sh' - 'scripts/ci/apt-get-update.sh' - 'scripts/ci/apt-get-install.sh' + # The build hint gates are run from this workflow and nowhere else, and one + # of them holds an empty baseline. Ignoring the whole directory meant a + # change that breaks a gate, or that adds a line to the baseline, could + # merge without the gate it weakens ever running. + - 'scripts/check-build-hint-catalog.sh' + - 'scripts/check-build-hint-catalog.py' + - 'scripts/build_hint_miner.py' + - 'scripts/build-hint-catalog-baseline.txt' + - 'scripts/build-hint-computed-sites.txt' + - 'scripts/gen-build-hint-annotations.sh' - '!docs/**' - '!**/*.md' - '!.github/workflows/developer-guide-docs.yml' @@ -140,7 +160,7 @@ jobs: # RETRY_ONLY_MATCHING keeps a failing test failing on the first attempt # rather than letting a re-run launder a flake into a pass. env: - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM' run: | MVN_GOAL="verify" MVN_ARGS="" @@ -416,6 +436,20 @@ jobs: - name: Run SpotBugs for ByteCodeTranslator if: ${{ matrix.java-version == 8 }} run: mvn -B -DskipTests=true -f vm/ByteCodeTranslator/pom.xml verify + # A build hint is a string nothing checks: a misspelled name is accepted, + # never read, and silently does nothing. The catalog in + # maven/build-hint-catalog is what gives every hint a type, a default and a + # value domain, and it is what the @Ios/@Android annotations, the developer + # guide table and the Settings tool are generated from. These two steps keep + # the catalog complete and the generated files in step with it. + - name: Check build hint catalog + if: ${{ matrix.java-version == 8 }} + run: scripts/check-build-hint-catalog.sh + - name: Check generated build hint annotations + if: ${{ matrix.java-version == 8 }} + run: | + git config --global --add safe.directory "$GITHUB_WORKSPACE" + scripts/gen-build-hint-annotations.sh --check # ParparVM's CHECKCAST is unchecked, so a failed cast does not throw # ClassCastException on iOS -- code written to catch it silently uses the # wrong object instead (issue #5531). core/android/ios are already compiled @@ -449,7 +483,7 @@ jobs: # could not be resolved" before a single test had run -- a Maven Central failure, which a # missing plugin version fails identically on every attempt anyway. env: - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' # Five attempts a minute apart rather than three at thirty seconds: Central # refused two different jobs on this branch today, and a window of about a # minute is shorter than the incidents have been. It costs nothing on a real diff --git a/.github/workflows/protocol-e2e.yml b/.github/workflows/protocol-e2e.yml index 00dd7f0568c..cf9805ca442 100644 --- a/.github/workflows/protocol-e2e.yml +++ b/.github/workflows/protocol-e2e.yml @@ -40,7 +40,7 @@ jobs: # here with "Unresolveable build extension: archetype-packaging ... could not be resolved" # before anything was compiled, which is Maven Central rather than this repository. env: - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' # Five attempts a minute apart rather than three at thirty seconds: Central # refused two different jobs on this branch today, and a window of about a # minute is shorter than the incidents have been. It costs nothing on a real diff --git a/.github/workflows/purchase-e2e.yml b/.github/workflows/purchase-e2e.yml index fb4af2d22fe..0fe96b1b7dd 100644 --- a/.github/workflows/purchase-e2e.yml +++ b/.github/workflows/purchase-e2e.yml @@ -104,7 +104,7 @@ jobs: # with "authorization failed for https://repo.maven.apache.org/maven2" against the JUnit # BOM and the publishing plugin -- Maven Central, not this repository. env: - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|or one of its dependencies could not be resolved|authorization failed for https://repo\.maven\.apache\.org|Connection reset|Premature end of Content-Length' # Five attempts a minute apart rather than three at thirty seconds: Central # refused two different jobs on this branch today, and a window of about a # minute is shorter than the incidents have been. It costs nothing on a real diff --git a/.github/workflows/release-on-maven-central.yml b/.github/workflows/release-on-maven-central.yml index aaa3360b592..4303aedc1dc 100644 --- a/.github/workflows/release-on-maven-central.yml +++ b/.github/workflows/release-on-maven-central.yml @@ -113,12 +113,13 @@ jobs: # "Deployment failed while publishing" even when the bundle was # actually accepted and published. As a safety net for that # false-positive case, poll Maven Central for the key artifacts: - # the codenameone-maven-plugin (proxy for the core release), its - # platform-feature-catalog dependency, and both archetypes. The - # catalog is a separate reactor artifact used by the local builders - # for built-in platform dependency selection, so confirming only the - # plugin could leave a released plugin with an unavailable runtime - # dependency. Skipped when the deploy already reported success (the + # the codenameone-maven-plugin (proxy for the core release), the two + # catalogs it depends on at runtime, and both archetypes. Each catalog + # is a separate reactor artifact -- platform-feature-catalog for + # built-in platform dependency selection, build-hint-catalog for the + # build hint table the plugin reads -- so confirming only the plugin + # could leave a released plugin whose own dependency will not resolve. + # Skipped when the deploy already reported success (the # artifacts may still be propagating from Sonatype Central to repo1; # that propagation can take 30+ minutes and isn't worth blocking on). set +e @@ -127,16 +128,19 @@ jobs: "https://repo1.maven.org/maven2/com/codenameone/codenameone-maven-plugin/${GITHUB_REF_NAME}/codenameone-maven-plugin-${GITHUB_REF_NAME}.pom") catalog_code=$(curl -s -o /dev/null -w "%{http_code}" \ "https://repo1.maven.org/maven2/com/codenameone/codenameone-platform-feature-catalog/${GITHUB_REF_NAME}/codenameone-platform-feature-catalog-${GITHUB_REF_NAME}.pom") + hints_code=$(curl -s -o /dev/null -w "%{http_code}" \ + "https://repo1.maven.org/maven2/com/codenameone/codenameone-build-hint-catalog/${GITHUB_REF_NAME}/codenameone-build-hint-catalog-${GITHUB_REF_NAME}.pom") app_code=$(curl -s -o /dev/null -w "%{http_code}" \ "https://repo1.maven.org/maven2/com/codenameone/cn1app-archetype/${GITHUB_REF_NAME}/cn1app-archetype-${GITHUB_REF_NAME}.pom") lib_code=$(curl -s -o /dev/null -w "%{http_code}" \ "https://repo1.maven.org/maven2/com/codenameone/cn1lib-archetype/${GITHUB_REF_NAME}/cn1lib-archetype-${GITHUB_REF_NAME}.pom") if [ "$plugin_code" = "200" ] && [ "$catalog_code" = "200" ] && \ + [ "$hints_code" = "200" ] && \ [ "$app_code" = "200" ] && [ "$lib_code" = "200" ]; then - echo "Confirmed plugin + platform-feature-catalog + cn1{app,lib}-archetype ${GITHUB_REF_NAME} on Maven Central" + echo "Confirmed plugin + platform-feature-catalog + build-hint-catalog + cn1{app,lib}-archetype ${GITHUB_REF_NAME} on Maven Central" exit 0 fi - echo "[$i/90] Waiting on Maven Central (plugin=$plugin_code, catalog=$catalog_code, cn1app=$app_code, cn1lib=$lib_code)" + echo "[$i/90] Waiting on Maven Central (plugin=$plugin_code, catalog=$catalog_code, hints=$hints_code, cn1app=$app_code, cn1lib=$lib_code)" sleep 20 done echo "Artifacts ${GITHUB_REF_NAME} did not appear on Maven Central within 30 minutes" @@ -153,6 +157,7 @@ jobs: # this keeps the release green even if that rule is ever removed. set -e for artifact in codenameone-core codenameone-maven-plugin codenameone-platform-feature-catalog \ + codenameone-build-hint-catalog \ cn1app-archetype cn1lib-archetype; do url="${R2_BASE_URL}/com/codenameone/${artifact}/${GITHUB_REF_NAME}/${artifact}-${GITHUB_REF_NAME}.pom?cb=${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" code=$(curl -s -o /dev/null -w "%{http_code}" "$url") diff --git a/.github/workflows/windows-cross-build-run.yml b/.github/workflows/windows-cross-build-run.yml index 3e258f275cc..80fff9ce60e 100644 --- a/.github/workflows/windows-cross-build-run.yml +++ b/.github/workflows/windows-cross-build-run.yml @@ -213,7 +213,7 @@ jobs: # translation failure that came and went would have passed on attempt two and taken # the gate green with it -- laundering exactly the kind of intermittent product bug # this job exists to catch. The unit test workflow narrows it for the same reason. - RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' + RETRY_ONLY_MATCHING: 'status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Connection reset|Premature end of Content-Length' run: | cd vm # Through the retry wrapper: this resolves plugins from Maven Central and the runner diff --git a/.github/workflows/windows-cross-compile.yml b/.github/workflows/windows-cross-compile.yml index 7f245f37fb3..f65ff8b682a 100644 --- a/.github/workflows/windows-cross-compile.yml +++ b/.github/workflows/windows-cross-compile.yml @@ -121,7 +121,7 @@ jobs: # retries reuse the previous attempt's target directories, so a partial output # can decide the result. Matching the output keeps a real failure terminal on # its first occurrence, and the retry starts from clean. - resolution='status: (403|429|50[0-9])|Could not transfer artifact|Unresolveable build extension|Non-resolvable import POM|Could not resolve dependencies' + resolution='status: (403|429|50[0-9])|Could not transfer artifact|Failed to read artifact descriptor|Unresolveable build extension|Non-resolvable import POM|Could not resolve dependencies' goal=install for delay in 30 120 300 0; do # PIPESTATUS, not the pipeline's status: tee succeeds even when mvn does not, diff --git a/.gitignore b/.gitignore index 7e03930d3cd..73beabfb303 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,15 @@ !maven/cn1app-archetype/src/main/resources/archetype-resources/.idea !maven/cn1app-archetype/src/main/resources/archetype-resources/.idea/** **/build/* +# ...but `build` is also a legitimate Java package name, and com.codename1.build.shared +# is where the catalogs shared with the build service live. Without these, a new file +# there is silently untracked: `git add` skips it, the module compiles locally from the +# working tree, and CI fails with "No sources to compile". The existing files in that +# package survive only because they were added before the rule above. +!**/src/main/java/**/build/ +!**/src/main/java/**/build/** +!**/src/test/java/**/build/ +!**/src/test/java/**/build/** **/dist/* *.zip CodenameOneDesigner/src/version.properties @@ -133,6 +142,12 @@ scripts/fidelity-app/common/src/main/resources/*ThemeDev.res scripts/fidelity-app/common/src/main/resources/iOSModernTheme.res scripts/fidelity-app/common/src/main/resources/AndroidMaterialTheme.res +# Rendered from maven/build-hint-catalog by scripts/gen-build-hint-table.sh every +# time the developer guide is built. Not checked in: a generated file living in +# git invites a hand edit that the next regeneration silently discards, and needs +# a drift gate to notice. Generating it on the fly removes both. +docs/developer-guide/_generated-build-hints.adoc + # Maven repository private to THIS checkout. # # Several CodenameOne checkouts live on the same machine and all install diff --git a/CLAUDE.md b/CLAUDE.md index 3ec43bd914a..d266d99490f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -213,6 +213,47 @@ removing one can make a previously-used private method dead. Findings land in each module's `target/spotbugsXml.xml`. +### Build hints are a catalog, not free-form strings + +A build hint is a `codename1.arg.=` line that reaches a builder as +`request.getArg(name, default)`. Nothing used to check the name, so a misspelled +hint was accepted, never read, and silently did nothing -- a green build with the +setting simply not applied. Our own agent reference shipped +`android.xPermissions`, `android.minSdkVersion` and `android.sdkVersion` for +years; the builders read `android.xpermissions`, `android.min_sdk_version`, and +nothing at all. + +**`maven/build-hint-catalog` is the single source of truth.** Every hint's name, +type, default, value domain, merge separator and documentation lives there, and +everything else is generated from it: + +- the `com.codename1.annotations.buildhints` annotations in `CodenameOne/src` +- `BuildHintAnnotationBinding`, which the annotation processor reads back +- the developer guide's build hint table, rendered by + `scripts/gen-build-hint-table.sh` every time the guide is built and **not** + checked in (both renderers -- `developer-guide-docs.yml` and + `scripts/website/build.sh` -- call it first) +- the simulator's Build Hint editor schema (`BuildHintCatalogDefaults`) +- the agent reference's annotation table (`skill/references/build-hints.md`) + +Adding a hint to a builder means adding it to the catalog in the same change. +Regenerate with: + +```bash +source tools/env.sh +scripts/gen-build-hint-annotations.sh # rewrite the generated files +scripts/gen-build-hint-annotations.sh --check # what CI runs +scripts/check-build-hint-catalog.sh # every hint the code reads is catalogued +``` + +`scripts/build-hint-catalog-baseline.txt` is a ratchet, and it is **empty**: every +hint the code reads is described. A new entry means a hint went in without a +catalog row. The same gate refuses a `codename1.arg.*` key in our own docs and +project templates that no builder reads. + +Do not re-run `tools/build-hint-bootstrap/` -- it seeded the catalog once and +would overwrite hand edits. + ### Never rely on ClassCastException **ParparVM's `CHECKCAST` is unchecked.** `BC_CHECKCAST` expands to nothing and the diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/Android.java b/CodenameOne/src/com/codename1/annotations/buildhints/Android.java new file mode 100644 index 00000000000..50d7ed12eaa --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/Android.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// Android build hints, checked by the compiler. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Android { + + /// Allows explicitly setting the `android:launchMode` attribute of the main + /// activity in android. Default is "singleTop," but for some applications you + /// may need to change this behaviour. In particular, apps that are meant to + /// open a file type will need to set this to "singleTask." See + /// https://developer.android.com/guide/topics/manifest/activity-element.html[Android + /// docs for the activity element] for more information about the + /// `android:launchMode` attribute. + String activityLaunchMode() default "singleTop"; + + /// Produces an Android App Bundle (.aab) rather than an APK. Required for new + /// Play Store submissions. + boolean appBundle() default false; + + /// Android build-tools version. It also selects the compile SDK, so there is no + /// separate compile-SDK hint. + String buildToolsVersion() default ""; + + /// Indicates whether the `RECORD_AUDIO` permission should be requested. Can be + /// `enabled` or any other value to disable this option + String captureRecord() default "enabled"; + + /// true/false defaults to true - indicates whether to include the debug version + /// in the build. Defaults conditionally rather than to a fixed value: when + /// android.release is on it defaults to false, and when release is off it + /// defaults to true, so a build that selects neither still produces something + /// installable (AndroidGradleBuilder.java:447-451). + boolean debug() default false; + + /// Turns off R8, falling back to the older shrinker. Note that hardening + /// requires R8, so this conflicts with harden.level. + boolean disableR8() default false; + + /// Boolean true/false defaults to true. Allows disabling the proguard + /// obfuscation even on release builds, notice that this isn't recommended + boolean enableProguard() default true; + + /// Gradle dependency statements to add to the app module, such as + /// implementation 'com.example:lib:1.0'. + /// Values are joined with `;` when the hint is written. + String[] gradleDep() default {}; + + /// Hides the Android status bar. + boolean hideStatusBar() default false; + + /// Maps to android:installLocation manifest entry defaults to auto. Can also be + /// set to internalOnly or preferExternal. + InstallLocation installLocation() default InstallLocation.AUTO; + + /// The license key for the Android app, this is required if you use in-app + /// purchase on Android + String licenseKey() default ""; + + /// The least SDK required to run this app, the default value changes based on + /// functionality but can be as low as 7. This corresponds to the XML attribute + /// `android:minSdkVersion`. + int minSdkVersion() default 19; + + /// Boolean true/false defaults to false. Multidex allows Android binaries to + /// reference more than 65536 methods. This slows builds a bit so you have it + /// off by default but if you get a build error mentioning this limit you should + /// turn this on. + boolean multidex() default true; + + /// Uses the current Firebase Cloud Messaging integration. Requires AndroidX and + /// Gradle 8.13 or newer. + boolean newFirebaseMessaging() default true; + + /// Arguments for the keep option in proguard allowing you to keep a pattern of + /// files for example, `-keep class com.mypackage.ProblemClass { *; }` + /// Values are joined with `\n` when the hint is written. + String[] proguardKeep() default {}; + + /// true/false defaults to true - indicates whether to include the release + /// version in the build + boolean release() default true; + + /// Extra Gradle repositories to resolve dependencies from. + /// Values are joined with `\n` when the hint is written. + String[] repositories() default {}; + + /// The Android SDK the build compiles against. Unset, the build server uses the + /// highest platform it has installed, so leaving this alone tracks the server + /// rather than pinning a number. Not every target works: the source may have + /// limitations, and not all SDK targets are installed. + int targetSDKVersion() default 0; + + /// `auto`, `modern` / `material`, `hololight` (default for existing apps), + /// `legacy`. `auto` and `modern` / `material` opt in to the CSS-generated + /// Android Material 3 theme from `native-themes/android-material/theme.css`. + /// `hololight` is Android Holo Light (what the framework shipped on API 14+ + /// before this refactor). `legacy` loads the pre-Holo Android theme. The legacy + /// alias `cn1.androidTheme` is still accepted, and `and.hololight=true` still + /// maps to `hololight`. The default stays on `hololight` for existing apps + /// until you flip in a future release. + AndroidThemeMode themeMode() default AndroidThemeMode.AUTO; + + /// Statements added to the top-level Gradle build file rather than the app + /// module. + /// Values are joined with `\n` when the hint is written. + String[] topDependency() default {}; + + /// Use Android X instead of support libraries. This will also run a + /// find/replace on all source files to replace support libraries and artifacts + /// with AndroidX equivalents. + boolean useAndroidX() default false; + + /// defaults to an empty string. Allows developers of native Android code to add + /// text within the application block to define things such as widgets, services + /// etc. + String xapplication() default ""; + + /// Arbitrary text spliced into the generated app-module Gradle file. + /// Values are joined with `\n` when the hint is written. + String[] xgradle() default {}; + + /// more permissions for the Android manifest + String xpermissions() default ""; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/AndroidThemeMode.java b/CodenameOne/src/com/codename1/annotations/buildhints/AndroidThemeMode.java new file mode 100644 index 00000000000..0fb0d887471 --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/AndroidThemeMode.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `and.themeMode` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum AndroidThemeMode { + AUTO("auto"), + MODERN("modern"), + HOLOLIGHT("hololight"), + LEGACY("legacy"); + + private final String wire; + + AndroidThemeMode(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/Build.java b/CodenameOne/src/com/codename1/annotations/buildhints/Build.java new file mode 100644 index 00000000000..f27777d3518 --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/Build.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// Build hints that are not specific to one platform. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Build { + + /// The application ID for an app that requires native Facebook login + /// integration, this defaults to null which means native Facebook support + /// shouldn't be in the app + String facebookAppId() default ""; + + /// The Android/chrome push identifier, see the push section for more details + String gcmSenderId() default ""; + + /// `modern`, `legacy`, `custom` (default unset). Cross-platform override that + /// sets both `ios.themeMode` and `and.themeMode` together when those aren't set + /// explicitly. `modern` = liquid glass + Material 3, `legacy` = iOS 7 flat + + /// Holo Light, `custom` disables the framework native theme entirely. The + /// legacy alias `cn1.nativeTheme` is still accepted. + NativeThemeMode nativeTheme() default NativeThemeMode.MODERN; + + /// true/false (defaults to false). Blocks codename one from injecting its own + /// resources when set to true, the only effect this has is in slightly reducing + /// archive size. This might have adverse effects on some features of Codename + /// One so it isn't recommended. + boolean noExtraResources() default false; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/Desktop.java b/CodenameOne/src/com/codename1/annotations/buildhints/Desktop.java new file mode 100644 index 00000000000..d8fcae1c401 --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/Desktop.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// Desktop build hints, checked by the compiler. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Desktop { + + /// Boolean true/false defaults to true. When set to true some values will ve + /// implicitly doubled to deal with retina displays and icons etc. Will use + /// higher DPI's + boolean adaptToRetina() default true; + + /// Starts the desktop build in full-screen mode. + boolean fullscreen() default false; + + /// Height in pixels for the form in desktop builds, will be doubled for retina + /// grade displays. Defaults to 600. + int height() default 600; + + /// Enables grab-able, click-to-page desktop scrollbars. + boolean interactiveScrollbars() default true; + + /// Boolean true/false defaults to true. Indicates whether the UI in the desktop + /// build is resizable + boolean resizable() default true; + + /// How the desktop window is framed: native for the OS title bar and menu bar, + /// custom for an undecorated window with a Codename One drawn title bar, or + /// toolbar for the legacy in-app Toolbar. An unrecognized value falls back to + /// native with a warning. + DesktopTitleBar titleBar() default DesktopTitleBar.NATIVE; + + /// Width in pixels for the form in desktop builds, will be doubled for retina + /// grade displays. Defaults to 800. + int width() default 800; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/DesktopTitleBar.java b/CodenameOne/src/com/codename1/annotations/buildhints/DesktopTitleBar.java new file mode 100644 index 00000000000..b9da214763c --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/DesktopTitleBar.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `desktop.titleBar` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum DesktopTitleBar { + NATIVE("native"), + CUSTOM("custom"), + TOOLBAR("toolbar"); + + private final String wire; + + DesktopTitleBar(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/HardenControlFlow.java b/CodenameOne/src/com/codename1/annotations/buildhints/HardenControlFlow.java new file mode 100644 index 00000000000..3e10121724d --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/HardenControlFlow.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `harden.controlFlow` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum HardenControlFlow { + OFF("off"), + ON("on"); + + private final String wire; + + HardenControlFlow(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/HardenLevel.java b/CodenameOne/src/com/codename1/annotations/buildhints/HardenLevel.java new file mode 100644 index 00000000000..ae32518c1be --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/HardenLevel.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `harden.level` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum HardenLevel { + OFF("off"), + STANDARD("standard"), + AGGRESSIVE("aggressive"), + PARANOID("paranoid"); + + private final String wire; + + HardenLevel(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/HardenStrings.java b/CodenameOne/src/com/codename1/annotations/buildhints/HardenStrings.java new file mode 100644 index 00000000000..15f866cd08d --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/HardenStrings.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `harden.strings` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum HardenStrings { + OFF("off"), + CONSTANTS("constants"), + ALL("all"); + + private final String wire; + + HardenStrings(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/Hardening.java b/CodenameOne/src/com/codename1/annotations/buildhints/Hardening.java new file mode 100644 index 00000000000..657ef4e737a --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/Hardening.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// App hardening build hints, checked by the compiler. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Hardening { + + /// Permits a local or source build to run with hardening requested but not + /// applied. Without it such a build is refused, so a hardened app is never + /// shipped from a target that can't actually harden it. + boolean allowUnhardenedLocalBuild() default false; + + /// Overrides control-flow obfuscation independently of harden.level. + HardenControlFlow controlFlow() default HardenControlFlow.OFF; + + /// Keep rules in ProGuard syntax, one per line, for classes that are resolved + /// by name at runtime and so can't be found by the automatic analysis. Same + /// syntax as android.proguardKeep, so existing rules port directly. Rules are + /// separated by newlines only, because a semicolon is legal inside a rule body + /// such as { *; }. + String keep() default ""; + + /// Master switch for app hardening: off, standard, aggressive or paranoid. An + /// unrecognized value fails the build rather than being treated as off. + HardenLevel level() default HardenLevel.OFF; + + /// Overrides symbol renaming independently of harden.level. + boolean rename() default false; + + /// Overrides string obfuscation independently of harden.level: off, constants + /// or all. + HardenStrings strings() default HardenStrings.OFF; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/InstallLocation.java b/CodenameOne/src/com/codename1/annotations/buildhints/InstallLocation.java new file mode 100644 index 00000000000..a1c7655fa57 --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/InstallLocation.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `android.installLocation` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum InstallLocation { + AUTO("auto"), + INTERNAL_ONLY("internalOnly"), + PREFER_EXTERNAL("preferExternal"); + + private final String wire; + + InstallLocation(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/Ios.java b/CodenameOne/src/com/codename1/annotations/buildhints/Ios.java new file mode 100644 index 00000000000..081b7a871bf --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/Ios.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// iOS build hints, checked by the compiler. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface Ios { + + /// A semicolon separated list of libraries that should be linked to the app to + /// build it + /// Values are joined with `;` when the hint is written. + String[] addLibs() default {}; + + /// Comma separated list of url schemes that `canExecute` will respect on iOS. + /// If the url scheme isn't mentioned here `canExecute` will return false + /// starting with iOS 9. Notice that this collides with `ios.plistInject` when + /// used with the `LSApplicationQueriesSchemes...` value so you + /// should use one or the other. For example, to enable `canExecute` for a url + /// like `myurl://xys` you can use: `myurl,myotherurl` + /// Values are joined with `,` when the hint is written. + String[] applicationQueriesSchemes() default {}; + + /// Objective-C code that can be injected into the iOS app delegate at the top + /// of the body of the didFinishLaunchingWithOptions callback method + String beforeFinishLaunching() default ""; + + /// Indicates the version number of the bundle, this is useful if you want to + /// create a minor version number change for the beta testing support + String bundleVersion() default ""; + + /// Which native dependency manager to use: auto picks one from whichever of + /// ios.pods and ios.spm.packages is set, and cocoapods, spm or both require the + /// matching hint to be set. An unrecognized value fails the build. + IosDependencyManager dependencyManager() default IosDependencyManager.AUTO; + + /// Minimum iOS version the build targets. Set it to the lowest iOS you actually + /// support; a higher value excludes older devices from the App Store listing. + String deploymentTarget() default ""; + + /// Objective-C code that can be injected into the iOS app delegate at the top + /// of the file. For example, if you need to include headers or make special + /// imports for other injected code + String glAppDelegateHeader() default ""; + + /// true/false (defaults to false). Whether to include the push capabilities in + /// the iOS build. Notice that the IDE plugin has an "Include Push" check box + /// you *should* use under the iOS section. + boolean includePush() default false; + + /// UIInterfaceOrientationPortrait by default. Indicates the orientation, one or + /// more of (separated by colon :): `UIInterfaceOrientationPortrait`, + /// `UIInterfaceOrientationPortraitUpsideDown`, + /// `UIInterfaceOrientationLandscapeLeft`, + /// `UIInterfaceOrientationLandscapeRight`. Notice that the IDE plugin has an + /// "Interface Orientation" combo box you *should* use under the iOS section. + String interfaceOrientation() default ""; + + /// The null and empty-string reads of this hint are presence checks; 6.0 is the + /// substantive default (IPhoneBuilder.java:4671). + String minDeploymentTarget() default "6.0"; + + /// true/false defaults to false but defined on new projects as true by default. + /// This changes the storage directory on iOS from using caches to using the + /// documents directory which is the recommended location but might break + /// compatibility. This is described in + /// https://github.com/codenameone/CodenameOne/issues/1480[this issue] + boolean newStorageLocation() default true; + + /// Added the `-ObjC` compile flag to the project files which some native + /// libraries require + boolean objC() default false; + + /// entries to inject into the iOS plist file during build. + String plistInject() default ""; + + /// A comma separated list of https://cocoapods.org/[Cocoa Pods] that should be + /// linked to the app to build it. For example, `AFNetworking ~> 2.6, + /// ORStackView ~> 3.0, SwiftyJSON ~> 2.3` + /// Values are joined with `,` when the hint is written. + String[] pods() default {}; + + /// Sets the Cocoapods 'platform' for the Cocoapods. Some Cocoapods require a + /// minimum platform level. For example, `ios.pods.platform=7.0`. + String podsPlatform() default ""; + + /// Extra CocoaPods spec repositories to search, in addition to the default + /// trunk. + /// Values are joined with `,` when the hint is written. + String[] podsSources() default {}; + + /// true/false defaults to false. The iOS build process adapts the submitted + /// icon for iOS conventions (adding an overlay) that might not be appropriate + /// on some icons. Setting this to true leaves the icon unchanged (only scaled). + boolean prerenderedIcon() default false; + + /// one of ios, ipad, iphone (defaults to ios). Indicates whether the resulting + /// binary is targeted to the iphone only or ipad only. Notice that the IDE + /// plugin has a "Project Type" combo box you *should* use under the iOS + /// section. + IosProjectType projectType() default IosProjectType.IOS; + + /// Swift Package Manager packages to link, one per entry, each written as + /// identity|url|requirement. + /// Values are joined with `;` when the hint is written. + String[] spmPackages() default {}; + + /// Specifies the team ID associated with the iOS provisioning profile and + /// certificate. Use `ios.debug.teamId` and `ios.release.teamId` to specify + /// different team IDs for debug and release builds respectively. + String teamId() default ""; + + /// `auto` (default), `modern`, `ios7`, `legacy`. `auto` (unset) keeps the + /// existing iOS 7 flat theme so pre-refactor screenshot goldens and apps see no + /// behavior change. `modern` / `liquid` opts in to the CSS-generated iOS Modern + /// (liquid-glass) theme shipped from `native-themes/ios-modern/theme.css`. + /// `ios7` / `flat` is the same as `auto` - pre-liquid iOS 7 flat theme; + /// `legacy` / `iphone` loads the pre-iOS 7 iPhone theme. The `auto` -> modern + /// flip is planned for a future release. + IosThemeMode themeMode() default IosThemeMode.AUTO; + + /// true/false (defaults to true). Enables iOS UIScene lifecycle support. + /// UIScene lets iOS manage one or more app UI sessions independently, improving + /// lifecycle handling in modern iOS versions. Apple has indicated UIScene will + /// be required starting with iOS 27, so this is now on by default; set the flag + /// to `false` only if you need to temporarily fall back to the legacy + /// `UIApplicationDelegate` lifecycle. + boolean uiscene() default true; + + /// Allows intercepting a URL call using the syntax `urlPrefix` + String urlScheme() default ""; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/IosDependencyManager.java b/CodenameOne/src/com/codename1/annotations/buildhints/IosDependencyManager.java new file mode 100644 index 00000000000..d30fa80f9ba --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/IosDependencyManager.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `ios.dependencyManager` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum IosDependencyManager { + AUTO("auto"), + COCOAPODS("cocoapods"), + SPM("spm"), + BOTH("both"), + NONE("none"); + + private final String wire; + + IosDependencyManager(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/IosPrivacy.java b/CodenameOne/src/com/codename1/annotations/buildhints/IosPrivacy.java new file mode 100644 index 00000000000..635793e561b --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/IosPrivacy.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// iOS `Info.plist` privacy usage descriptions. Set the one for every protected +/// resource your app touches: the build server accepts an app without them, and +/// the App Store rejects it. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface IosPrivacy { + + /// Why the app uses Bluetooth. Supplied automatically when the app references + /// `com.codename1.bluetooth`; set it to say something more specific than the + /// default. + String bluetoothAlwaysUsageDescription() default ""; + + /// The pre-iOS 13 spelling of the Bluetooth usage description, supplied and + /// overridable on the same terms. + String bluetoothPeripheralUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the calendars full access. It + /// becomes the `NSCalendarsFullAccessUsageDescription` key in `Info.plist`. The + /// App Store rejects an app that touches this resource without one. + String calendarsFullAccessUsageDescription() default "This app uses your calendars to read and schedule events."; + + /// The text iOS shows when the app first asks for the calendars. It becomes the + /// `NSCalendarsUsageDescription` key in `Info.plist`. The App Store rejects an + /// app that touches this resource without one. + String calendarsUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the calendars write only + /// access. It becomes the `NSCalendarsWriteOnlyAccessUsageDescription` key in + /// `Info.plist`. The App Store rejects an app that touches this resource + /// without one. + String calendarsWriteOnlyAccessUsageDescription() default "This app uses your calendar to schedule events."; + + /// The text iOS shows when the app first asks for the camera. It becomes the + /// `NSCameraUsageDescription` key in `Info.plist`. The App Store rejects an app + /// that touches this resource without one. + String cameraUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the health share. It becomes + /// the `NSHealthShareUsageDescription` key in `Info.plist`. The App Store + /// rejects an app that touches this resource without one. + String healthShareUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the health update. It becomes + /// the `NSHealthUpdateUsageDescription` key in `Info.plist`. The App Store + /// rejects an app that touches this resource without one. + String healthUpdateUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the local network. It becomes + /// the `NSLocalNetworkUsageDescription` key in `Info.plist`. The App Store + /// rejects an app that touches this resource without one. + String localNetworkUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the location always and when + /// in use. It becomes the `NSLocationAlwaysAndWhenInUseUsageDescription` key in + /// `Info.plist`. The App Store rejects an app that touches this resource + /// without one. + String locationAlwaysAndWhenInUseUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the location always. It + /// becomes the `NSLocationAlwaysUsageDescription` key in `Info.plist`. The App + /// Store rejects an app that touches this resource without one. + String locationAlwaysUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the location when in use. It + /// becomes the `NSLocationWhenInUseUsageDescription` key in `Info.plist`. The + /// App Store rejects an app that touches this resource without one. + String locationWhenInUseUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the microphone. It becomes + /// the `NSMicrophoneUsageDescription` key in `Info.plist`. The App Store + /// rejects an app that touches this resource without one. + String microphoneUsageDescription() default ""; + + /// The pre-iOS 16 spelling of the nearby-interaction usage description, + /// supplied automatically when the app references the nearby APIs. + String nearbyInteractionAllowOnceUsageDescription() default ""; + + /// Why the app measures distance and direction to nearby devices. Supplied + /// automatically when the app references the nearby APIs; set it to say + /// something more specific than the default. + String nearbyInteractionUsageDescription() default ""; + + /// The text iOS shows when the app first asks for the reminders full access. It + /// becomes the `NSRemindersFullAccessUsageDescription` key in `Info.plist`. The + /// App Store rejects an app that touches this resource without one. + String remindersFullAccessUsageDescription() default "This app uses your reminders to read and schedule tasks."; + + /// The text iOS shows when the app first asks for the reminders. It becomes the + /// `NSRemindersUsageDescription` key in `Info.plist`. The App Store rejects an + /// app that touches this resource without one. + String remindersUsageDescription() default ""; + + /// Why the app sends speech for recognition. Supplied automatically when the + /// app references the speech APIs; set it to say something more specific. + String speechRecognitionUsageDescription() default ""; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/IosProjectType.java b/CodenameOne/src/com/codename1/annotations/buildhints/IosProjectType.java new file mode 100644 index 00000000000..1e18538ee3b --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/IosProjectType.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `ios.project_type` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum IosProjectType { + IOS("ios"), + IPAD("ipad"), + IPHONE("iphone"); + + private final String wire; + + IosProjectType(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/IosThemeMode.java b/CodenameOne/src/com/codename1/annotations/buildhints/IosThemeMode.java new file mode 100644 index 00000000000..ca2a7d24aa7 --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/IosThemeMode.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `ios.themeMode` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum IosThemeMode { + AUTO("auto"), + MODERN("modern"), + IOS7("ios7"), + LEGACY("legacy"); + + private final String wire; + + IosThemeMode(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/NativeThemeMode.java b/CodenameOne/src/com/codename1/annotations/buildhints/NativeThemeMode.java new file mode 100644 index 00000000000..7b9f2291ebb --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/NativeThemeMode.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +/// Accepted values of the `nativeTheme` build hint. +/// +/// Each constant carries the string the build actually receives, which is not +/// always the constant's own name. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +public enum NativeThemeMode { + MODERN("modern"), + LEGACY("legacy"), + CUSTOM("custom"); + + private final String wire; + + NativeThemeMode(String wire) { + this.wire = wire; + } + + /// The value written into the build hint. + public String wireValue() { + return wire; + } +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/OnDeviceDebug.java b/CodenameOne/src/com/codename1/annotations/buildhints/OnDeviceDebug.java new file mode 100644 index 00000000000..21c7a20e283 --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/OnDeviceDebug.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2012, 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.codename1.annotations.buildhints; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/// On-device debugging build hints for iOS and Android. +/// +/// Place this on your application's main class -- the class named by +/// `codename1.mainName`. An attribute you do not set is not written at all, so +/// the builder's own default applies; the values shown here are that default, +/// for reference. +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.TYPE) +public @interface OnDeviceDebug { + + /// Boolean true/false defaults to false. When `true`, the generated + /// `AndroidManifest.xml` is marked `android:debuggable="true"`, R8/proguard is + /// disabled, and the build is pinned to debug-only (`android.release` is forced + /// off and `android.debug` is forced on) so a stray hint can't ship a + /// release-signed APK that's `debuggable="true"`. Pair with the + /// `cn1:android-on-device-debugging` Maven goal (or the bundled IntelliJ run + /// configs) to install, launch, forward JDWP, and stream logcat through adb. + /// Has no effect on builds that don't carry it -- release builds are + /// unaffected. See the On-Device Debugging (Android) chapter for the full flow. + boolean android() default false; + + /// Boolean true/false defaults to false. When `true`, the iOS build links a + /// small JDWP listener thread (`cn1_debugger`) into the binary and the ParparVM + /// translator emits source-line and locals metadata so a desktop proxy can + /// serve the running app to any JDWP-speaking debugger. Has no effect on + /// release builds. See the On-Device Debugging (iOS) chapter for the full flow. + boolean ios() default false; + + /// Hostname or IP address the device-side listener dials to reach the desktop + /// proxy. Default `127.0.0.1` (correct for the native iOS simulator). For a + /// physical device, set this to the developer laptop's LAN IP. Has no effect + /// unless `ios.onDeviceDebug=true`. + String iosProxyHost() default ""; + + /// TCP port on `ios.onDeviceDebug.proxyHost` where the proxy is listening for + /// the device. Default `55333`. Has no effect unless `ios.onDeviceDebug=true`. + int iosProxyPort() default 55333; + + /// Boolean true/false defaults to false. When `true`, the app blocks at startup + /// until the proxy connects and the IDE tells the VM to continue. Useful when + /// the breakpoint to investigate fires during app boot. Has no effect unless + /// `ios.onDeviceDebug=true`. + boolean iosWaitForAttach() default false; +} diff --git a/CodenameOne/src/com/codename1/annotations/buildhints/package-info.java b/CodenameOne/src/com/codename1/annotations/buildhints/package-info.java new file mode 100644 index 00000000000..a4c36dbcccf --- /dev/null +++ b/CodenameOne/src/com/codename1/annotations/buildhints/package-info.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012, 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. + */ +/// Build hints expressed as annotations, so the compiler checks them. +/// +/// A build hint used to be a `codename1.arg.=` line in +/// `codenameone_settings.properties`. Nothing validated it, so a misspelled +/// name was copied into the build request, never read, and silently dropped: +/// the build stayed green and the setting simply did nothing. Written as an +/// annotation the same mistake is an unknown symbol, a wrong value type is a +/// type error, and a value outside a hint's supported set is an unknown enum +/// constant. +/// +/// Put the annotations on your application's main class: +/// +/// ```java +/// @Ios(newStorageLocation = true, themeMode = IosThemeMode.MODERN) +/// @Android(themeMode = AndroidThemeMode.MODERN) +/// @Desktop(titleBar = DesktopTitleBar.NATIVE) +/// public class MyApplication { +/// } +/// ``` +/// +/// These annotations cover the hints most applications set. The rest, and the +/// open-ended families such as `android.permission.` that an annotation +/// cannot express, are still set in `codenameone_settings.properties`, which +/// continues to work exactly as before. Setting the same hint in both places is +/// a build error. +/// +/// A project generated recently already runs the goal that turns these into +/// build hints. An older one may not: a goal's default phase does not add an +/// execution to a project, so the annotations would compile and then be +/// ignored. The build refuses rather than shipping without them, and the module +/// that compiles the main class needs: +/// +/// ```xml +/// +/// cn1-process-classes +/// process-classes +/// +/// process-annotations +/// +/// +/// ``` +/// +/// Generated from com.codename1.build.shared.BuildHints by +/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and +/// re-run scripts/gen-build-hint-annotations.sh. +package com.codename1.annotations.buildhints; diff --git a/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintCatalogDefaults.java b/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintCatalogDefaults.java new file mode 100644 index 00000000000..bcfa12d8761 --- /dev/null +++ b/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintCatalogDefaults.java @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2012, 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.codename1.impl.javase; + +/** + * Build Hint editor schema for every hint that has a build hint annotation. + * + *

Generated from com.codename1.build.shared.BuildHints by + * BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and re-run + * scripts/gen-build-hint-annotations.sh.

+ * + *

Registered after {@link BuildHintSchemaDefaults} and skipping every hint + * that class already describes. Precedence cannot be left to the setter: + * the group name is part of the property key, so registering harden.level + * under both `hardening` and `Hardening` does not overwrite anything -- it + * makes a second group, and the editor renders both, giving the user + * duplicate controls for one setting.

+ */ +final class BuildHintCatalogDefaults { + + private BuildHintCatalogDefaults() { + } + + static void register() { + java.util.Set handWritten = BuildHintSchemaDefaults.declaredHints(); + + set("{{@IosPrivacy}}.label", "iOS Privacy Strings"); + if (!handWritten.contains("ios.NSBluetoothAlwaysUsageDescription")) { + set("{{#IosPrivacy#ios.NSBluetoothAlwaysUsageDescription}}.label", "Bluetooth always usage description"); + set("{{#IosPrivacy#ios.NSBluetoothAlwaysUsageDescription}}.type", "TextField"); + set("{{#IosPrivacy#ios.NSBluetoothAlwaysUsageDescription}}.description", "Why the app uses Bluetooth. Supplied automatically when the app references `com.codename1.bluetooth`; set it to say something more specific than the default."); + } + if (!handWritten.contains("ios.NSBluetoothPeripheralUsageDescription")) { + set("{{#IosPrivacy#ios.NSBluetoothPeripheralUsageDescription}}.label", "Bluetooth peripheral usage description"); + set("{{#IosPrivacy#ios.NSBluetoothPeripheralUsageDescription}}.type", "TextField"); + set("{{#IosPrivacy#ios.NSBluetoothPeripheralUsageDescription}}.description", "The pre-iOS 13 spelling of the Bluetooth usage description, supplied and overridable on the same terms."); + } + if (!handWritten.contains("ios.NSCalendarsFullAccessUsageDescription")) { + set("{{#IosPrivacy#ios.NSCalendarsFullAccessUsageDescription}}.label", "Calendars full access usage description"); + set("{{#IosPrivacy#ios.NSCalendarsFullAccessUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSCalendarsUsageDescription")) { + set("{{#IosPrivacy#ios.NSCalendarsUsageDescription}}.label", "Calendars usage description"); + set("{{#IosPrivacy#ios.NSCalendarsUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSCalendarsWriteOnlyAccessUsageDescription")) { + set("{{#IosPrivacy#ios.NSCalendarsWriteOnlyAccessUsageDescription}}.label", "Calendars write only access usage description"); + set("{{#IosPrivacy#ios.NSCalendarsWriteOnlyAccessUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSCameraUsageDescription")) { + set("{{#IosPrivacy#ios.NSCameraUsageDescription}}.label", "Camera usage description"); + set("{{#IosPrivacy#ios.NSCameraUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSHealthShareUsageDescription")) { + set("{{#IosPrivacy#ios.NSHealthShareUsageDescription}}.label", "Health share usage description"); + set("{{#IosPrivacy#ios.NSHealthShareUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSHealthUpdateUsageDescription")) { + set("{{#IosPrivacy#ios.NSHealthUpdateUsageDescription}}.label", "Health update usage description"); + set("{{#IosPrivacy#ios.NSHealthUpdateUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSLocalNetworkUsageDescription")) { + set("{{#IosPrivacy#ios.NSLocalNetworkUsageDescription}}.label", "Local network usage description"); + set("{{#IosPrivacy#ios.NSLocalNetworkUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSLocationAlwaysAndWhenInUseUsageDescription")) { + set("{{#IosPrivacy#ios.NSLocationAlwaysAndWhenInUseUsageDescription}}.label", "Location always and when in use usage description"); + set("{{#IosPrivacy#ios.NSLocationAlwaysAndWhenInUseUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSLocationAlwaysUsageDescription")) { + set("{{#IosPrivacy#ios.NSLocationAlwaysUsageDescription}}.label", "Location always usage description"); + set("{{#IosPrivacy#ios.NSLocationAlwaysUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSLocationWhenInUseUsageDescription")) { + set("{{#IosPrivacy#ios.NSLocationWhenInUseUsageDescription}}.label", "Location when in use usage description"); + set("{{#IosPrivacy#ios.NSLocationWhenInUseUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSMicrophoneUsageDescription")) { + set("{{#IosPrivacy#ios.NSMicrophoneUsageDescription}}.label", "Microphone usage description"); + set("{{#IosPrivacy#ios.NSMicrophoneUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSNearbyInteractionAllowOnceUsageDescription")) { + set("{{#IosPrivacy#ios.NSNearbyInteractionAllowOnceUsageDescription}}.label", "Nearby interaction allow once usage description"); + set("{{#IosPrivacy#ios.NSNearbyInteractionAllowOnceUsageDescription}}.type", "TextField"); + set("{{#IosPrivacy#ios.NSNearbyInteractionAllowOnceUsageDescription}}.description", "The pre-iOS 16 spelling of the nearby-interaction usage description, supplied automatically when the app references the nearby APIs."); + } + if (!handWritten.contains("ios.NSNearbyInteractionUsageDescription")) { + set("{{#IosPrivacy#ios.NSNearbyInteractionUsageDescription}}.label", "Nearby interaction usage description"); + set("{{#IosPrivacy#ios.NSNearbyInteractionUsageDescription}}.type", "TextField"); + set("{{#IosPrivacy#ios.NSNearbyInteractionUsageDescription}}.description", "Why the app measures distance and direction to nearby devices. Supplied automatically when the app references the nearby APIs; set it to say something more specific than the default."); + } + if (!handWritten.contains("ios.NSRemindersFullAccessUsageDescription")) { + set("{{#IosPrivacy#ios.NSRemindersFullAccessUsageDescription}}.label", "Reminders full access usage description"); + set("{{#IosPrivacy#ios.NSRemindersFullAccessUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSRemindersUsageDescription")) { + set("{{#IosPrivacy#ios.NSRemindersUsageDescription}}.label", "Reminders usage description"); + set("{{#IosPrivacy#ios.NSRemindersUsageDescription}}.type", "TextField"); + } + if (!handWritten.contains("ios.NSSpeechRecognitionUsageDescription")) { + set("{{#IosPrivacy#ios.NSSpeechRecognitionUsageDescription}}.label", "Speech recognition usage description"); + set("{{#IosPrivacy#ios.NSSpeechRecognitionUsageDescription}}.type", "TextField"); + set("{{#IosPrivacy#ios.NSSpeechRecognitionUsageDescription}}.description", "Why the app sends speech for recognition. Supplied automatically when the app references the speech APIs; set it to say something more specific."); + } + + set("{{@Ios}}.label", "iOS"); + if (!handWritten.contains("ios.add_libs")) { + set("{{#Ios#ios.add_libs}}.label", "Add libs"); + set("{{#Ios#ios.add_libs}}.type", "TextArea"); + set("{{#Ios#ios.add_libs}}.description", "A semicolon separated list of libraries that should be linked to the app to build it"); + } + if (!handWritten.contains("ios.applicationQueriesSchemes")) { + set("{{#Ios#ios.applicationQueriesSchemes}}.label", "Application queries schemes"); + set("{{#Ios#ios.applicationQueriesSchemes}}.type", "TextArea"); + set("{{#Ios#ios.applicationQueriesSchemes}}.description", "Comma separated list of url schemes that `canExecute` will respect on iOS. If the url scheme isn't mentioned here `canExecute` will return false starting with iOS 9. Notice that this collides with `ios.plistInject` when used with the `LSApplicationQueriesSchemes...` value so you should use one or the other. For example, to enable `canExecute` for a url like `myurl://xys` you can use: `myurl,myotherurl`"); + } + if (!handWritten.contains("ios.beforeFinishLaunching")) { + set("{{#Ios#ios.beforeFinishLaunching}}.label", "Before finish launching"); + set("{{#Ios#ios.beforeFinishLaunching}}.type", "TextArea"); + set("{{#Ios#ios.beforeFinishLaunching}}.description", "Objective-C code that can be injected into the iOS app delegate at the top of the body of the didFinishLaunchingWithOptions callback method"); + } + if (!handWritten.contains("ios.bundleVersion")) { + set("{{#Ios#ios.bundleVersion}}.label", "Bundle version"); + set("{{#Ios#ios.bundleVersion}}.type", "TextField"); + set("{{#Ios#ios.bundleVersion}}.description", "Indicates the version number of the bundle, this is useful if you want to create a minor version number change for the beta testing support"); + } + if (!handWritten.contains("ios.dependencyManager")) { + set("{{#Ios#ios.dependencyManager}}.label", "Dependency manager"); + set("{{#Ios#ios.dependencyManager}}.type", "Select"); + set("{{#Ios#ios.dependencyManager}}.values", "auto,cocoapods,spm,both,none"); + set("{{#Ios#ios.dependencyManager}}.description", "Which native dependency manager to use: auto picks one from whichever of ios.pods and ios.spm.packages is set, and cocoapods, spm or both require the matching hint to be set. An unrecognized value fails the build."); + } + if (!handWritten.contains("ios.deployment_target")) { + set("{{#Ios#ios.deployment_target}}.label", "Deployment target"); + set("{{#Ios#ios.deployment_target}}.type", "TextField"); + set("{{#Ios#ios.deployment_target}}.description", "Minimum iOS version the build targets. Set it to the lowest iOS you actually support; a higher value excludes older devices from the App Store listing."); + } + if (!handWritten.contains("ios.glAppDelegateHeader")) { + set("{{#Ios#ios.glAppDelegateHeader}}.label", "Gl app delegate header"); + set("{{#Ios#ios.glAppDelegateHeader}}.type", "TextArea"); + set("{{#Ios#ios.glAppDelegateHeader}}.description", "Objective-C code that can be injected into the iOS app delegate at the top of the file. For example, if you need to include headers or make special imports for other injected code"); + } + if (!handWritten.contains("ios.includePush")) { + set("{{#Ios#ios.includePush}}.label", "Include push"); + set("{{#Ios#ios.includePush}}.type", "Checkbox"); + set("{{#Ios#ios.includePush}}.description", "true/false (defaults to false). Whether to include the push capabilities in the iOS build. Notice that the IDE plugin has an \"Include Push\" check box you *should* use under the iOS section."); + } + if (!handWritten.contains("ios.interface_orientation")) { + set("{{#Ios#ios.interface_orientation}}.label", "Interface orientation"); + set("{{#Ios#ios.interface_orientation}}.type", "TextField"); + set("{{#Ios#ios.interface_orientation}}.description", "UIInterfaceOrientationPortrait by default. Indicates the orientation, one or more of (separated by colon :): `UIInterfaceOrientationPortrait`, `UIInterfaceOrientationPortraitUpsideDown`, `UIInterfaceOrientationLandscapeLeft`, `UIInterfaceOrientationLandscapeRight`. Notice that the IDE plugin has an \"Interface Orientation\" combo box you *should* use under the iOS section."); + } + if (!handWritten.contains("ios.minDeploymentTarget")) { + set("{{#Ios#ios.minDeploymentTarget}}.label", "Min deployment target"); + set("{{#Ios#ios.minDeploymentTarget}}.type", "TextField"); + set("{{#Ios#ios.minDeploymentTarget}}.description", "The null and empty-string reads of this hint are presence checks; 6.0 is the substantive default (IPhoneBuilder.java:4671)."); + } + if (!handWritten.contains("ios.newStorageLocation")) { + set("{{#Ios#ios.newStorageLocation}}.label", "New storage location"); + set("{{#Ios#ios.newStorageLocation}}.type", "Checkbox"); + set("{{#Ios#ios.newStorageLocation}}.description", "true/false defaults to false but defined on new projects as true by default. This changes the storage directory on iOS from using caches to using the documents directory which is the recommended location but might break compatibility. This is described in https://github.com/codenameone/CodenameOne/issues/1480[this issue]"); + } + if (!handWritten.contains("ios.objC")) { + set("{{#Ios#ios.objC}}.label", "Obj c"); + set("{{#Ios#ios.objC}}.type", "Checkbox"); + set("{{#Ios#ios.objC}}.description", "Added the `-ObjC` compile flag to the project files which some native libraries require"); + } + if (!handWritten.contains("ios.plistInject")) { + set("{{#Ios#ios.plistInject}}.label", "Plist inject"); + set("{{#Ios#ios.plistInject}}.type", "TextArea"); + set("{{#Ios#ios.plistInject}}.description", "entries to inject into the iOS plist file during build."); + } + if (!handWritten.contains("ios.pods")) { + set("{{#Ios#ios.pods}}.label", "Pods"); + set("{{#Ios#ios.pods}}.type", "TextArea"); + set("{{#Ios#ios.pods}}.description", "A comma separated list of https://cocoapods.org/[Cocoa Pods] that should be linked to the app to build it. For example, `AFNetworking ~> 2.6, ORStackView ~> 3.0, SwiftyJSON ~> 2.3`"); + } + if (!handWritten.contains("ios.pods.platform")) { + set("{{#Ios#ios.pods.platform}}.label", "Pods platform"); + set("{{#Ios#ios.pods.platform}}.type", "TextField"); + set("{{#Ios#ios.pods.platform}}.description", "Sets the Cocoapods 'platform' for the Cocoapods. Some Cocoapods require a minimum platform level. For example, `ios.pods.platform=7.0`."); + } + if (!handWritten.contains("ios.pods.sources")) { + set("{{#Ios#ios.pods.sources}}.label", "Pods sources"); + set("{{#Ios#ios.pods.sources}}.type", "TextArea"); + set("{{#Ios#ios.pods.sources}}.description", "Extra CocoaPods spec repositories to search, in addition to the default trunk."); + } + if (!handWritten.contains("ios.prerendered_icon")) { + set("{{#Ios#ios.prerendered_icon}}.label", "Prerendered icon"); + set("{{#Ios#ios.prerendered_icon}}.type", "Checkbox"); + set("{{#Ios#ios.prerendered_icon}}.description", "true/false defaults to false. The iOS build process adapts the submitted icon for iOS conventions (adding an overlay) that might not be appropriate on some icons. Setting this to true leaves the icon unchanged (only scaled)."); + } + if (!handWritten.contains("ios.project_type")) { + set("{{#Ios#ios.project_type}}.label", "Project type"); + set("{{#Ios#ios.project_type}}.type", "Select"); + set("{{#Ios#ios.project_type}}.values", "ios,ipad,iphone"); + set("{{#Ios#ios.project_type}}.description", "one of ios, ipad, iphone (defaults to ios). Indicates whether the resulting binary is targeted to the iphone only or ipad only. Notice that the IDE plugin has a \"Project Type\" combo box you *should* use under the iOS section."); + } + if (!handWritten.contains("ios.spm.packages")) { + set("{{#Ios#ios.spm.packages}}.label", "Spm packages"); + set("{{#Ios#ios.spm.packages}}.type", "TextArea"); + set("{{#Ios#ios.spm.packages}}.description", "Swift Package Manager packages to link, one per entry, each written as identity|url|requirement."); + } + if (!handWritten.contains("ios.teamId")) { + set("{{#Ios#ios.teamId}}.label", "Team id"); + set("{{#Ios#ios.teamId}}.type", "TextField"); + set("{{#Ios#ios.teamId}}.description", "Specifies the team ID associated with the iOS provisioning profile and certificate. Use `ios.debug.teamId` and `ios.release.teamId` to specify different team IDs for debug and release builds respectively."); + } + if (!handWritten.contains("ios.themeMode")) { + set("{{#Ios#ios.themeMode}}.label", "Theme mode"); + set("{{#Ios#ios.themeMode}}.type", "Select"); + set("{{#Ios#ios.themeMode}}.values", "auto,modern,ios7,legacy"); + set("{{#Ios#ios.themeMode}}.description", "`auto` (default), `modern`, `ios7`, `legacy`. `auto` (unset) keeps the existing iOS 7 flat theme so pre-refactor screenshot goldens and apps see no behavior change. `modern` / `liquid` opts in to the CSS-generated iOS Modern (liquid-glass) theme shipped from `native-themes/ios-modern/theme.css`. `ios7` / `flat` is the same as `auto` - pre-liquid iOS 7 flat theme; `legacy` / `iphone` loads the pre-iOS 7 iPhone theme. The `auto` -> modern flip is planned for a future release."); + } + if (!handWritten.contains("ios.uiscene")) { + set("{{#Ios#ios.uiscene}}.label", "Uiscene"); + set("{{#Ios#ios.uiscene}}.type", "Checkbox"); + set("{{#Ios#ios.uiscene}}.description", "true/false (defaults to true). Enables iOS UIScene lifecycle support. UIScene lets iOS manage one or more app UI sessions independently, improving lifecycle handling in modern iOS versions. Apple has indicated UIScene will be required starting with iOS 27, so this is now on by default; set the flag to `false` only if you need to temporarily fall back to the legacy `UIApplicationDelegate` lifecycle."); + } + if (!handWritten.contains("ios.urlScheme")) { + set("{{#Ios#ios.urlScheme}}.label", "Url scheme"); + set("{{#Ios#ios.urlScheme}}.type", "TextField"); + set("{{#Ios#ios.urlScheme}}.description", "Allows intercepting a URL call using the syntax `urlPrefix`"); + } + + set("{{@Android}}.label", "Android"); + if (!handWritten.contains("android.activity.launchMode")) { + set("{{#Android#android.activity.launchMode}}.label", "Activity launch mode"); + set("{{#Android#android.activity.launchMode}}.type", "TextField"); + set("{{#Android#android.activity.launchMode}}.description", "Allows explicitly setting the `android:launchMode` attribute of the main activity in android. Default is \"singleTop,\" but for some applications you may need to change this behaviour. In particular, apps that are meant to open a file type will need to set this to \"singleTask.\" See https://developer.android.com/guide/topics/manifest/activity-element.html[Android docs for the activity element] for more information about the `android:launchMode` attribute."); + } + if (!handWritten.contains("android.appBundle")) { + set("{{#Android#android.appBundle}}.label", "App bundle"); + set("{{#Android#android.appBundle}}.type", "Checkbox"); + set("{{#Android#android.appBundle}}.description", "Produces an Android App Bundle (.aab) rather than an APK. Required for new Play Store submissions."); + } + if (!handWritten.contains("android.buildToolsVersion")) { + set("{{#Android#android.buildToolsVersion}}.label", "Build tools version"); + set("{{#Android#android.buildToolsVersion}}.type", "TextField"); + set("{{#Android#android.buildToolsVersion}}.description", "Android build-tools version. It also selects the compile SDK, so there is no separate compile-SDK hint."); + } + if (!handWritten.contains("android.captureRecord")) { + set("{{#Android#android.captureRecord}}.label", "Capture record"); + set("{{#Android#android.captureRecord}}.type", "TextField"); + set("{{#Android#android.captureRecord}}.description", "Indicates whether the `RECORD_AUDIO` permission should be requested. Can be `enabled` or any other value to disable this option"); + } + if (!handWritten.contains("android.debug")) { + set("{{#Android#android.debug}}.label", "Debug"); + set("{{#Android#android.debug}}.type", "Checkbox"); + set("{{#Android#android.debug}}.description", "true/false defaults to true - indicates whether to include the debug version in the build. Defaults conditionally rather than to a fixed value: when android.release is on it defaults to false, and when release is off it defaults to true, so a build that selects neither still produces something installable (AndroidGradleBuilder.java:447-451)."); + } + if (!handWritten.contains("android.disableR8")) { + set("{{#Android#android.disableR8}}.label", "Disable r8"); + set("{{#Android#android.disableR8}}.type", "Checkbox"); + set("{{#Android#android.disableR8}}.description", "Turns off R8, falling back to the older shrinker. Note that hardening requires R8, so this conflicts with harden.level."); + } + if (!handWritten.contains("android.enableProguard")) { + set("{{#Android#android.enableProguard}}.label", "Enable proguard"); + set("{{#Android#android.enableProguard}}.type", "Checkbox"); + set("{{#Android#android.enableProguard}}.description", "Boolean true/false defaults to true. Allows disabling the proguard obfuscation even on release builds, notice that this isn't recommended"); + } + if (!handWritten.contains("android.gradleDep")) { + set("{{#Android#android.gradleDep}}.label", "Gradle dep"); + set("{{#Android#android.gradleDep}}.type", "TextArea"); + set("{{#Android#android.gradleDep}}.description", "Gradle dependency statements to add to the app module, such as implementation 'com.example:lib:1.0'."); + } + if (!handWritten.contains("android.hideStatusBar")) { + set("{{#Android#android.hideStatusBar}}.label", "Hide status bar"); + set("{{#Android#android.hideStatusBar}}.type", "Checkbox"); + set("{{#Android#android.hideStatusBar}}.description", "Hides the Android status bar."); + } + if (!handWritten.contains("android.installLocation")) { + set("{{#Android#android.installLocation}}.label", "Install location"); + set("{{#Android#android.installLocation}}.type", "Select"); + set("{{#Android#android.installLocation}}.values", "auto,internalOnly,preferExternal"); + set("{{#Android#android.installLocation}}.description", "Maps to android:installLocation manifest entry defaults to auto. Can also be set to internalOnly or preferExternal."); + } + if (!handWritten.contains("android.licenseKey")) { + set("{{#Android#android.licenseKey}}.label", "License key"); + set("{{#Android#android.licenseKey}}.type", "TextField"); + set("{{#Android#android.licenseKey}}.description", "The license key for the Android app, this is required if you use in-app purchase on Android"); + } + if (!handWritten.contains("android.min_sdk_version")) { + set("{{#Android#android.min_sdk_version}}.label", "Min sdk version"); + set("{{#Android#android.min_sdk_version}}.type", "TextField"); + set("{{#Android#android.min_sdk_version}}.description", "The least SDK required to run this app, the default value changes based on functionality but can be as low as 7. This corresponds to the XML attribute `android:minSdkVersion`."); + } + if (!handWritten.contains("android.multidex")) { + set("{{#Android#android.multidex}}.label", "Multidex"); + set("{{#Android#android.multidex}}.type", "Checkbox"); + set("{{#Android#android.multidex}}.description", "Boolean true/false defaults to false. Multidex allows Android binaries to reference more than 65536 methods. This slows builds a bit so you have it off by default but if you get a build error mentioning this limit you should turn this on."); + } + if (!handWritten.contains("android.newFirebaseMessaging")) { + set("{{#Android#android.newFirebaseMessaging}}.label", "New firebase messaging"); + set("{{#Android#android.newFirebaseMessaging}}.type", "Checkbox"); + set("{{#Android#android.newFirebaseMessaging}}.description", "Uses the current Firebase Cloud Messaging integration. Requires AndroidX and Gradle 8.13 or newer."); + } + if (!handWritten.contains("android.proguardKeep")) { + set("{{#Android#android.proguardKeep}}.label", "Proguard keep"); + set("{{#Android#android.proguardKeep}}.type", "TextArea"); + set("{{#Android#android.proguardKeep}}.description", "Arguments for the keep option in proguard allowing you to keep a pattern of files for example, `-keep class com.mypackage.ProblemClass { *; }`"); + } + if (!handWritten.contains("android.release")) { + set("{{#Android#android.release}}.label", "Release"); + set("{{#Android#android.release}}.type", "Checkbox"); + set("{{#Android#android.release}}.description", "true/false defaults to true - indicates whether to include the release version in the build"); + } + if (!handWritten.contains("android.repositories")) { + set("{{#Android#android.repositories}}.label", "Repositories"); + set("{{#Android#android.repositories}}.type", "TextArea"); + set("{{#Android#android.repositories}}.description", "Extra Gradle repositories to resolve dependencies from."); + } + if (!handWritten.contains("android.targetSDKVersion")) { + set("{{#Android#android.targetSDKVersion}}.label", "Target sDKVersion"); + set("{{#Android#android.targetSDKVersion}}.type", "TextField"); + set("{{#Android#android.targetSDKVersion}}.description", "The Android SDK the build compiles against. Unset, the build server uses the highest platform it has installed, so leaving this alone tracks the server rather than pinning a number. Not every target works: the source may have limitations, and not all SDK targets are installed."); + } + if (!handWritten.contains("and.themeMode")) { + set("{{#Android#and.themeMode}}.label", "Theme mode"); + set("{{#Android#and.themeMode}}.type", "Select"); + set("{{#Android#and.themeMode}}.values", "auto,modern,hololight,legacy"); + set("{{#Android#and.themeMode}}.description", "`auto`, `modern` / `material`, `hololight` (default for existing apps), `legacy`. `auto` and `modern` / `material` opt in to the CSS-generated Android Material 3 theme from `native-themes/android-material/theme.css`. `hololight` is Android Holo Light (what the framework shipped on API 14+ before this refactor). `legacy` loads the pre-Holo Android theme. The legacy alias `cn1.androidTheme` is still accepted, and `and.hololight=true` still maps to `hololight`. The default stays on `hololight` for existing apps until you flip in a future release."); + } + if (!handWritten.contains("android.topDependency")) { + set("{{#Android#android.topDependency}}.label", "Top dependency"); + set("{{#Android#android.topDependency}}.type", "TextArea"); + set("{{#Android#android.topDependency}}.description", "Statements added to the top-level Gradle build file rather than the app module."); + } + if (!handWritten.contains("android.useAndroidX")) { + set("{{#Android#android.useAndroidX}}.label", "Use android x"); + set("{{#Android#android.useAndroidX}}.type", "Checkbox"); + set("{{#Android#android.useAndroidX}}.description", "Use Android X instead of support libraries. This will also run a find/replace on all source files to replace support libraries and artifacts with AndroidX equivalents."); + } + if (!handWritten.contains("android.xapplication")) { + set("{{#Android#android.xapplication}}.label", "Xapplication"); + set("{{#Android#android.xapplication}}.type", "TextArea"); + set("{{#Android#android.xapplication}}.description", "defaults to an empty string. Allows developers of native Android code to add text within the application block to define things such as widgets, services etc."); + } + if (!handWritten.contains("android.xgradle")) { + set("{{#Android#android.xgradle}}.label", "Xgradle"); + set("{{#Android#android.xgradle}}.type", "TextArea"); + set("{{#Android#android.xgradle}}.description", "Arbitrary text spliced into the generated app-module Gradle file."); + } + if (!handWritten.contains("android.xpermissions")) { + set("{{#Android#android.xpermissions}}.label", "Xpermissions"); + set("{{#Android#android.xpermissions}}.type", "TextArea"); + set("{{#Android#android.xpermissions}}.description", "more permissions for the Android manifest"); + } + + set("{{@Desktop}}.label", "Desktop"); + if (!handWritten.contains("desktop.adaptToRetina")) { + set("{{#Desktop#desktop.adaptToRetina}}.label", "Adapt to retina"); + set("{{#Desktop#desktop.adaptToRetina}}.type", "Checkbox"); + set("{{#Desktop#desktop.adaptToRetina}}.description", "Boolean true/false defaults to true. When set to true some values will ve implicitly doubled to deal with retina displays and icons etc. Will use higher DPI's"); + } + if (!handWritten.contains("desktop.fullscreen")) { + set("{{#Desktop#desktop.fullscreen}}.label", "Fullscreen"); + set("{{#Desktop#desktop.fullscreen}}.type", "Checkbox"); + set("{{#Desktop#desktop.fullscreen}}.description", "Starts the desktop build in full-screen mode."); + } + if (!handWritten.contains("desktop.height")) { + set("{{#Desktop#desktop.height}}.label", "Height"); + set("{{#Desktop#desktop.height}}.type", "TextField"); + set("{{#Desktop#desktop.height}}.description", "Height in pixels for the form in desktop builds, will be doubled for retina grade displays. Defaults to 600."); + } + if (!handWritten.contains("desktop.interactiveScrollbars")) { + set("{{#Desktop#desktop.interactiveScrollbars}}.label", "Interactive scrollbars"); + set("{{#Desktop#desktop.interactiveScrollbars}}.type", "Checkbox"); + set("{{#Desktop#desktop.interactiveScrollbars}}.description", "Enables grab-able, click-to-page desktop scrollbars."); + } + if (!handWritten.contains("desktop.resizable")) { + set("{{#Desktop#desktop.resizable}}.label", "Resizable"); + set("{{#Desktop#desktop.resizable}}.type", "Checkbox"); + set("{{#Desktop#desktop.resizable}}.description", "Boolean true/false defaults to true. Indicates whether the UI in the desktop build is resizable"); + } + if (!handWritten.contains("desktop.titleBar")) { + set("{{#Desktop#desktop.titleBar}}.label", "Title bar"); + set("{{#Desktop#desktop.titleBar}}.type", "Select"); + set("{{#Desktop#desktop.titleBar}}.values", "native,custom,toolbar"); + set("{{#Desktop#desktop.titleBar}}.description", "How the desktop window is framed: native for the OS title bar and menu bar, custom for an undecorated window with a Codename One drawn title bar, or toolbar for the legacy in-app Toolbar. An unrecognized value falls back to native with a warning."); + } + if (!handWritten.contains("desktop.width")) { + set("{{#Desktop#desktop.width}}.label", "Width"); + set("{{#Desktop#desktop.width}}.type", "TextField"); + set("{{#Desktop#desktop.width}}.description", "Width in pixels for the form in desktop builds, will be doubled for retina grade displays. Defaults to 800."); + } + + set("{{@OnDeviceDebug}}.label", "On-Device Debugging"); + if (!handWritten.contains("android.onDeviceDebug")) { + set("{{#OnDeviceDebug#android.onDeviceDebug}}.label", "Android"); + set("{{#OnDeviceDebug#android.onDeviceDebug}}.type", "Checkbox"); + set("{{#OnDeviceDebug#android.onDeviceDebug}}.description", "Boolean true/false defaults to false. When `true`, the generated `AndroidManifest.xml` is marked `android:debuggable=\"true\"`, R8/proguard is disabled, and the build is pinned to debug-only (`android.release` is forced off and `android.debug` is forced on) so a stray hint can't ship a release-signed APK that's `debuggable=\"true\"`. Pair with the `cn1:android-on-device-debugging` Maven goal (or the bundled IntelliJ run configs) to install, launch, forward JDWP, and stream logcat through adb. Has no effect on builds that don't carry it -- release builds are unaffected. See the On-Device Debugging (Android) chapter for the full flow."); + } + if (!handWritten.contains("ios.onDeviceDebug")) { + set("{{#OnDeviceDebug#ios.onDeviceDebug}}.label", "Ios"); + set("{{#OnDeviceDebug#ios.onDeviceDebug}}.type", "Checkbox"); + set("{{#OnDeviceDebug#ios.onDeviceDebug}}.description", "Boolean true/false defaults to false. When `true`, the iOS build links a small JDWP listener thread (`cn1_debugger`) into the binary and the ParparVM translator emits source-line and locals metadata so a desktop proxy can serve the running app to any JDWP-speaking debugger. Has no effect on release builds. See the On-Device Debugging (iOS) chapter for the full flow."); + } + if (!handWritten.contains("ios.onDeviceDebug.proxyHost")) { + set("{{#OnDeviceDebug#ios.onDeviceDebug.proxyHost}}.label", "Ios proxy host"); + set("{{#OnDeviceDebug#ios.onDeviceDebug.proxyHost}}.type", "TextField"); + set("{{#OnDeviceDebug#ios.onDeviceDebug.proxyHost}}.description", "Hostname or IP address the device-side listener dials to reach the desktop proxy. Default `127.0.0.1` (correct for the native iOS simulator). For a physical device, set this to the developer laptop's LAN IP. Has no effect unless `ios.onDeviceDebug=true`."); + } + if (!handWritten.contains("ios.onDeviceDebug.proxyPort")) { + set("{{#OnDeviceDebug#ios.onDeviceDebug.proxyPort}}.label", "Ios proxy port"); + set("{{#OnDeviceDebug#ios.onDeviceDebug.proxyPort}}.type", "TextField"); + set("{{#OnDeviceDebug#ios.onDeviceDebug.proxyPort}}.description", "TCP port on `ios.onDeviceDebug.proxyHost` where the proxy is listening for the device. Default `55333`. Has no effect unless `ios.onDeviceDebug=true`."); + } + if (!handWritten.contains("ios.onDeviceDebug.waitForAttach")) { + set("{{#OnDeviceDebug#ios.onDeviceDebug.waitForAttach}}.label", "Ios wait for attach"); + set("{{#OnDeviceDebug#ios.onDeviceDebug.waitForAttach}}.type", "Checkbox"); + set("{{#OnDeviceDebug#ios.onDeviceDebug.waitForAttach}}.description", "Boolean true/false defaults to false. When `true`, the app blocks at startup until the proxy connects and the IDE tells the VM to continue. Useful when the breakpoint to investigate fires during app boot. Has no effect unless `ios.onDeviceDebug=true`."); + } + + set("{{@Build}}.label", "General"); + if (!handWritten.contains("facebook.appId")) { + set("{{#Build#facebook.appId}}.label", "Facebook app id"); + set("{{#Build#facebook.appId}}.type", "TextField"); + set("{{#Build#facebook.appId}}.description", "The application ID for an app that requires native Facebook login integration, this defaults to null which means native Facebook support shouldn't be in the app"); + } + if (!handWritten.contains("gcm.sender_id")) { + set("{{#Build#gcm.sender_id}}.label", "Gcm sender id"); + set("{{#Build#gcm.sender_id}}.type", "TextField"); + set("{{#Build#gcm.sender_id}}.description", "The Android/chrome push identifier, see the push section for more details"); + } + if (!handWritten.contains("nativeTheme")) { + set("{{#Build#nativeTheme}}.label", "Native theme"); + set("{{#Build#nativeTheme}}.type", "Select"); + set("{{#Build#nativeTheme}}.values", "modern,legacy,custom"); + set("{{#Build#nativeTheme}}.description", "`modern`, `legacy`, `custom` (default unset). Cross-platform override that sets both `ios.themeMode` and `and.themeMode` together when those aren't set explicitly. `modern` = liquid glass + Material 3, `legacy` = iOS 7 flat + Holo Light, `custom` disables the framework native theme entirely. The legacy alias `cn1.nativeTheme` is still accepted."); + } + if (!handWritten.contains("noExtraResources")) { + set("{{#Build#noExtraResources}}.label", "No extra resources"); + set("{{#Build#noExtraResources}}.type", "Checkbox"); + set("{{#Build#noExtraResources}}.description", "true/false (defaults to false). Blocks codename one from injecting its own resources when set to true, the only effect this has is in slightly reducing archive size. This might have adverse effects on some features of Codename One so it isn't recommended."); + } + + set("{{@Hardening}}.label", "App Hardening"); + if (!handWritten.contains("harden.allowUnhardenedLocalBuild")) { + set("{{#Hardening#harden.allowUnhardenedLocalBuild}}.label", "Allow unhardened local build"); + set("{{#Hardening#harden.allowUnhardenedLocalBuild}}.type", "Checkbox"); + set("{{#Hardening#harden.allowUnhardenedLocalBuild}}.description", "Permits a local or source build to run with hardening requested but not applied. Without it such a build is refused, so a hardened app is never shipped from a target that can't actually harden it."); + } + if (!handWritten.contains("harden.controlFlow")) { + set("{{#Hardening#harden.controlFlow}}.label", "Control flow"); + set("{{#Hardening#harden.controlFlow}}.type", "Select"); + set("{{#Hardening#harden.controlFlow}}.values", "off,on"); + set("{{#Hardening#harden.controlFlow}}.description", "Overrides control-flow obfuscation independently of harden.level."); + } + if (!handWritten.contains("harden.keep")) { + set("{{#Hardening#harden.keep}}.label", "Keep"); + set("{{#Hardening#harden.keep}}.type", "TextArea"); + set("{{#Hardening#harden.keep}}.description", "Keep rules in ProGuard syntax, one per line, for classes that are resolved by name at runtime and so can't be found by the automatic analysis. Same syntax as android.proguardKeep, so existing rules port directly. Rules are separated by newlines only, because a semicolon is legal inside a rule body such as { *; }."); + } + if (!handWritten.contains("harden.level")) { + set("{{#Hardening#harden.level}}.label", "Level"); + set("{{#Hardening#harden.level}}.type", "Select"); + set("{{#Hardening#harden.level}}.values", "off,standard,aggressive,paranoid"); + set("{{#Hardening#harden.level}}.description", "Master switch for app hardening: off, standard, aggressive or paranoid. An unrecognized value fails the build rather than being treated as off."); + } + if (!handWritten.contains("harden.rename")) { + set("{{#Hardening#harden.rename}}.label", "Rename"); + set("{{#Hardening#harden.rename}}.type", "Checkbox"); + set("{{#Hardening#harden.rename}}.description", "Overrides symbol renaming independently of harden.level."); + } + if (!handWritten.contains("harden.strings")) { + set("{{#Hardening#harden.strings}}.label", "Strings"); + set("{{#Hardening#harden.strings}}.type", "Select"); + set("{{#Hardening#harden.strings}}.values", "off,constants,all"); + set("{{#Hardening#harden.strings}}.description", "Overrides string obfuscation independently of harden.level: off, constants or all."); + } + } + + /** Idempotent setter: does not overwrite user or project-level metadata. */ + private static void set(String suffix, String value) { + String key = "codename1.arg." + suffix; + if (System.getProperty(key) == null) { + System.setProperty(key, value); + } + } +} diff --git a/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults.java b/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults.java index 584e2dd75ae..f85a6fc37e9 100644 --- a/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults.java +++ b/Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults.java @@ -235,10 +235,40 @@ static void register() { + "category, android.software.leanback uses-feature, touchscreen " + "required=false) and a generated tv_banner drawable. With the " + "hint off the manifest is unchanged."); + + // Everything else that has a build hint annotation, generated from the + // catalog. Registered last on purpose: set() never overwrites, so the + // hand-written labels and descriptions above win and this only fills in + // the hints nobody has written prose for. + BuildHintCatalogDefaults.register(); + } + + /** + * The hints this class describes by hand. + * + *

{@link BuildHintCatalogDefaults} consults it so the two never describe + * the same hint. The group name is part of the property key, so a hint + * registered under both {@code hardening} and {@code Hardening} is not + * overwritten -- it is a second group, and the editor renders both, giving + * the user duplicate controls for one setting.

+ */ + private static final java.util.Set DECLARED = new java.util.HashSet(); + + /** Hint names {@link #register} describes, for the generated companion to skip. */ + static java.util.Set declaredHints() { + return java.util.Collections.unmodifiableSet(DECLARED); } /** Idempotent setter: does not overwrite user / project-level hint metadata. */ private static void set(String suffix, String value) { + int hash = suffix.indexOf('#'); + if (suffix.startsWith("{{#") && hash >= 0) { + int second = suffix.indexOf('#', hash + 1); + int close = suffix.indexOf("}}", second + 1); + if (second > 0 && close > second) { + DECLARED.add(suffix.substring(second + 1, close)); + } + } String key = "codename1.arg." + suffix; if (System.getProperty(key) == null) { System.setProperty(key, value); diff --git a/Ports/JavaSE/src/com/codename1/impl/javase/Simulator.java b/Ports/JavaSE/src/com/codename1/impl/javase/Simulator.java index c89f10b3775..b3bcadfdd27 100644 --- a/Ports/JavaSE/src/com/codename1/impl/javase/Simulator.java +++ b/Ports/JavaSE/src/com/codename1/impl/javase/Simulator.java @@ -160,6 +160,7 @@ public static void main(final String[] argv) throws Exception { files.add(commonClasses.getAbsoluteFile()); } loadSimulatorProperties(cn1Props.getParentFile()); + publishAnnotationBuildHints(cn1Props.getParentFile(), classPathStr); } if (isDebug && usingHotswapAgent) { HotswapProperties hotswapProperties = new HotswapProperties(); @@ -451,4 +452,618 @@ private List getExtraClasses() { } } + + /** + * Publishes build hints declared as annotations so the simulator sees them. + * + *

The simulator never runs {@code cn1:build}, so it never sees the build + * request the annotations feed. Without this, moving a hint like + * {@code desktop.titleBar} or {@code nativeTheme} out of + * {@code codenameone_settings.properties} and onto the main class would + * silently stop it working under {@code cn1:run} -- the build would still be + * right and only the simulator would be wrong, which is the hardest kind of + * discrepancy to track down.

+ * + *

Published as system properties rather than added as another source to + * {@code JavaSEPort.buildHint} because several readers bypass that method + * and call {@code System.getProperty("codename1.arg....")} directly. Setting + * the property fixes those, and every future one, with no change to them.

+ * + *

An existing value always wins, which is what preserves {@code -D}: the + * JVM has already applied the command line by the time this runs.

+ * + *

Read straight off disk, not through {@code getResourceAsStream}: at this + * point in {@code main} the application classes are not on any classloader + * yet -- the loader is built from {@code files} further down.

+ */ + private static void publishAnnotationBuildHints(File projectDir, String classPathStr) { + // A reload re-enters main() in the SAME JVM, so anything published last + // time is still set. Withdraw it before deciding anything: otherwise the + // "existing value wins" rule that protects -D also protects the previous + // build's annotation value, and an edited @Desktop(titleBar = ...) -- or + // a deleted annotation, which takes an early return below -- keeps + // showing the old setting until the process is restarted. + // + // Only what THIS method installed is withdrawn. A -D was never installed + // here, because a key already set is skipped, so it is never a candidate. + withdrawPublishedHints(); + if (projectDir == null) { + return; + } + String expectedMain = configuredMainClass(projectDir); + FoundManifest found = findAnnotationManifest(projectDir, classPathStr, expectedMain); + if (found == null) { + return; + } + java.util.Properties p = found.hints; + File f = found.file; + String stampedFor = p.getProperty("cn1.buildHints.mainClass"); + if (stampedFor != null && expectedMain != null && !stampedFor.equals(expectedMain)) { + // Somebody else's configuration. codename1.mainName changing without a + // clean build leaves the old class and its manifest together in the + // output directory, and the timestamp check finds that pair perfectly + // consistent -- so without the stamp the simulator runs the previous + // application's hints. The native merge already refuses this. + System.err.println("Warning: " + found.where + " was generated for " + stampedFor + + ", not " + expectedMain + ", so its build hints were NOT applied."); + return; + } + // Sharing an archive does not mean sharing a build. Nothing deletes an + // old manifest from target/classes, so a recompiled main class and last + // week's resource are packaged into the same jar. + String staleAgainst = staleManifestReason(p, found); + if (staleAgainst != null) { + // Nothing removes target/classes between builds, so a project that ran + // process-annotations once and then stopped -- goal unbound, skipped, + // or bound to a phase that no longer runs -- keeps a manifest that + // looks entirely valid while the annotations beside it have moved on. + // The device build refuses this outright; the simulator would + // otherwise run on the previous values of hints it can actually see, + // such as desktop.titleBar and nativeTheme, and show the wrong thing + // with no indication why. + // + // Judged on timestamps rather than the manifest's own fingerprint: + // recomputing that means parsing the class file's annotation table, + // and the simulator has no bytecode reader. The comparison is sound in + // the direction that matters -- process-classes always follows compile + // within a build, so a main class newer than the manifest cannot have + // produced it. + System.err.println("Warning: " + found.where + " " + staleAgainst + + ", so it was produced by an earlier build " + + "and its build hints were NOT applied."); + System.err.println(" Rebuild the project so the cn1 process-annotations " + + "goal regenerates it."); + return; + } + // A hint declared BOTH ways is a build error, and the native merge says + // so. Publishing it here instead would bury it: buildHint() reads the + // system property before the settings file, so the line the developer + // just added to codenameone_settings.properties would be silently + // ignored by the simulator while the device build refused to run at all. + // Reachable because editing the properties file does not touch the class, + // so the timestamp check above still finds the manifest current. + java.util.Properties declared = loadProjectSettings(projectDir); + int applied = 0; + for (String key : p.stringPropertyNames()) { + if (!key.startsWith("codename1.arg.")) { + continue; + } + String conflict = declaredInPropertiesToo(p, declared, key); + if (conflict != null) { + System.err.println("Warning: " + conflict + " is declared both as an annotation " + + "and in codenameone_settings.properties, so the annotation value was " + + "NOT applied. Delete one of them -- a build will refuse this."); + continue; + } + if (System.getProperty(key) == null) { + System.setProperty(key, p.getProperty(key)); + PUBLISHED_HINTS.add(key); + applied++; + } + } + if (applied > 0) { + System.out.println("Applied " + applied + " build hint(s) from annotations"); + } + } + + /** + * Keys this class installed into the system properties, so a reload can take + * them back out. + * + *

Static because a reload re-enters {@code main} in the same JVM rather + * than starting a process.

+ */ + private static final java.util.Set PUBLISHED_HINTS = + new java.util.HashSet(); + + /** Removes what a previous launch published, leaving anything else alone. */ + private static void withdrawPublishedHints() { + if (PUBLISHED_HINTS.isEmpty()) { + return; + } + for (String key : PUBLISHED_HINTS) { + System.clearProperty(key); + } + PUBLISHED_HINTS.clear(); + } + + /** + * The properties key that declares the same setting as {@code key} in the /** + * The properties key that declares the same setting as {@code key} in the + * settings file, or null when the file declares none of its spellings. + * + *

An alias and its target name one setting -- the builder reads + * {@code android.captureRecord} and then lets {@code and.captureRecord} + * override it -- so either spelling in the file collides. The spellings come + * out of the manifest, which the annotation processor writes them into, + * because the catalog that knows about aliases is a build-time artifact and + * this port cannot reach it.

+ */ + private static String declaredInPropertiesToo(java.util.Properties manifest, + java.util.Properties declared, String key) { + if (declared == null) { + return null; + } + if (declared.getProperty(key) != null) { + return key; + } + String name = key.substring("codename1.arg.".length()); + String aliases = manifest.getProperty("cn1.buildHints.alias." + name); + if (aliases == null) { + return null; + } + for (String alias : aliases.split(",")) { + String other = "codename1.arg." + alias.trim(); + if (alias.trim().length() > 0 && declared.getProperty(other) != null) { + return other; + } + } + return null; + } + + /** The project's settings file, or null when it cannot be read. */ + private static java.util.Properties loadProjectSettings(File projectDir) { + File settings = new File(projectDir, "codenameone_settings.properties"); + if (!settings.isFile()) { + return null; + } + java.util.Properties p = new java.util.Properties(); + FileInputStream in = null; + try { + in = new FileInputStream(settings); + p.load(in); + return p; + } catch (IOException ex) { + return null; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ignored) { + // read-only stream; nothing useful to do + } + } + } + } + + /** + * The main class this project is configured to launch, or null. /** + * The main class this project is configured to launch, or null. + * + *

Read from the settings file rather than from the system properties: the + * file is what the annotation processor stamped the manifest against, and a + * {@code -D} override is a launch choice rather than a change of identity.

+ */ + private static String configuredMainClass(File projectDir) { + java.util.Properties p = loadProjectSettings(projectDir); + if (p == null) { + return null; + } + String main = p.getProperty("codename1.mainName"); + if (main == null || main.trim().length() == 0) { + return null; + } + String pkg = p.getProperty("codename1.packageName"); + return (pkg == null || pkg.trim().length() == 0) + ? main.trim() : pkg.trim() + "." + main.trim(); + } + + /** + * The emitted build hint manifest, or null when there is none. /** + * The emitted build hint manifest, or null when there is none. + * + *

{@code target/classes} is only the default: a module may configure + * {@code build/outputDirectory}, and the annotation processor writes where + * that says. Hard-coding the conventional path meant the device build applied + * the annotated hints and {@code cn1:run} silently ignored them, which is the + * asymmetry this whole publishing step exists to remove.

+ * + *

The configured directory is on the simulator's own classpath, so the + * classpath is searched rather than the layout guessed at. The conventional + * path is tried first, since it is right for almost every project and costs + * one stat.

+ */ + /** + * A manifest that was found, and where. + * + *

Not a File, because it can live inside a jar: the javase-only nested + * build the simulator runs resolves the application's own common module as a + * dependency artifact, so its manifest has no path of its own.

+ */ + /** The manifest's path inside a jar, which is its resource path with / separators. */ + private static final String ANNOTATION_HINTS_ENTRY = + "META-INF/codenameone/build-hints.properties"; + + static final class FoundManifest { + final java.util.Properties hints; + /** The file on disk, or null when it came out of a jar. */ + final File file; + /** The jar it came out of, or null when it is a file on disk. */ + final File jar; + final String where; + + FoundManifest(java.util.Properties hints, File file, File jar, String where) { + this.hints = hints; + this.file = file; + this.jar = jar; + this.where = where; + } + } + + static FoundManifest findAnnotationManifest(File projectDir, String classPathStr, + String expectedMain) { + String resource = "META-INF" + File.separator + "codenameone" + + File.separator + "build-hints.properties"; + String entryName = ANNOTATION_HINTS_ENTRY; + // The classpath first, because it is the output the build is ACTUALLY + // using. Trying the conventional path first looked harmless and is not: + // a project that moves to a configured output directory without running + // clean leaves the old target/classes in place, complete with its old + // manifest and the old class beside it, so the staleness check compares + // two obsolete files against each other, finds them consistent, and + // publishes last week's hints while the real ones sit on the classpath. + FoundManifest fallback = null; + FoundManifest stale = null; + if (classPathStr != null) { + for (String entry + : classPathStr.split(java.util.regex.Pattern.quote(File.pathSeparator))) { + if (entry.length() == 0) { + continue; + } + File dir = new File(entry); + if (dir.isDirectory()) { + File candidate = new File(dir, resource); + if (candidate.isFile()) { + java.util.Properties loaded = readProperties(candidate); + if (loaded != null) { + // The stamp decides here too. A reactor dependency or + // a stale JavaSE output directory earlier on the + // classpath can carry ANOTHER application's manifest, + // and taking it ended the search: the caller then saw + // a main class that was not this one and published + // nothing at all, so cn1:run silently dropped + // desktop.titleBar and nativeTheme while this + // application's own manifest sat in a later entry. + String stamp = loaded.getProperty("cn1.buildHints.mainClass"); + FoundManifest found = + new FoundManifest(loaded, candidate, null, + candidate.toString()); + if (expectedMain == null || expectedMain.equals(stamp)) { + // Right application, but possibly the wrong + // build: a leftover output directory earlier on + // the classpath carries a manifest stamped for + // this same main class, and taking it ended the + // search -- the caller then reported it stale and + // published nothing, while the current manifest + // sat in a later entry. The first stale one is + // kept so that finding NO current manifest still + // says why. + if (staleManifestReason(loaded, found) == null) { + return found; + } + if (stale == null) { + stale = found; + } + } + if (stamp == null && fallback == null) { + // No stamp is not a foreign manifest, only an + // unidentifiable one. Kept as a last resort so a + // manifest that predates the stamp is still read. + fallback = found; + } + } + } + continue; + } + // A jar too. The javase-only nested build the simulator runs + // resolves the application's OWN common module as a dependency + // artifact, so its manifest has no directory anywhere -- skipping + // jars meant desktop.titleBar and nativeTheme were simply absent + // under cn1:run while the device build applied them. + // + // The stamp is what tells that jar from a library's: a jar is + // accepted only when it was generated for THIS application's main + // class, so a dependency carrying its own manifest is passed over + // rather than picked and then rejected. + if (dir.isFile() && entry.endsWith(".jar") && expectedMain != null) { + java.util.Properties loaded = readJarEntry(dir, entryName); + if (loaded != null + && expectedMain.equals(loaded.getProperty("cn1.buildHints.mainClass"))) { + FoundManifest found = new FoundManifest(loaded, null, dir, + entryName + " in " + dir.getName()); + if (staleManifestReason(loaded, found) == null) { + return found; + } + if (stale == null) { + stale = found; + } + } + } + } + } + if (fallback != null) { + return fallback; + } + // Only when the classpath carries none: a launch that did not pass the + // module's output directory at all still finds a conventional build. + File conventional = new File(projectDir, "target" + File.separator + "classes" + + File.separator + resource); + java.util.Properties loaded = conventional.isFile() ? readProperties(conventional) : null; + if (loaded != null) { + FoundManifest found = + new FoundManifest(loaded, conventional, null, conventional.toString()); + if (staleManifestReason(loaded, found) == null) { + return found; + } + if (stale == null) { + stale = found; + } + } + // Nothing current anywhere. The stale one is returned rather than + // nothing, so the caller can say which file it is and why it was not + // used instead of silently applying no hints at all. + return stale; + } + + /** Loads a properties file, or null when it cannot be read. */ + private static java.util.Properties readProperties(File f) { + java.util.Properties p = new java.util.Properties(); + FileInputStream in = null; + try { + in = new FileInputStream(f); + p.load(in); + return p; + } catch (IOException ex) { + System.err.println("Warning: could not read " + f + ": " + ex.getMessage()); + return null; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ignored) { + // read-only stream; nothing useful to do + } + } + } + } + + /** Loads one entry of a jar as properties, or null when it is not there. */ + private static java.util.Properties readJarEntry(File jar, String entryName) { + java.util.zip.ZipFile zip = null; + try { + zip = new java.util.zip.ZipFile(jar); + java.util.zip.ZipEntry entry = zip.getEntry(entryName); + if (entry == null) { + return null; + } + java.util.Properties p = new java.util.Properties(); + java.io.InputStream in = zip.getInputStream(entry); + try { + p.load(in); + } finally { + in.close(); + } + return p; + } catch (IOException ex) { + return null; + } finally { + if (zip != null) { + try { + zip.close(); + } catch (IOException ignored) { + // read-only archive + } + } + } + } + + /** + * The compiled main class when it is newer than the manifest, or null. + * + *

Null whenever the question cannot be answered -- no main class recorded, + * no class file for it, no readable timestamps -- so the manifest is taken at + * face value rather than discarded on a guess.

+ */ + /** + * Why the manifest was left behind by an earlier build, or null when it is + * current. + * + *

By the class file's own contents when the manifest records them, and + * only otherwise by timestamps. Timestamps are not always available to + * compare: a jar records entry times to two-second granularity, and a build + * configured for reproducible output stamps every entry identically, which + * makes the comparison inert rather than merely coarse. A manifest with no + * recorded digest is one an older plugin wrote, so it falls back rather than + * being refused.

+ */ + static String staleManifestReason(java.util.Properties manifest, + FoundManifest found) { + String main = manifest.getProperty("cn1.buildHints.mainClass"); + if (main == null || main.trim().length() == 0) { + return null; + } + String entry = main.trim().replace('.', '/') + ".class"; + String recorded = manifest.getProperty("cn1.buildHints.classDigest"); + if (recorded != null && recorded.length() > 0) { + String actual = found.jar != null + ? digestOfJarEntry(found.jar, entry) + : digestOfFile(classFileBeside(found.file, main)); + if (actual != null) { + return recorded.equals(actual) ? null + : "does not describe the compiled " + entry; + } + } + String older = found.jar != null + ? classNewerThanManifestInJar(manifest, found.jar) + : (found.file == null ? null : classNewerThanManifest(manifest, found.file)); + return older == null ? null : "is older than " + older; + } + + /** The compiled main class in the output directory the manifest sits in. */ + private static File classFileBeside(File manifestFile, String main) { + if (manifestFile == null) { + return null; + } + File classes = manifestFile.getParentFile(); // .../codenameone + classes = classes == null ? null : classes.getParentFile(); // .../META-INF + classes = classes == null ? null : classes.getParentFile(); // the output dir + if (classes == null) { + return null; + } + File f = new File(classes, main.trim().replace('.', File.separatorChar) + ".class"); + return f.isFile() ? f : null; + } + + /** SHA-256 of a file, hex, or null when it cannot be read. */ + private static String digestOfFile(File f) { + if (f == null) { + return null; + } + try { + java.io.InputStream in = new FileInputStream(f); + try { + return digestOf(in); + } finally { + in.close(); + } + } catch (IOException ex) { + return null; + } + } + + /** SHA-256 of one jar entry, hex, or null when it is absent or unreadable. */ + static String digestOfJarEntry(File jar, String entryName) { + java.util.zip.ZipFile zip = null; + try { + zip = new java.util.zip.ZipFile(jar); + java.util.zip.ZipEntry entry = zip.getEntry(entryName); + if (entry == null) { + return null; + } + java.io.InputStream in = zip.getInputStream(entry); + try { + return digestOf(in); + } finally { + in.close(); + } + } catch (IOException ex) { + return null; + } finally { + if (zip != null) { + try { + zip.close(); + } catch (IOException ignored) { + // read-only archive + } + } + } + } + + private static String digestOf(java.io.InputStream in) throws IOException { + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); + byte[] buf = new byte[8192]; + for (int n = in.read(buf); n > 0; n = in.read(buf)) { + md.update(buf, 0, n); + } + StringBuilder hex = new StringBuilder(); + for (byte b : md.digest()) { + hex.append(Character.forDigit((b >> 4) & 0xF, 16)); + hex.append(Character.forDigit(b & 0xF, 16)); + } + return hex.toString(); + } catch (java.security.NoSuchAlgorithmException ex) { + return null; + } + } + + /** + * As above, for a manifest read out of a jar: the two entries' own + * timestamps, since being in one archive proves nothing about which build + * wrote them. + * + *

Zip stores times to two-second granularity, so the comparison is + * deliberately strict -- a class newer by less than that reads as + * consistent. It only has to catch a manifest from an EARLIER build, which + * is not a near thing.

+ */ + static String classNewerThanManifestInJar(java.util.Properties manifest, File jar) { + String main = manifest.getProperty("cn1.buildHints.mainClass"); + if (main == null || main.trim().length() == 0) { + return null; + } + String classEntry = main.trim().replace('.', '/') + ".class"; + java.util.zip.ZipFile zip = null; + try { + zip = new java.util.zip.ZipFile(jar); + java.util.zip.ZipEntry cls = zip.getEntry(classEntry); + java.util.zip.ZipEntry res = zip.getEntry(ANNOTATION_HINTS_ENTRY); + if (cls == null || res == null) { + return null; + } + long classTime = cls.getTime(); + long manifestTime = res.getTime(); + if (classTime < 0L || manifestTime < 0L) { + return null; + } + return classTime > manifestTime ? classEntry : null; + } catch (IOException ex) { + return null; + } finally { + if (zip != null) { + try { + zip.close(); + } catch (IOException ignored) { + // read-only archive + } + } + } + } + + private static String classNewerThanManifest(java.util.Properties manifest, + File manifestFile) { + String main = manifest.getProperty("cn1.buildHints.mainClass"); + if (main == null || main.trim().length() == 0) { + return null; + } + // Beside the manifest, whatever directory that turned out to be -- the + // two are written by the same build into the same output directory. + File classes = manifestFile.getParentFile(); // .../codenameone + classes = classes == null ? null : classes.getParentFile(); // .../META-INF + classes = classes == null ? null : classes.getParentFile(); // the output dir + if (classes == null) { + return null; + } + File classFile = new File(classes, + main.trim().replace('.', File.separatorChar) + ".class"); + if (!classFile.isFile()) { + return null; + } + long classTime = classFile.lastModified(); + long manifestTime = manifestFile.lastModified(); + if (classTime == 0L || manifestTime == 0L) { + return null; + } + return classTime > manifestTime ? classFile.getName() : null; + } } diff --git a/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc b/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc index 4509a700c8a..ead34ed89a4 100644 --- a/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc +++ b/docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc @@ -25,715 +25,19 @@ Application code can read a custom build argument through `Display.getProperty() include::../demos/common/src/main/java/com/codenameone/developerguide/advancedtopics/AppArgSnippet.java[tag=appArg,indent=0] ---- -Here is the current list of supported arguments. Build hints change over time, so consult the discussion forum if you don't find what you need here: +Here is the current list of supported arguments, generated from the same catalog +the builders and the annotations are generated from: -.Build hints -|=== -|Name |Description - -|build.cn1Version -|Pro/Enterprise only. Pins the cloud build to a specific released Codename One version using the Maven release scheme (for example `7.0.182`), or to `master` to build against the current development head. The build server fetches that version's framework artifacts. Pro accounts can target versions published within the last two months; Enterprise within the last six months. Requesting an older version, a version that was never published, or using this hint without a Pro/Enterprise subscription fails the build with an explanatory error. See <>. - -|android.debug -|true/false defaults to true - indicates whether to include the debug version in the build - -|android.release -|true/false defaults to true - indicates whether to include the release version in the build - -|android.onDeviceDebug -|Boolean true/false defaults to false. When `true`, the generated `AndroidManifest.xml` is marked `android:debuggable="true"`, R8/proguard is disabled, and the build is pinned to debug-only (`android.release` is forced off and `android.debug` is forced on) so a stray hint can't ship a release-signed APK that's `debuggable="true"`. Pair with the `cn1:android-on-device-debugging` Maven goal (or the bundled IntelliJ run configs) to install, launch, forward JDWP, and stream logcat through adb. Has no effect on builds that don't carry it — release builds are unaffected. See the <> for the full flow. - -|android.installLocation -|Maps to android:installLocation manifest entry defaults to auto. Can also be set to internalOnly or preferExternal. - -|android.xapplication -|defaults to an empty string. Allows developers of native Android code to add text within the application block to define things such as widgets, services etc. - -|android.permission.PERMISSION_NAME -|true/false Whether to include a particular permission. Use of these build hints is preferred to `android.xpermissions` since they avoid possible conflicts with libraries. See https://developer.android.com/reference/android/Manifest.permission.html[Android's `Manifest.permission` docs] for a full list of permissions. - -|android.permission.PERMISSION_NAME.maxSdkVersion -|Will be translated to the `maxSdkVersion` attribute of the `` tag for the corresponding `android.permission.PERMISSION_NAME` build hint. (Optional) - -|android.permission.PERMISSION_NAME.required -|true/false Will be translated to the `required` attribute of the `` tag for the corresponding `android.permission.PERMISSION_NAME` build hint. (Optional) - -|android.xpermissions -|more permissions for the Android manifest - -|android.xintent_filter -|Allows adding an intent filter to the main android activity - -|android.tv -|true/false (defaults to false). Marks the build as an Android TV / Google TV app. Adds the `LEANBACK_LAUNCHER` intent category to the launcher activity (so the app appears on the TV home screen), declares the `android.software.leanback` feature, makes `android.hardware.touchscreen` optional (so it installs on touchless TVs), and generates a 320×180 launcher banner (`@drawable/tv_banner`) from the app icon. The same APK still installs and runs on phones and tablets, and `CN.isTV()` returns true at runtime on a TV. - - -|android.activity.launchMode -|Allows explicitly setting the `android:launchMode` attribute of the main activity in android. Default is "singleTop," but for some applications you may need to change this behaviour. In particular, apps that are meant to open a file type will need to set this to "singleTask." See https://developer.android.com/guide/topics/manifest/activity-element.html[Android docs for the activity element] for more information about the `android:launchMode` attribute. - - -|android.licenseKey -|The license key for the Android app, this is required if you use in-app purchase on Android - -|android.signingV1 -|true/false Default true. See https://source.android.com/docs/security/features/apksigning - -|android.signingV2 -|true/false Default true. See https://source.android.com/docs/security/features/apksigning - -|android.signingV3 -|true/false Default true. See https://source.android.com/docs/security/features/apksigning - -|android.signingV4 -|true/false Default true. See https://source.android.com/docs/security/features/apksigning - -|android.stack_size -|Size in bytes for the Android stack thread - -|android.statusbar_hidden -|true/false defaults to false. When set to true hides the status bar on Android devices. - -|android.facebook_permissions -|Permissions for Facebook used in the Android build target, applicable only if Facebook native integration is used. - -|android.googleAdUnitId -|Allows integrating admob/google play ads, this is effectively identical to google.adUnitId but only applies to Android - -|android.googleAdUnitTestDevice -|Device key used to mark a specific Android device as a test device for Google Play ads defaults to C6783E2486F0931D9D09FABC65094FDF - -|android.includeGPlayServices -|*Deprecated, please android.playService.+++*+++!* Indicates whether Google Play Services should be included into the build, defaults to false but that might change based on the functionality of the application and other build hints. Adding Google Play Services support allows you to use a more refined location implementation and invoke some Google specific functionality from native code. - -|android.playService.plus, android.playService.auth, android.playService.base, android.playService.identity, android.playService.indexing, android.playService.appInvite, android.playService.analytics, android.playService.cast, android.playService.gcm, android.playService.drive, android.playService.fitness, android.playService.location, android.playService.maps, android.playService.ads, android.playService.vision, android.playService.nearby, android.playService.panorama, android.playService.games, android.playService.safetynet, android.playService.wallet, android.playService.wearable -|Allows including only a specific play services library portion. Notice that this setting conflicts with the deprecated `android.includeGPlayServices` and only works with the Gradle-based Android build pipeline. + - -If none of the services are defined to true then plus, auth, base, analytics, gcm, location, maps & ads will be set to true. If one or more of the `android.playService` entries are defined to something then all entries will default to false. - -|android.playServicesVersion -| The version number of play services to build against. Experimental. **Use with caution** as building against versions other than the server default may introduce incompatibilities with some Codename One APIs. - -|xxx.minPlayServicesVersion -|This is a special case build hint. You can use any prefix to the build hint and the convention is to use your cn1lib name. It's identical to `android.minPlayServicesVersion` with the exception that the "highest version wins." That way if your cn1lib requires play services 9+ and uses: `myLib.minPlayServicesVersion=9.0.0` and another library has `otherLib.minPlayServicesVersion=10.0.0` then play services will be 10.0.0 - -|android.multidex -|Boolean true/false defaults to false. Multidex allows Android binaries to reference more than 65536 methods. This slows builds a bit so you have it off by default but if you get a build error mentioning this limit you should turn this on. - -|android.headphoneCallback -|Boolean true/false defaults to false. When set to true it assumes the main class has two methods: `headphonesConnected` & `headphonesDisconnected` which it invokes appropriately as needed - -|android.gpsPermission -|Indicates whether the GPS permission should be requested, it's autodetected by default if you use the location API. But, some code might want to explicitly define it - -|android.asyncPaint -|Boolean true/false defaults to true. Toggles the Android pipeline between the legacy pipeline (false) and new pipeline (true) - -|android.stringsXml -|Allows injecting more entries into the strings.xml file using a value that includes something like this `value1value2` - -|android.supportV4 -|Boolean true/false defaults to false but that can change based on usage (for example, push implicitly activates this). Indicates whether the android support v4 library should be included in the build - -|android.style -|Allows injecting more data into the `styles.xml` file right before the closing resources tag - -|android.enableAdaptiveIcons -|Boolean true/false defaults to false. Enables Android adaptive icon generation in Android Gradle builds. When enabled, Codename One generates `mipmap` launcher resources (`ic_launcher`, `ic_launcher_foreground`, and adaptive XML in `mipmap-anydpi-v26`) and uses them in the application manifest (`android:icon` and `android:roundIcon`). - -|android.adaptiveIconBackground -|Background color to use for adaptive icons when `android.enableAdaptiveIcons=true` and no background image is supplied. Defaults to `#ffffff` and is written as `@color/ic_launcher_background`. - -|android.adaptiveIconBackgroundImage -|Optional path (relative to the root of the native Android project) to an image file to use as the adaptive icon background when `android.enableAdaptiveIcons=true`. If this property is set, it overrides `android.adaptiveIconBackground`. - -|android.cusom_layout1 -|Applies to any number of layouts as long as they're in sequence (for example, android.cusom_layout2, android.cusom_layout3 etc.). Will write the content of the argument as a layout XML file and give it the name `cusom_layout1.xml` onwards. This can be used by native code to work with XML files - -|android.keyboardOpen -|Boolean true/false defaults to true. Toggles the new async keyboard mode that leaves the keyboard open while you move between text components - -|android.versionCode -|Allows overriding the auto generated version number with a custom internal version number specifically used for the XML attribute `android:versionCode` - -|android.captureRecord -|Indicates whether the `RECORD_AUDIO` permission should be requested. Can be `enabled` or any other value to disable this option - -|android.nonconsumable -|Comma delimited string of items that are non-consumable in the in-app purchase API - -|android.removeBasePermissions -|Boolean true/false defaults to false. Disables the built-in permissions specifically `INTERNET` permission (that is, no networking...) - -|android.blockExternalStoragePermission -|Boolean true/false defaults to false. Disables the external storage (SD card) permission - -|android.blockReadMediaPermissions -|Boolean true/false, defaults to the value of `android.blockExternalStoragePermission`. Suppresses the `READ_MEDIA_VIDEO` and `READ_MEDIA_AUDIO` permissions that playing a URI adds on API 33 and above - -|android.requestReadMediaPermissions -|Boolean true/false defaults to false. Declares `READ_MEDIA_IMAGES`, `READ_MEDIA_VIDEO` and `READ_MEDIA_AUDIO` on API 33 and above even when the build detected no media playback. `READ_MEDIA_IMAGES` is only ever added by this hint - -|android.min_sdk_version -|The least SDK required to run this app, the default value changes based on functionality but can be as low as 7. This corresponds to the XML attribute `android:minSdkVersion`. - -|android.manifest.queries -|Embeds XML content into the section of the Android manifest file. This is https://developer.android.com/training/package-visibility[required in Android 11 for package visibility]. See https://developer.android.com/guide/topics/manifest/queries-element[queries element Android documentation]. - -|android.mockLocation -|Boolean true/false defaults to true. Toggles the mock location permission which is on by default, this allows easier debugging of Android device location based services - -|android.smallScreens -|Boolean true/false defaults to true. Corresponds to the `android:smallScreens` XML attribute and allows disabling the support for small phones - -|android.xapplication_attr -|Allows injecting more attributes into the `application`` tag in the Android XML - -|android.xactivity -|Allows injecting more attributes into the `activity` tag in the Android XML - -|android.streamMode -|The mode in which the volume key should behave, defaults to OS default. Allows setting it to `music` for music playback apps - -|android.pushVibratePattern -|Comma delimited long values to describe the push pattern of vibrate used for the `setVibrate` native method - -|android.enableProguard -|Boolean true/false defaults to true. Allows disabling the proguard obfuscation even on release builds, notice that this isn't recommended - -|android.proguardKeep -|Arguments for the keep option in proguard allowing you to keep a pattern of files for example, `-keep class com.mypackage.ProblemClass { *; }` - -|android.shrinkResources -|Boolean true/false defaults to false. Used only in conjunction with android.enableProguard. Strips out unused resources to reduce apk size. Since 7.0 - -|android.sharedUserId -|Allows adding a manifest attribute for the sharedUserId option - -|android.sharedUserLabel -|Allows adding a manifest attribute for the sharedUserLabel option - -|android.targetSDKVersion -|Indicates the Android SDK used to compile the Android build defaults to 21. Notice that not all targets will work since the source might have some limitations and not all SDK targets are installed on the build servers. - -|android.useAndroidX -|Use Android X instead of support libraries. This will also run a find/replace on all source files to replace support libraries and artifacts with AndroidX equivalents. - -|android.rootCheck -|Boolean true/false defaults to false. Indicates whether the app should check for root access on the device. If root access is detected, the app will exit. - -|android.tapjackingGuard -|Boolean true/false defaults to false. Switches on tapjacking / screen-overlay protection at launch, so touches that arrive while another app's window covers this one are detected and dropped. See the security chapter. - -|android.tapjackingGuard.mode -|`block` (default), `strict`, `report` or `off`. `block` drops gestures that start on a fully obscured window, `report` only observes, `strict` also drops touches where only part of the window is covered (which benign system UI can trigger). Only relevant if `android.tapjackingGuard=true`. - -|android.tapjackingGuard.hideOverlays -|Boolean true/false defaults to true. Also asks Android 12+ to hide overlay windows drawn over the app, which is the only mitigation that covers native peer components, and declares the `HIDE_OVERLAY_WINDOWS` permission it requires. Only relevant if `android.tapjackingGuard=true`. - -|android.hideOverlayWindows -|Boolean true/false defaults to false. Declares the `android.permission.HIDE_OVERLAY_WINDOWS` permission needed by `DeviceIntegrity.setHideOverlayWindows()` on Android 12+, for apps that call the runtime API without enabling `android.tapjackingGuard`. A normal install-time permission, so the user sees no prompt. - -|android.fridaDetection -|Boolean true/false defaults to false. Indicates whether the app should check for the presence of the https://www.frida.re/[Frida] dynamic instrumentation toolkit on the device. If Frida is detected, the app will exit. This uses the [frida-blocker](https://github.com/shannah/frida-blocker) library to perform the frida detection. - -|android.fridaVersion -|x.y.z The version of [frida-blocker](https://github.com/shannah/frida-blocker) to use to perform frida detection. This is only relevant if `android.fridaDetection=true`. If omitted, it will use the latest tested version in the build server. - -|android.fridaDebugLogging -|Boolean true/false defaults to false. If true, it will add verbose debug logs during frida detection to show which check if fails on. - -|android.theme -|Light or Dark defaults to Light. On Android 4+ the default Holo theme is used to render the native widgets sometimes and this indicates whether holo light or holo dark is used. This doesn't affect the Codename One theme but that might change in the future. - -|android.web_loading_hidden -|true/false defaults to false - set to true to hide the progress indicator that appears when loading a web page on Android. - -|block_server_registration -|true/false flag defaults to false. By default Codename One applications register with the Codename One server. Setting this to true blocks them from sending information to the Codename One cloud, which is kept for statistical purposes and may be used to provide more installation stats in the future. - -|facebook.appId -|The application ID for an app that requires native Facebook login integration, this defaults to null which means native Facebook support shouldn't be in the app - -|facebook.clientToken -|The client token for an app that requires native Facebook login integration, this is required if the facebook.appId is set. - -|gcm.sender_id -|The Android/chrome push identifier, see the push section for more details - -| android.background_push_handling -| Deliver push messages on Android when the app is minimized by setting this to "true." Default behaviour is to deliver the message only if the app is in the foreground when received, or after the user taps on the notification to open the app, if the app was in the background when the message was received. - -| desktop.mac.plist.PLISTKEY -| Set the key `PLISTKEY` in the Info.plist file for desktop mac build. For example, `desktop.mac.plist.LSApplicationCategoryType=public.app-category.business`. See https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html[Apple Documentation of Info.plist keys and values for a full list of supported keys]. -+ -Only supported for App Store builds. See https://www.codenameone.com/developer-guide.html#_mac_os_desktop_build_options[macOS Desktop Build Options] for more information. - -| desktop.mac.plistInject -| Injects raw XML into the Info.plist file for desktop builds. For example, `desktop.mac.plistInject=LSApplicationCategoryTypepublic.app-category.business` -+ -Only supported for App Store builds. See https://www.codenameone.com/developer-guide.html#_mac_os_desktop_build_options[macOS Desktop Build Options] for more information. - -| windows.arch -| Native Windows (`windows-device`) target CPU: `x64` (default), `arm64`, or `both`. An x64 binary also runs on Windows-on-ARM via the OS's x64 emulation. See <>. - -| windows.debug -| Native Windows target: `true`/`false` (default `false`). When `false` the `.exe` is optimized and stripped (with the `.pdb` in its own file); `true` keeps symbols (a single x64 build) for crash symbolication. Optimizations stay on either way. - -| windows.signing.pkcs12 / windows.signing.password / windows.signing.timestampUrl / windows.signing.digest / windows.signing.name / windows.signing.url -| Native Windows Authenticode signing of the produced `.exe` (via `osslsigncode`). A certificate is taken from `windows.signing.pkcs12` or the build's uploaded certificate; set `windows.signing=false` to skip. Unsigned binaries run but trip SmartScreen / "Unknown publisher." - -| linux.arch -| Native Linux (`linux-device`) target CPU: `x64` (default), `arm64`, or `both`. See <>. - -| linux.debug -| Native Linux target: `true`/`false` (default `false`). When `false` the ELF is optimized and stripped (debug info is split into a separate `.debug`); `true` keeps symbols (`RelWithDebInfo`) for crash symbolication. Optimizations stay on either way. - -| linux.libc -| Native Linux target: `glibc` (default) or `musl`. The default compiles against an old glibc so the ELF runs on essentially any mainstream distro; `musl` targets Alpine (where the GTK stack is itself musl-built). A glibc binary and a musl binary aren't interchangeable. - -|ios.associatedDomains -|Comma-delimited list of domains associated with this app. Each domain should be prefixed by a supported prefix. For example, "applinks:" or "webcredentials:." See https://developer.apple.com/documentation/security/password_autofill/setting_up_an_app_s_associated_domains?language=objc[Apple's documentation on Associated domains] for more information. - -|ios.bitcode -|true/false defaults to false. Enables bitcode support for the build. - -|ios.debug.archs -|Can be set to "armv7" to force iOS debug builds to be 32 bit. By default, debug builds are 64 bit only. - -|ios.release.archs -|Can be set to "arm64" to only build iOS release builds for 64 bit. By default, release builds are both 32 and 64 bit. - -|ios.distributionMethod -|Specifies distribution type for debug iOS builds. This is used for enterprise or ad-hoc builds (using values "enterprise" and "ad-hoc" respectively). - -|ios.debug.distributionMethod -|Specifies distribution type for debug iOS builds only. This is used for enterprise or ad-hoc builds (using values "enterprise" and "ad-hoc" respectively). - -|ios.release.distributionMethod -|Specifies distribution type for release iOS builds only. This is used for enterprise or ad-hoc builds (using values "enterprise" and "ad-hoc" respectively). - -|ios.keyboardOpen -|Flips between iOS keyboard open mode and autofold keyboard mode. Defaults to true which means the keyboard will remain open and not fold automatically when editing moves to another field. - -|ios.uiscene -|true/false (defaults to true). Enables iOS UIScene lifecycle support. UIScene lets iOS manage one or more app UI sessions independently, improving lifecycle handling in modern iOS versions. Apple has indicated UIScene will be required starting with iOS 27, so this is now on by default; set the flag to `false` only if you need to temporarily fall back to the legacy `UIApplicationDelegate` lifecycle. - -|ios.urlScheme -|Allows intercepting a URL call using the syntax `urlPrefix` - -|ios.useAVKit -|Use AVKit for video components on iOS rather than `MPMoviePlayerController` on iOS versions 8 through 12. iOS 13 will always use AVKit, and iOS 7 and lower will always use `MPMoviePlayerController`. Default value `false` - -|ios.teamId -|Specifies the team ID associated with the iOS provisioning profile and certificate. Use `ios.debug.teamId` and `ios.release.teamId` to specify different team IDs for debug and release builds respectively. - -|ios.debug.teamId -|Specifies the team ID associated with the iOS debug provisioning profile and certificate. - -|ios.release.teamId -|Specifies the team ID associated with the iOS release provisioning profile and certificate. - -|ios.project_type -|one of ios, ipad, iphone (defaults to ios). Indicates whether the resulting binary is targeted to the iphone only or ipad only. Notice that the IDE plugin has a "Project Type" combo box you *should* use under the iOS section. - -|ios.rpmalloc -// vale-skip: write-good.TooWordy — 'minimum' refers to the deployment-target floor; 'least' would change the meaning. -|`true`/`false` Use https://github.com/rampantpixels/rpmalloc[rpmalloc] instead of malloc/free for memory allocation in ParparVM. This will cause the deployment target to be changed to a minimum of iOS 8.0. - -|ios.statusbar_hidden -|true/false defaults to false. Hides the iOS status bar if set to true. - -|ios.newStorageLocation -|true/false defaults to false but defined on new projects as true by default. This changes the storage directory on iOS from using caches to using the documents directory which is the recommended location but might break compatibility. This is described in https://github.com/codenameone/CodenameOne/issues/1480[this issue] - -|ios.prerendered_icon -|true/false defaults to false. The iOS build process adapts the submitted icon for iOS conventions (adding an overlay) that might not be appropriate on some icons. Setting this to true leaves the icon unchanged (only scaled). - -|ios.app_groups -|Space-delimited list of app groups that this app belongs to as described in https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW19[Apple's documentation]. These are added to the entitlements file with key `com.apple.security.application-groups`. - -|ios.keychainAccessGroup -|Space-delimited list of keychain access groups that this app has access to as described in https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html#//apple_ref/doc/uid/TP30000897-CH204-SW11[Apple's documentation]. These are added to the entitlements file with the key `keychain-access-groups`. - -|ios.application_exits -|true/false (defaults to false). Indicates whether the application should exit on home button press. The default is to exit, leaving the application running is only tested at the moment. - -|ios.blockScreenshotsOnEnterBackground -|true/false (defaults to false). Indicates that app should prevent iOS from taking screenshots when app enters background. Described https://shannah.github.io/cn1-recipes/#_hiding_sensitive_data_when_entering_background[here]. - -|ios.detectJailbreak -|true/false (defaults to false). When true, the iOS app will exit on launch if it detects that it's running on a jailbroken device. - -|ios.notificationPermissionAtLaunch -|true/false (defaults to false). Backward-compatibility flag for the pre-issue-#4876 behavior. By default, the iOS notification permission prompt is deferred until the app calls `Push.register()` or schedules a `LocalNotification`, matching the Android flow and giving the developer a chance to display a rationale screen first. Set this hint to `true` to restore the legacy behavior in which the prompt fires automatically inside `application:didFinishLaunchingWithOptions:` as soon as the app launches. Existing apps relying on the prompt being shown at launch should set this to `true`; new apps should leave it disabled and trigger the prompt explicitly when they're ready to ask for permission. - -|ios.applicationQueriesSchemes -|Comma separated list of url schemes that `canExecute` will respect on iOS. If the url scheme isn't mentioned here `canExecute` will return false starting with iOS 9. Notice that this collides with `ios.plistInject` when used with the `LSApplicationQueriesSchemes...` value so you should use one or the other. For example, to enable `canExecute` for a url like `myurl://xys` you can use: `myurl,myotherurl` - -|ios.themeMode -|`auto` (default), `modern`, `ios7`, `legacy`. `auto` (unset) keeps the existing iOS 7 flat theme so pre-refactor screenshot goldens and apps see no behavior change. `modern` / `liquid` opts in to the CSS-generated iOS Modern (liquid-glass) theme shipped from `native-themes/ios-modern/theme.css`. `ios7` / `flat` is the same as `auto` - pre-liquid iOS 7 flat theme; `legacy` / `iphone` loads the pre-iOS 7 iPhone theme. The `auto` -> modern flip is planned for a future release. - -|and.themeMode -|`auto`, `modern` / `material`, `hololight` (default for existing apps), `legacy`. `auto` and `modern` / `material` opt in to the CSS-generated Android Material 3 theme from `native-themes/android-material/theme.css`. `hololight` is Android Holo Light (what the framework shipped on API 14+ before this refactor). `legacy` loads the pre-Holo Android theme. The legacy alias `cn1.androidTheme` is still accepted, and `and.hololight=true` still maps to `hololight`. The default stays on `hololight` for existing apps until you flip in a future release. - -|nativeTheme -|`modern`, `legacy`, `custom` (default unset). Cross-platform override that sets both `ios.themeMode` and `and.themeMode` together when those aren't set explicitly. `modern` = liquid glass + Material 3, `legacy` = iOS 7 flat + Holo Light, `custom` disables the framework native theme entirely. The legacy alias `cn1.nativeTheme` is still accepted. +Most of the commonly used hints also have a compiler-checked form: an annotation +in `com.codename1.annotations.buildhints` that you put on the application's main +class. Written that way a misspelled name is an unknown symbol and an +unsupported value is an unknown enum constant, instead of a properties line that +is accepted, never read, and has no effect. The Annotation column below +names that form where one exists. Setting the same hint both ways fails the +build. -|ios.interface_orientation -|UIInterfaceOrientationPortrait by default. Indicates the orientation, one or more of (separated by colon :): `UIInterfaceOrientationPortrait`, `UIInterfaceOrientationPortraitUpsideDown`, `UIInterfaceOrientationLandscapeLeft`, `UIInterfaceOrientationLandscapeRight`. Notice that the IDE plugin has an "Interface Orientation" combo box you *should* use under the iOS section. - -|ios.xcode_version -|The version of Xcode used on the server. Defaults to 4.5; accepts 5.0 as an option and nothing else. - -|ios.multitasking -|Set to true to enable iOS multitasking and split-screen support. This only works if `ios.xcode_verson=9.2`. - -|java.version -|Valid values include 5 or 8. Indicates the JVM version that should be used for server compilation, this is defined by default for newly created apps based on the Java 8 mode selection - -|javascript.inject_proxy -|true/false (defaults to `true`). The ParparVM builder generates a same-origin proxy bundle and configures the app to use it. Setting this to `false` disables both proxy generation and proxy URL injection. - -|javascript.inject.beforeHead -| Content to be injected into the index.html file at the beginning of the `` tag. - -|javascript.inject.afterHead -| Content to be injected into the index.html file at the end of the `` tag. - -|javascript.minifying -|true/false (defaults to `true`). By default the JavaScript code is minified to reduce file size. You may optionally disable minification by setting `javascript.minifying` to `false`. - -|javascript.port -|`parparvm` (default) or `teavm`. Selects the public JavaScript compiler for cloud builds. `teavm` retains the original builder as a compatibility fallback. - -|javascript.proxy.allowedTargets -|Comma-separated target origins, host names, or wildcard subdomains that a generated proxy may access, for example `https://api.example.com,*.services.example.org`. If omitted, the proxy accepts any HTTP or HTTPS target and the build emits a warning. - -|javascript.proxy.target -|The generated ParparVM proxy deployment platform. Supported values are `jakarta-servlet` (default), `javax-servlet`, `node`, `php`, `aws-lambda`, `google-cloud-functions`, `cloudflare-workers`, and `none`. - -|javascript.proxy.url -|The URL of an existing proxy to use for network requests. Setting it suppresses generated proxy packaging unless `javascript.proxy.target` is also set. If `javascript.inject_proxy` is `false`, this build hint is ignored. - -|javascript.sourceFilesCopied -|true/false (defaults to `false`). Setting this flag to `true` will cause available java source files to be included in the resulting .zip and .war files. These may be used by Chrome during debugging. - -|javascript.stopOnErrors -|true/false (defaults to `true`). Causes a TeaVM JavaScript build to fail when the compiler reports warnings. Setting this to `false` may allow the fallback builder to complete, but can turn compiler diagnostics into runtime failures that are more difficult to debug. - -|javascript.teavm.version -| (Optional) The version of TeaVM to use for the build. *Use caution*, only use this property if you know what you're doing! - - -|google.adUnitId -|Allows integrating Admob/Google Play ads into the application see link:https://www.codenameone.com/blog/adding-google-play-ads.html[this] - -|ios.entitlementsInject -|Content to inject into the iOS entitlements file. This should be in the Plist XML format. See https://developer.apple.com/documentation/bundleresources/entitlements?language=objc[Apple Entitlements Documentation]. - -|ios.plistInject -|entries to inject into the iOS plist file during build. - -|ios.includePush -|true/false (defaults to false). Whether to include the push capabilities in the iOS build. Notice that the IDE plugin has an "Include Push" check box you *should* use under the iOS section. - -|ios.newPipeline -|Boolean true/false defaults to true. Allows toggling the OpenGL ES 2.0 drawing pipeline off to the older OGL ES 1.0 pipeline. - -|ios.headphoneCallback -|Boolean true/false defaults to false. When set to true it assumes the main class has two methods: `headphonesConnected` & `headphonesDisconnected` which it invokes appropriately as needed - -|ios.facebook_permissions -|Permissions for Facebook used in the Android build target, applicable only if Facebook native integration is used. - -|ios.applicationDidEnterBackground -|Objective-C code that can be injected into the iOS callback method (message) `applicationDidEnterBackground`. - -|ios.enableAutoplayVideo -|Boolean true/false defaults to false. Makes videos "autoplay" when loaded on iOS - -|ios.googleAdUnitId -|Allows integrating admob/google play ads, this is effectively identical to google.adUnitId but only applies to iOS - -|ios.viewDidLoad -|Objective-C code that can be injected into the iOS callback method (message) `viewDidLoad` - -|ios.googleAdUnitIdPadding -|Indicates the amount of padding to pass to the Google Ads placed at the bottom of the screen with `google.adUnitId` - -|ios.enableBadgeClear -|Boolean true/false defaults to true. Clears the badge value with every load of the app, this is useful if the app doesn't manually keep track of number values for the badge - -|ios.glAppDelegateHeader -|Objective-C code that can be injected into the iOS app delegate at the top of the file. For example, if you need to include headers or make special imports for other injected code - -|ios.glAppDelegateBody -|Objective-C code that can be injected into the iOS app delegate within the body of the file before the end. This only makes sence for methods that aren't already declared in the class - -|ios.beforeFinishLaunching -|Objective-C code that can be injected into the iOS app delegate at the top of the body of the didFinishLaunchingWithOptions callback method - -|ios.afterFinishLaunching -|Objective-C code that can be injected into the iOS app delegate at the bottom of the body of the didFinishLaunchingWithOptions callback method - -|ios.locationUsageDescription -|This flag is required for iOS 8 and newer if you're using the location API. It needs to include a description of the reason for which you need access to the users location - -|ios.NSXXXUsageDescription -|iOS privacy flags for using certain APIs. Starting with Xcode 8, you're required to add usage description strings for certain APIs. Find a full list of the available keys in https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html[Apple's docs]. Some relevant ones include `ios.NSCameraUsageDescription`, `ios.NSContactsUsageDescription`, `ios.NSLocationAlwaysUsageDescription`, `NSLocationUsageDescription`, `ios.NSMicrophoneUsageDescription`, `ios.NSPhotoLibraryAddUsageDescription`, `ios.NSSpeechRecognitionUsageDescription`, `ios.NSSiriUsageDescription` - -|ios.add_libs -|A semicolon separated list of libraries that should be linked to the app to build it - -|ios.pods -|A comma separated list of https://cocoapods.org/[Cocoa Pods] that should be linked to the app to build it. For example, `AFNetworking ~> 2.6, ORStackView ~> 3.0, SwiftyJSON ~> 2.3` - -|ios.pods.platform -// vale-skip: write-good.TooWordy — 'minimum platform level' is the standard CocoaPods term; 'least platform level' is wrong. -| Sets the Cocoapods 'platform' for the Cocoapods. Some Cocoapods require a minimum platform level. For example, `ios.pods.platform=7.0`. - -| ios.deployment_target -// vale-skip: write-good.TooWordy — 'minimum version' is the standard term for a deployment-target floor. -| Sets the deployment target for iOS builds. This is the minimum version of iOS required by a device to install the app. For example, `ios.deployment_target=8.0`. Default is '6.0'. Note: This build hint interacts with the `ios.rpmalloc` build hint. If `ios.deployment_target` is 8.0 or higher, ParparVM will use https://github.com/rampantpixels/rpmalloc[rpmalloc] by default. You can disable this default and revert back to using malloc/free by setting the `ios.rpmalloc=false` build hint. - -|ios.bundleVersion -|Indicates the version number of the bundle, this is useful if you want to create a minor version number change for the beta testing support - -|ios.objC -|Added the `-ObjC` compile flag to the project files which some native libraries require - -|ios.testFlight -|Boolean true/false defaults to false and works only for pro accounts. Enables the testflight support in the release binaries for easy beta testing. Notice that the IDE plugin has a "Test Flight" check box you *should* use under the iOS section. - -|ios.metal -|Boolean true/false defaults to true. Selects the Metal rendering backend (`CAMetalLayer`) over the legacy OpenGL ES 2 path (`CAEAGLLayer`). Metal is the supported iOS graphics API; OpenGL ES is deprecated. Set to `false` to opt out if you hit a Metal-only rendering regression. See link:#_metal_renderer[Working with iOS / Metal renderer] for details. - -|ios.metal.colorSpace -|Selects the `CAMetalLayer.colorspace` for the Metal renderer. Accepts `sRGB` (default), `displayP3`, `deviceRGB`, `linearSRGB`, `extendedSRGB`, `extendedLinearSRGB`, or `none`. Has no effect when `ios.metal=false`. See link:#_choosing_a_color_space_for_the_metal_renderer[Working with iOS / Choosing a color space] for the full table. - -|ios.generateSplashScreens -|Boolean true/false defaults to false. Enables legacy generation of splash screen images instead of the current launch storyboards. - -|ios.onDeviceDebug -|Boolean true/false defaults to false. When `true`, the iOS build links a small JDWP listener thread (`cn1_debugger`) into the binary and the ParparVM translator emits source-line and locals metadata so a desktop proxy can serve the running app to any JDWP-speaking debugger. Has no effect on release builds. See the <> for the full flow. - -|ios.onDeviceDebug.proxyHost -|Hostname or IP address the device-side listener dials to reach the desktop proxy. Default `127.0.0.1` (correct for the native iOS simulator). For a physical device, set this to the developer laptop's LAN IP. Has no effect unless `ios.onDeviceDebug=true`. - -|ios.onDeviceDebug.proxyPort -|TCP port on `ios.onDeviceDebug.proxyHost` where the proxy is listening for the device. Default `55333`. Has no effect unless `ios.onDeviceDebug=true`. - -|ios.onDeviceDebug.waitForAttach -|Boolean true/false defaults to false. When `true`, the app blocks at startup until the proxy connects and the IDE tells the VM to continue. Useful when the breakpoint to investigate fires during app boot. Has no effect unless `ios.onDeviceDebug=true`. - -|ios.wallet.extension -|Boolean true/false defaults to false. Generates an Apple Wallet issuer provisioning extension (the "From apps on your iPhone" flow in the Wallet app) and embeds it in the build. Requires `ios.wallet.appGroup` and `ios.wallet.issuerEndpoint`. See the <>. - -|ios.wallet.appGroup -|App Group id starting with `group.` shared by the app and the generated Wallet extensions. The app publishes pass entries into this group through `com.codename1.payment.WalletExtension` and the group is added to the app and extension entitlements automatically. Required when `ios.wallet.extension=true`. - -|ios.wallet.issuerEndpoint -|HTTPS URL of the issuer backend endpoint that produces the encrypted provisioning payload. The generated extension POSTs Apple's certificates/nonce plus the card identifier and auth token there as JSON. Required when `ios.wallet.extension=true`. - -|ios.wallet.includeUI -|Boolean true/false defaults to false. Also generates the Wallet authorization UI extension - a login form shown inside the Wallet app when the app reports that authentication is required. Requires `ios.wallet.authEndpoint`. - -|ios.wallet.authEndpoint -|HTTPS URL the generated login UI extension POSTs `{"username","password"}` to; the JSON response's `token` is stored in the App Group for the provisioning request. Required when `ios.wallet.includeUI=true`. - -|ios.wallet.nonuiExtensionName / ios.wallet.uiExtensionName -|Names of the generated extension targets, also used as the bundle id suffix (`.`). Default `WalletNonUIExtension` / `WalletUIExtension`. The matching App IDs must be registered with the payment-pass-provisioning entitlement and listed by the card network. - -|ios.wallet.nonuiProvisioningProfile / ios.wallet.uiProvisioningProfile -|Cloud device builds only. File name of the extension's `.mobileprovision` placed under `common/src/main/resources`. The profile must match the app's distribution certificate and carry the `com.apple.developer.payment-pass-provisioning` entitlement; the build keeps it out of the app bundle. - -|ios.wallet.nonuiProvisioningURL / ios.wallet.uiProvisioningURL -|Cloud device builds only. URL fallback for the extension provisioning profile when it isn't bundled in resources, mirroring `ios.notificationServiceExtensionProvisioningURL`. - -|ios.wallet.nonui.buildSettings.SETTING / ios.wallet.ui.buildSettings.SETTING -|Extra Xcode build settings applied to the generated extension targets, for example `ios.wallet.nonui.buildSettings.DEVELOPMENT_TEAM=ABCD123456`. Applied last so they override the generated defaults. - -|ios.wallet.nonuiImportsInject, ios.wallet.statusInject, ios.wallet.passEntriesInject, ios.wallet.remotePassEntriesInject, ios.wallet.generateRequestInject, ios.wallet.generateResponseInject, ios.wallet.uiImportsInject, ios.wallet.uiViewDidLoadInject, ios.wallet.uiAuthRequestInject, ios.wallet.uiAuthResponseInject -|Objective-C code injected at the matching marker comment in the generated Wallet extension sources, for custom behavior at each callback (for example adding fields to the issuer endpoint payload in `generateRequestInject`). See the <>. - -|ios.appext.NAME.provisioningURL -|Cloud device builds only. URL of the provisioning profile for a generic app extension dropped into `ios/app_extensions/NAME/` (or a generated extension such as `CN1Widgets`), used when the extension folder doesn't bundle a `.mobileprovision` itself. The profile is installed on the build machine and added to the export options per bundle id. Used for both debug and release builds unless a qualified variant (below) is set. An extension is signed against its own App ID, so a device build with no profile for it -- by any of the three carriers -- is refused unless the app's own profile is a wildcard that covers the extension's bundle id. - -|ios.debug.appext.NAME.provisioningURL / ios.release.appext.NAME.provisioningURL -|Cloud device builds only. Build-type-specific variants of `ios.appext.NAME.provisioningURL`: point the `debug` variant at the extension's development profile and the `release` variant at its distribution profile. The Maven build resolves the variant matching the build target (`ios-device` and `ios-on-device-debug` are debug, `ios-device-release` is release) into the unqualified hint before submitting the build; the unqualified hint acts as the fallback. The same qualifiers work for the local-path settings `codename1.ios.debug.appext.NAME.provision` / `codename1.ios.release.appext.NAME.provision`. - -|codename1.mac.appid -|Mac Native cloud builds only. The Mac bundle identifier registered in App Store Connect / Apple Developer. Distinct from `codename1.ios.appid` because Apple treats the iOS and Mac App Store records as separate products. Required for cloud Mac builds. - -|codename1.mac.certificate -|Mac Native cloud builds only. Path to the `.p12` file containing the Mac signing certificate(s) — _Mac App Distribution_ (3rd Party Mac Developer Application) for App Store builds, _Developer ID Application_ for Developer ID builds, or both bundled into the same P12 when `macNative.distribution=both`. Not interchangeable with the iOS distribution certificate. Required for cloud Mac builds. - -|codename1.mac.certificatePassword -|Mac Native cloud builds only. Password to unlock the P12 referenced by `codename1.mac.certificate`. Required for cloud Mac builds. - -|codename1.mac.provision -|Mac Native cloud builds only. Path to the Mac provisioning profile (`.provisionprofile`). Apple issues distinct provisioning profiles for Mac App Store and Developer ID distribution — pass the one that matches the chosen channel. - -|macNative.distribution -|Mac Native builds only. `appStore` (default), `developerID`, or `both`. Selects which entitlements + ExportOptions plist + signing certificate to emit. `both` emits parallel `*-AppStore.entitlements` / `*-DeveloperID.entitlements` and matching `ExportOptions-*-Mac.plist` files so a single project can be archived to either channel. - -|macNative.teamId -|Mac Native builds only. Apple Developer Team ID (alphanumeric). Falls back to `ios.release.teamId` → `ios.teamId` → `ios.debug.teamId` since most apps share a single Apple Developer Team for iOS and Mac. - -|macNative.bundleId -|Mac Native builds only. Used only when `macNative.deriveBundleId=false`. Default: `.mac`. - -|macNative.deriveBundleId -|Mac Native builds only. `true` (default) maps to Xcode's `DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER=YES` (Xcode appends `.maccatalyst` to the iOS bundle ID). Set to `false` to take the bundle ID verbatim from `macNative.bundleId`. - -|macNative.minDeploymentTarget -|Mac Native builds only. Minimum macOS version (`MACOSX_DEPLOYMENT_TARGET`). Default `10.15` — earlier versions don't support Mac Catalyst. - -|macNative.iosMinDeploymentTarget -|Mac Native builds only. iOS deployment-target floor for the Catalyst slice (`IPHONEOS_DEPLOYMENT_TARGET`). Default `13.1`. The plugin coerces the iOS slice's minimum upward when set. - -|macNative.appCategory -|Mac Native builds only. `LSApplicationCategoryType` in the generated Info.plist. Default `public.app-category.utilities`. See https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype[Apple's category list]. - -|macNative.copyright -|Mac Native builds only. `NSHumanReadableCopyright` in the Info.plist. Defaults to `Copyright (c) `. - -|macNative.signing.style -|Mac Native builds only. `automatic` (default) lets Xcode pick the signing certificate; `manual` forces the certificate identity hints below to be respected verbatim. - -|macNative.signingIdentity.appStore -|Mac Native builds only. Signing certificate identity for the App Store channel. Default `Apple Distribution`. - -|macNative.signingIdentity.developerID -|Mac Native builds only. Signing certificate identity for the Developer ID channel. Default `Developer ID Application`. - -|macNative.provisioningProfile.appStore -|Mac Native builds only. Provisioning profile name for App Store distribution — used only when `macNative.signing.style=manual`. - -|macNative.provisioningProfile.developerID -|Mac Native builds only. Provisioning profile name for Developer ID distribution — used only when `macNative.signing.style=manual`. - -|macNative.entitlements.appSandbox -|Mac Native builds only. `true` enables `com.apple.security.app-sandbox`. Default is `true` for the `appStore` channel (Mac App Store requires the sandbox), `false` for `developerID`. - -|macNative.entitlements.network.client -|Mac Native builds only. Toggles `com.apple.security.network.client`. Default `true`. - -|macNative.entitlements.network.server -|Mac Native builds only. Toggles `com.apple.security.network.server`. Default `false`. - -|macNative.entitlements.files.userSelected -|Mac Native builds only. `readwrite` (default), `readonly`, or `none`. Sets the matching `com.apple.security.files.user-selected.*` entitlement. - -|macNative.entitlements.hardenedRuntime -|Mac Native builds only. `true` enables hardened runtime restrictions. Default is `true` for `developerID` (notarization requires it), `false` for `appStore`. - -|macNative.entitlements.allowJit -|Mac Native builds only. `true` enables `com.apple.security.cs.allow-jit` for hardened runtime. ParparVM is AOT-compiled so this is `false` by default; flip when bundling a JIT-using cn1lib. - -|macNative.entitlements.extra -|Mac Native builds only. Free-form XML inserted verbatim inside the `` of the generated entitlements plist. Use for entitlements Codename One doesn't expose individually. - -|macNative.fixedWindowSize -|Mac Native builds only. Opt-in. Format `x` — for example `1024x685`. When set, the Catalyst window's `UISceneSession.sizeRestrictions` minimum and maximum are pinned to the requested size so every launch produces a byte-identical window. Default unset, in which case the window is resizable. The CI screenshot pipeline turns this on to keep the strict-pixel golden comparison stable; production apps should leave it off. - -|desktop.width -|Width in pixels for the form in desktop builds, will be doubled for retina grade displays. Defaults to 800. - -|desktop.height -|Height in pixels for the form in desktop builds, will be doubled for retina grade displays. Defaults to 600. - -|desktop.adaptToRetina -|Boolean true/false defaults to true. When set to true some values will ve implicitly doubled to deal with retina displays and icons etc. Will use higher DPI's - -|desktop.resizable -|Boolean true/false defaults to true. Indicates whether the UI in the desktop build is resizable - -|desktop.fontSizes -|Indicates the sizes in pixels for the system fonts as a comma delimited string containing 3 numbers for small,medium,large fonts. - -|desktop.theme -|Name of the theme res file (without the ".res" extension) to use as the "native" theme. By default this is native indicating iOS theme on Mac and Windows Metro on Windows. If its something else then the app will try to load the file /themeName.res (placed in native/Java SE directory). - -|desktop.themeMac -|Same as `desktop.theme` but specific to macOS - -|desktop.themeWin -|Same as `desktop.theme` but specific to Windows - -|desktop.windowsOutput -|Can be exe or msi depending on desired results - -|desktop.win.cef -|Whether to use CEF for media and BrowserComponent instead of JavaFX in windows desktop builds. true/false. Default value is `false` (Jan 2021), but this will be changed to `true` in a future version. - -|desktop.mac.cef -|Whetherto use CEF for media or BrowserComponent instead of JavaFX in Mac desktop builds. true/false. Default value is `false` (Jan 2021), but this will be changed to `true` in a future version. - -|tvNative.enabled -|true/false (defaults to false). Adds an Apple TV (tvOS) application target to the iOS build. The tvOS app is a separate `appletvos` target built from the same Java/Kotlin sources through ParparVM (UIKit + Metal; tvOS has no OpenGL ES). Enabling it doesn't change the iOS app -- in particular it doesn't override the iOS app's `ios.metal` setting. Also turned on implicitly by `codename1.tvMain`. - -|tvNative.mainClass (a.k.a. codename1.tvMain) -|Fully-qualified tvOS lifecycle entry class. Setting it auto enables the tvOS target. If omitted while `tvNative.enabled=true`, the tvOS app reuses the phone main class. - -|tvNative.bundleId -|Bundle identifier of the tvOS app. Defaults to `.tvos`. - -|tvNative.minDeploymentTarget -|`TVOS_DEPLOYMENT_TARGET` for the tvOS target. Defaults to `13.0`. - -|tvNative.displayName -|The tvOS app name shown on Apple TV. Defaults to the app's display name. - -|tvNative.teamId -|Apple Developer Team ID used to sign the tvOS target. Falls back to the iOS team id (`ios.release.teamId` / `ios.teamId` / `ios.debug.teamId`). - -|mac.desktop-vm -|The JVM the should be bundled with Mac desktop build. Mac desktop builds only. Supported values: zuluFx8, zulu11, zuluFx11 - -|win.desktop-vm -|The JVM that should be bundled in the Windows desktop build. Windows desktop builds only. Supported values: zulu8, zuluFx8, zulu8-32bit, zuluFx8-32bit, zulu11, zuluFx11, zulu11-32bit, zuluFx11-32bit - -|windows.extensions -|Historical build hint for the discontinued UWP target. It's retained here only for legacy reference and isn't used by current supported build targets. - -|win.vm32bit -|true/false (defaults to false). Forces windows desktop builds to use the Win32 JVM instead of the 64 bit VM making them compatible with older Windows Machines. This is off by default at the moment because of a bug in JDK 8 update 112 that might cause this to fail for some cases - -|win.installDirName -|Windows desktop builds only. Overrides the default installation folder name suggested by the installer (under `Program Files`). Defaults to the application's main class name for backward compatibility. Use this build hint to set a user-friendly installation folder name (for example, `win.installDirName=My Application`). The application ID used by Windows for upgrade detection is unaffected, so existing installations continue to upgrade. - -|win.shortcutName -|Windows desktop builds only. Overrides the name used for the Start Menu shortcut, the Desktop shortcut and (when `win.launchOnStart=true`) the autostart shortcut. Defaults to the application's main class name for backward compatibility. Use this build hint to set a user-friendly shortcut label (for example, `win.shortcutName=My Application`). - -|noExtraResources -|true/false (defaults to false). Blocks codename one from injecting its own resources when set to true, the only effect this has is in slightly reducing archive size. This might have adverse effects on some features of Codename One so it isn't recommended. - -|windows.arch -|Native Windows port only (the `windows-native` build target -- not the JVM `win.*` desktop hints above). Target CPU architecture for the standalone `.exe`: `x64` (the default) or `arm64`. Accepts the usual synonyms (`x86_64`/`amd64`, `aarch64`). clang-cl cross-compiles to the chosen architecture from either host. See the link:#_working_with_the_native_windows_port[Working with the native Windows port chapter]. - -|windows.debug -|Native Windows port only. true/false (defaults to false). When `false` the `.exe` is built optimized and *stripped* -- no PDB, dead-stripped unreferenced code (`/OPT:REF`) and folded identical functions (`/OPT:ICF`) -- which is the shipping default. Set `true` to keep debug symbols (a `.pdb` next to the exe, via `RelWithDebInfo` / clang-cl `/Zi` + linker `/DEBUG`) so a native crash address can be symbolized during development. Optimizations stay on in both cases. - -|windows.sdkRoot -|Native Windows port only; used when building on a *non-Windows* host (for example a Linux build server). Path to a Windows SDK laid out by https://github.com/Jake-Shadle/xwin[`xwin splat`] (a directory containing `crt/include` and `sdk/include/um`), used to cross-compile the `.exe` with clang-cl + lld-link instead of a Visual Studio environment. If unset, the `CN1_XWIN_SYSROOT` environment variable is used. Ignored on Windows hosts, which build through Visual Studio. The same SDK serves both `windows.arch` targets (its `x86_64` / `aarch64` lib subdirs). - -|(signing certificate) -|Native Windows port only. The code-signing certificate itself isn't a build-hint argument; configure it through project settings as `codename1.windows.signing.certificate` (path to a PKCS#12 `.pfx`/`.p12` file holding the certificate + key) and `codename1.windows.signing.password`. The build uses it for both local and cloud builds -- a cloud build uploads it with the build request automatically, exactly like the iOS / Android signing certificates. When a certificate is present the produced `.exe` is Authenticode-signed with `osslsigncode` (which signs Windows PE files on any OS, so it works in the Linux build cloud); without one the exe ships unsigned (it runs, but shows "Unknown publisher" in UAC and trips SmartScreen on download). - -|windows.signing.timestampUrl -|Native Windows port only. RFC 3161 timestamp server used when signing, so the signature stays valid after the certificate expires. Default `http://timestamp.digicert.com`; set empty to disable timestamping. - -|windows.signing.digest -|Native Windows port only. Signature digest algorithm. Default `sha256`. - -|windows.signing.name / windows.signing.url -|Native Windows port only. The description and URL embedded in the signature (the "More info" shown by Windows). Default: the app's display name, and no URL. - -|windows.signing -|Native Windows port only. `true`/`false` (default `true`). Set `false` to force an unsigned build even when a certificate is available. - -|=== +.Build hints +include::_generated-build-hints.adoc[] === Versioned builds diff --git a/maven/build-hint-catalog/pom.xml b/maven/build-hint-catalog/pom.xml new file mode 100644 index 00000000000..24045b96c83 --- /dev/null +++ b/maven/build-hint-catalog/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + com.codenameone + codenameone + 8.0-SNAPSHOT + + codenameone-build-hint-catalog + Codename One Build Hint Catalog + Shared registry describing every Codename One build hint: type, default, value domain and merge semantics + + 1.8 + 1.8 + UTF-8 + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintAnnotationBinding.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintAnnotationBinding.java new file mode 100644 index 00000000000..15af3227474 --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintAnnotationBinding.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Maps a build hint annotation back to the hint it sets. + * + *

The annotation processor reads bytecode, where an annotation member is + * just a name and an enum value is just a constant name. It must not + * re-derive the hint name or the wire value from those strings: the folding + * rule would then exist in two places, and a builder silently falls back to + * its default on a value it does not recognise, so a mismatch would be + * invisible. This table is generated from the same catalog as the + * annotations, so the two cannot drift.

+ * + *

Generated by BuildHintCodeGenerator. Do not edit by hand.

+ */ +public final class BuildHintAnnotationBinding { + + /** JVM descriptor of an annotation type, by its simple name. */ + private static final Map DESCRIPTORS = + new HashMap(); + /** "#" to hint name. */ + private static final Map HINTS = new HashMap(); + /** "#" to the value the build receives. */ + private static final Map WIRE = new HashMap(); + + static { + DESCRIPTORS.put("IosPrivacy", "Lcom/codename1/annotations/buildhints/IosPrivacy;"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#bluetoothAlwaysUsageDescription", "ios.NSBluetoothAlwaysUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#bluetoothPeripheralUsageDescription", "ios.NSBluetoothPeripheralUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#calendarsFullAccessUsageDescription", "ios.NSCalendarsFullAccessUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#calendarsUsageDescription", "ios.NSCalendarsUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#calendarsWriteOnlyAccessUsageDescription", "ios.NSCalendarsWriteOnlyAccessUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#cameraUsageDescription", "ios.NSCameraUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#healthShareUsageDescription", "ios.NSHealthShareUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#healthUpdateUsageDescription", "ios.NSHealthUpdateUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#localNetworkUsageDescription", "ios.NSLocalNetworkUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#locationAlwaysAndWhenInUseUsageDescription", "ios.NSLocationAlwaysAndWhenInUseUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#locationAlwaysUsageDescription", "ios.NSLocationAlwaysUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#locationWhenInUseUsageDescription", "ios.NSLocationWhenInUseUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#microphoneUsageDescription", "ios.NSMicrophoneUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#nearbyInteractionAllowOnceUsageDescription", "ios.NSNearbyInteractionAllowOnceUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#nearbyInteractionUsageDescription", "ios.NSNearbyInteractionUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#remindersFullAccessUsageDescription", "ios.NSRemindersFullAccessUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#remindersUsageDescription", "ios.NSRemindersUsageDescription"); + HINTS.put("Lcom/codename1/annotations/buildhints/IosPrivacy;#speechRecognitionUsageDescription", "ios.NSSpeechRecognitionUsageDescription"); + DESCRIPTORS.put("Ios", "Lcom/codename1/annotations/buildhints/Ios;"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#addLibs", "ios.add_libs"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#applicationQueriesSchemes", "ios.applicationQueriesSchemes"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#beforeFinishLaunching", "ios.beforeFinishLaunching"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#bundleVersion", "ios.bundleVersion"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#dependencyManager", "ios.dependencyManager"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#deploymentTarget", "ios.deployment_target"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#glAppDelegateHeader", "ios.glAppDelegateHeader"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#includePush", "ios.includePush"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#interfaceOrientation", "ios.interface_orientation"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#minDeploymentTarget", "ios.minDeploymentTarget"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#newStorageLocation", "ios.newStorageLocation"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#objC", "ios.objC"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#plistInject", "ios.plistInject"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#pods", "ios.pods"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#podsPlatform", "ios.pods.platform"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#podsSources", "ios.pods.sources"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#prerenderedIcon", "ios.prerendered_icon"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#projectType", "ios.project_type"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#spmPackages", "ios.spm.packages"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#teamId", "ios.teamId"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#themeMode", "ios.themeMode"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#uiscene", "ios.uiscene"); + HINTS.put("Lcom/codename1/annotations/buildhints/Ios;#urlScheme", "ios.urlScheme"); + DESCRIPTORS.put("Android", "Lcom/codename1/annotations/buildhints/Android;"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#activityLaunchMode", "android.activity.launchMode"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#appBundle", "android.appBundle"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#buildToolsVersion", "android.buildToolsVersion"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#captureRecord", "android.captureRecord"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#debug", "android.debug"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#disableR8", "android.disableR8"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#enableProguard", "android.enableProguard"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#gradleDep", "android.gradleDep"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#hideStatusBar", "android.hideStatusBar"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#installLocation", "android.installLocation"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#licenseKey", "android.licenseKey"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#minSdkVersion", "android.min_sdk_version"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#multidex", "android.multidex"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#newFirebaseMessaging", "android.newFirebaseMessaging"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#proguardKeep", "android.proguardKeep"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#release", "android.release"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#repositories", "android.repositories"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#targetSDKVersion", "android.targetSDKVersion"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#themeMode", "and.themeMode"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#topDependency", "android.topDependency"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#useAndroidX", "android.useAndroidX"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#xapplication", "android.xapplication"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#xgradle", "android.xgradle"); + HINTS.put("Lcom/codename1/annotations/buildhints/Android;#xpermissions", "android.xpermissions"); + DESCRIPTORS.put("Desktop", "Lcom/codename1/annotations/buildhints/Desktop;"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#adaptToRetina", "desktop.adaptToRetina"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#fullscreen", "desktop.fullscreen"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#height", "desktop.height"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#interactiveScrollbars", "desktop.interactiveScrollbars"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#resizable", "desktop.resizable"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#titleBar", "desktop.titleBar"); + HINTS.put("Lcom/codename1/annotations/buildhints/Desktop;#width", "desktop.width"); + DESCRIPTORS.put("OnDeviceDebug", "Lcom/codename1/annotations/buildhints/OnDeviceDebug;"); + HINTS.put("Lcom/codename1/annotations/buildhints/OnDeviceDebug;#android", "android.onDeviceDebug"); + HINTS.put("Lcom/codename1/annotations/buildhints/OnDeviceDebug;#ios", "ios.onDeviceDebug"); + HINTS.put("Lcom/codename1/annotations/buildhints/OnDeviceDebug;#iosProxyHost", "ios.onDeviceDebug.proxyHost"); + HINTS.put("Lcom/codename1/annotations/buildhints/OnDeviceDebug;#iosProxyPort", "ios.onDeviceDebug.proxyPort"); + HINTS.put("Lcom/codename1/annotations/buildhints/OnDeviceDebug;#iosWaitForAttach", "ios.onDeviceDebug.waitForAttach"); + DESCRIPTORS.put("Build", "Lcom/codename1/annotations/buildhints/Build;"); + HINTS.put("Lcom/codename1/annotations/buildhints/Build;#facebookAppId", "facebook.appId"); + HINTS.put("Lcom/codename1/annotations/buildhints/Build;#gcmSenderId", "gcm.sender_id"); + HINTS.put("Lcom/codename1/annotations/buildhints/Build;#nativeTheme", "nativeTheme"); + HINTS.put("Lcom/codename1/annotations/buildhints/Build;#noExtraResources", "noExtraResources"); + DESCRIPTORS.put("Hardening", "Lcom/codename1/annotations/buildhints/Hardening;"); + HINTS.put("Lcom/codename1/annotations/buildhints/Hardening;#allowUnhardenedLocalBuild", "harden.allowUnhardenedLocalBuild"); + HINTS.put("Lcom/codename1/annotations/buildhints/Hardening;#controlFlow", "harden.controlFlow"); + HINTS.put("Lcom/codename1/annotations/buildhints/Hardening;#keep", "harden.keep"); + HINTS.put("Lcom/codename1/annotations/buildhints/Hardening;#level", "harden.level"); + HINTS.put("Lcom/codename1/annotations/buildhints/Hardening;#rename", "harden.rename"); + HINTS.put("Lcom/codename1/annotations/buildhints/Hardening;#strings", "harden.strings"); + + WIRE.put("AndroidThemeMode#AUTO", "auto"); + WIRE.put("AndroidThemeMode#MODERN", "modern"); + WIRE.put("AndroidThemeMode#HOLOLIGHT", "hololight"); + WIRE.put("AndroidThemeMode#LEGACY", "legacy"); + WIRE.put("DesktopTitleBar#NATIVE", "native"); + WIRE.put("DesktopTitleBar#CUSTOM", "custom"); + WIRE.put("DesktopTitleBar#TOOLBAR", "toolbar"); + WIRE.put("HardenControlFlow#OFF", "off"); + WIRE.put("HardenControlFlow#ON", "on"); + WIRE.put("HardenLevel#OFF", "off"); + WIRE.put("HardenLevel#STANDARD", "standard"); + WIRE.put("HardenLevel#AGGRESSIVE", "aggressive"); + WIRE.put("HardenLevel#PARANOID", "paranoid"); + WIRE.put("HardenStrings#OFF", "off"); + WIRE.put("HardenStrings#CONSTANTS", "constants"); + WIRE.put("HardenStrings#ALL", "all"); + WIRE.put("InstallLocation#AUTO", "auto"); + WIRE.put("InstallLocation#INTERNAL_ONLY", "internalOnly"); + WIRE.put("InstallLocation#PREFER_EXTERNAL", "preferExternal"); + WIRE.put("IosDependencyManager#AUTO", "auto"); + WIRE.put("IosDependencyManager#COCOAPODS", "cocoapods"); + WIRE.put("IosDependencyManager#SPM", "spm"); + WIRE.put("IosDependencyManager#BOTH", "both"); + WIRE.put("IosDependencyManager#NONE", "none"); + WIRE.put("IosProjectType#IOS", "ios"); + WIRE.put("IosProjectType#IPAD", "ipad"); + WIRE.put("IosProjectType#IPHONE", "iphone"); + WIRE.put("IosThemeMode#AUTO", "auto"); + WIRE.put("IosThemeMode#MODERN", "modern"); + WIRE.put("IosThemeMode#IOS7", "ios7"); + WIRE.put("IosThemeMode#LEGACY", "legacy"); + WIRE.put("NativeThemeMode#MODERN", "modern"); + WIRE.put("NativeThemeMode#LEGACY", "legacy"); + WIRE.put("NativeThemeMode#CUSTOM", "custom"); + } + + private BuildHintAnnotationBinding() { + } + + /** Every build hint annotation descriptor, in JVM internal form. */ + public static java.util.Collection descriptors() { + return Collections.unmodifiableCollection(DESCRIPTORS.values()); + } + + /** + * The hint an annotation member sets. + * + * @param descriptor the annotation's JVM descriptor + * @param member the annotation member name + * @return the bare hint name, or null when the pair is not a build hint + */ + public static String hintFor(String descriptor, String member) { + return HINTS.get(descriptor + "#" + member); + } + + /** + * The value the build receives for an enum constant. + * + * @param enumDescriptorOrName the enum type, as a descriptor or a simple name + * @param constant the constant name as it appears in the class file + * @return the wire value, or null when the constant is unknown + */ + public static String wireValue(String enumDescriptorOrName, String constant) { + String simple = enumDescriptorOrName; + int slash = simple.lastIndexOf('/'); + if (slash >= 0) { + simple = simple.substring(slash + 1); + } + if (simple.endsWith(";")) { + simple = simple.substring(0, simple.length() - 1); + } + return WIRE.get(simple + "#" + constant); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintCodeGenerator.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintCodeGenerator.java new file mode 100644 index 00000000000..220023ade9c --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintCodeGenerator.java @@ -0,0 +1,786 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.FileOutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Generates the {@code com.codename1.annotations.build} annotation types from + * {@link BuildHints}, plus the binding table the annotation processor reads + * back. + * + *

The generated sources are checked in rather than produced into + * {@code target/}. {@code CodenameOne/src} is compiled by four independent + * front ends -- the Maven core module, the Ant/NetBeans project, IntelliJ and + * {@code ant core} -- and generating into {@code target/} reaches exactly one + * of them. The failure mode is not a build error but a jar-identity split, + * where {@code mvn install} and {@code ant core} produce different + * {@code codenameone-core.jar}s. Checked-in sources also mean {@code @Ios(} + * autocompletes in every IDE, which is the entire point of the feature.

+ * + *

Run through {@code scripts/gen-build-hint-annotations.sh}; CI re-runs it + * with {@code --check} and fails on any diff.

+ */ +public final class BuildHintCodeGenerator { + + private static final String LICENSE = + "/*\n" + + " * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.\n" + + " * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n" + + " * This code is free software; you can redistribute it and/or modify it\n" + + " * under the terms of the GNU General Public License version 2 only, as\n" + + " * published by the Free Software Foundation. Codename One designates this\n" + + " * particular file as subject to the \"Classpath\" exception as provided\n" + + " * by Oracle in the LICENSE file that accompanied this code.\n" + + " *\n" + + " * This code is distributed in the hope that it will be useful, but WITHOUT\n" + + " * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n" + + " * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n" + + " * version 2 for more details (a copy is included in the LICENSE file that\n" + + " * accompanied this code).\n" + + " *\n" + + " * You should have received a copy of the GNU General Public License version\n" + + " * 2 along with this work; if not, write to the Free Software Foundation,\n" + + " * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n" + + " *\n" + + " * Please contact Codename One through http://www.codenameone.com/ if you\n" + + " * need additional information or have any questions.\n" + + " */\n"; + + private static final String GENERATED_NOTE = + "/// Generated from com.codename1.build.shared.BuildHints by\n" + + "/// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and\n" + + "/// re-run scripts/gen-build-hint-annotations.sh.\n"; + + // NOT ...annotations.build: .gitignore carries a repo-wide **/build/* rule, + // which would silently make every generated source uncommittable and leave + // the CI drift gate with nothing to compare. + private static final String PKG = "com.codename1.annotations.buildhints"; + private static final String PKG_PATH = "com/codename1/annotations/buildhints"; + + private BuildHintCodeGenerator() { + } + + /** + * @param args annotation source root, the catalog source root for the + * generated binding table, then any number of further outputs: + * a directory receives the simulator schema, an {@code .adoc} + * file receives the developer guide's table + */ + public static void main(String[] args) throws IOException { + // The developer guide's table is not checked in: it is rendered from the + // catalog every time the guide is built, so it cannot drift and there is + // nothing for a hand edit to survive in. This mode writes that one file + // and nothing else, so a documentation build does not also rewrite source + // trees it has no business touching. + if (args.length == 2 && "--table-only".equals(args[0])) { + write(new File(args[1]), asciidocTable()); + return; + } + if (args.length < 2) { + System.err.println("usage: BuildHintCodeGenerator " + + " [output...]"); + System.exit(2); + } + File annRoot = new File(args[0], PKG_PATH); + File catalogRoot = new File(args[1], "com/codename1/build/shared"); + if (!annRoot.isDirectory() && !annRoot.mkdirs()) { + throw new IOException("Could not create " + annRoot); + } + + Map> byGroup = + new LinkedHashMap>(); + Map enums = new TreeMap(); + for (BuildHints.Hint h : BuildHints.entries()) { + if (!h.isAnnotated()) { + continue; + } + List list = byGroup.get(h.group()); + if (list == null) { + list = new ArrayList(); + byGroup.put(h.group(), list); + } + list.add(h); + if (h.type() == HintType.ENUM) { + BuildHints.Hint previous = enums.put(h.enumName(), h); + if (previous != null && !previous.values().equals(h.values())) { + throw new IllegalStateException("Enum " + h.enumName() + + " is declared with two different domains: " + + previous.name() + " and " + h.name()); + } + } + } + + Set written = new LinkedHashSet(); + for (Map.Entry> e : byGroup.entrySet()) { + Collections.sort(e.getValue(), new Comparator() { + public int compare(BuildHints.Hint a, BuildHints.Hint b) { + return a.attr().compareTo(b.attr()); + } + }); + String name = e.getKey().annotationSimpleName(); + write(new File(annRoot, name + ".java"), annotationSource(e.getKey(), e.getValue())); + written.add(name + ".java"); + } + for (Map.Entry e : enums.entrySet()) { + write(new File(annRoot, e.getKey() + ".java"), enumSource(e.getKey(), e.getValue())); + written.add(e.getKey() + ".java"); + } + write(new File(annRoot, "package-info.java"), packageInfoSource(byGroup)); + written.add("package-info.java"); + + // A group that loses its last annotated hint must not leave a stale + // annotation type behind: it would still compile and still be settable, + // and it would write a hint nothing reads. + File[] existing = annRoot.listFiles(); + if (existing != null) { + for (File f : existing) { + if (f.getName().endsWith(".java") && !written.contains(f.getName()) && !f.delete()) { + throw new IOException("Could not remove stale generated file " + f); + } + } + } + + write(new File(catalogRoot, "BuildHintAnnotationBinding.java"), bindingSource(byGroup, enums)); + for (int i = 2; i < args.length; i++) { + File target = new File(args[i]); + if (target.getName().endsWith(".adoc") || target.getName().endsWith(".asciidoc")) { + write(target, asciidocTable()); + } else { + write(new File(target, "com/codename1/impl/javase/BuildHintCatalogDefaults.java"), + simulatorSchemaSource(byGroup)); + } + } + System.out.println("cn1: generated " + written.size() + " source(s) under " + annRoot); + } + + private static String javaType(BuildHints.Hint h) { + switch (h.type()) { + case BOOLEAN: return "boolean"; + case INT: return "int"; + case ENUM: return h.enumName(); + case STRING_LIST: return "String[]"; + default: return "String"; + } + } + + private static String defaultClause(BuildHints.Hint h) { + String d = h.def(); + switch (h.type()) { + case BOOLEAN: + return "true".equals(d) ? "true" : "false"; + case INT: + if (d != null && d.length() > 0) { + try { + return String.valueOf(Integer.parseInt(d.trim())); + } catch (NumberFormatException ignored) { + // fall through to zero + } + } + return "0"; + case ENUM: + String constant = d != null && h.values().contains(d) + ? enumConstant(d) : enumConstant(h.values().get(0)); + return h.enumName() + "." + constant; + case STRING_LIST: + return "{}"; + default: + // A literal IP address in generated source reads to a static analyser + // as hardcoded configuration (PMD AvoidUsingHardCodedIP), and it is not + // load-bearing here: the annotation's default clause is documentation + // only, since the processor emits a hint solely for members the + // developer actually wrote. The real default stays in the javadoc. + if (d != null && LOOKS_LIKE_IP.matcher(d).matches()) { + return "\"\""; + } + return "\"" + esc(d == null ? "" : d) + "\""; + } + } + + private static final java.util.regex.Pattern LOOKS_LIKE_IP = + java.util.regex.Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3}|::1|[0-9a-fA-F:]*:[0-9a-fA-F:]+"); + + /** Wire value to Java enum constant: {@code internalOnly} to INTERNAL_ONLY. */ + static String enumConstant(String wire) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < wire.length(); i++) { + char c = wire.charAt(i); + if (Character.isUpperCase(c) && sb.length() > 0 + && Character.isLowerCase(wire.charAt(i - 1))) { + sb.append('_'); + } + sb.append(Character.isLetterOrDigit(c) ? Character.toUpperCase(c) : '_'); + } + String out = sb.toString(); + return Character.isDigit(out.charAt(0)) ? "V" + out : out; + } + + private static String annotationSource(HintGroup group, List hints) { + StringBuilder sb = new StringBuilder(LICENSE); + sb.append("package ").append(PKG).append(";\n\n"); + sb.append("import java.lang.annotation.ElementType;\n"); + sb.append("import java.lang.annotation.Retention;\n"); + sb.append("import java.lang.annotation.RetentionPolicy;\n"); + sb.append("import java.lang.annotation.Target;\n\n"); + sb.append(doc(groupBlurb(group), "")); + sb.append("///\n"); + sb.append(doc("Place this on your application's main class -- the class named by " + + "`codename1.mainName`. An attribute you do not set is not written at all, " + + "so the builder's own default applies; the values shown here are that " + + "default, for reference.", "")); + sb.append("///\n"); + sb.append(GENERATED_NOTE); + sb.append("@Retention(RetentionPolicy.CLASS)\n"); + sb.append("@Target(ElementType.TYPE)\n"); + sb.append("public @interface ").append(group.annotationSimpleName()).append(" {\n"); + for (int i = 0; i < hints.size(); i++) { + BuildHints.Hint h = hints.get(i); + sb.append("\n"); + String text = h.doc(); + if (text == null || text.length() == 0) { + text = group == HintGroup.IOS_PRIVACY + ? "The text iOS shows when the app first asks for " + + plistSubject(h.name()) + ". It becomes the `" + + h.name().substring("ios.".length()) + + "` key in `Info.plist`. The App Store rejects an app that " + + "touches this resource without one." + : "Sets the `" + h.name() + "` build hint."; + } + sb.append(doc(text, " ")); + if (h.type() == HintType.STRING_LIST) { + sb.append(doc("Values are joined with `" + visible(h.separator()) + + "` when the hint is written.", " ")); + } + if (h.deprecated() != null) { + sb.append(" ///\n"); + sb.append(doc("Deprecated. " + h.deprecated(), " ")); + sb.append(" @Deprecated\n"); + } + sb.append(" ").append(javaType(h)).append(" ").append(h.attr()) + .append("() default ").append(defaultClause(h)).append(";\n"); + } + sb.append("}\n"); + return sb.toString(); + } + + /// Turns ios.NSCameraUsageDescription into "the camera", so the generated + /// sentence reads naturally rather than repeating the plist key. + private static String plistSubject(String hintName) { + String body = hintName.substring("ios.NS".length()); + if (body.endsWith("UsageDescription")) { + body = body.substring(0, body.length() - "UsageDescription".length()); + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < body.length(); i++) { + char c = body.charAt(i); + if (i > 0 && Character.isUpperCase(c) && !Character.isUpperCase(body.charAt(i - 1))) { + sb.append(' '); + } + sb.append(i == 0 ? Character.toLowerCase(c) : c); + } + return "the " + sb.toString().toLowerCase(); + } + + private static String groupBlurb(HintGroup g) { + switch (g) { + case IOS: return "iOS build hints, checked by the compiler."; + case ANDROID: return "Android build hints, checked by the compiler."; + case DESKTOP: return "Desktop build hints, checked by the compiler."; + case HARDENING: return "App hardening build hints, checked by the compiler."; + case ON_DEVICE_DEBUG: return "On-device debugging build hints for iOS and Android."; + case IOS_PRIVACY: return "iOS `Info.plist` privacy usage descriptions. Set the one " + + "for every protected resource your app touches: the build server accepts " + + "an app without them, and the App Store rejects it."; + case GENERAL: return "Build hints that are not specific to one platform."; + default: return g.annotationSimpleName() + " build hints."; + } + } + + private static String enumSource(String name, BuildHints.Hint origin) { + StringBuilder sb = new StringBuilder(LICENSE); + sb.append("package ").append(PKG).append(";\n\n"); + sb.append(doc("Accepted values of the `" + origin.name() + "` build hint.", "")); + sb.append("///\n"); + sb.append(doc("Each constant carries the string the build actually receives, which is " + + "not always the constant's own name.", "")); + sb.append("///\n"); + sb.append(GENERATED_NOTE); + sb.append("public enum ").append(name).append(" {\n"); + List values = origin.values(); + List labels = origin.valueLabels(); + for (int i = 0; i < values.size(); i++) { + String v = values.get(i); + if (i < labels.size()) { + sb.append(doc(labels.get(i), " ")); + } + sb.append(" ").append(enumConstant(v)).append("(\"").append(esc(v)).append("\")"); + sb.append(i == values.size() - 1 ? ";\n" : ",\n"); + } + sb.append("\n private final String wire;\n\n"); + sb.append(" ").append(name).append("(String wire) {\n"); + sb.append(" this.wire = wire;\n }\n\n"); + sb.append(doc("The value written into the build hint.", " ")); + sb.append(" public String wireValue() {\n return wire;\n }\n}\n"); + return sb.toString(); + } + + private static String packageInfoSource(Map> byGroup) { + StringBuilder sb = new StringBuilder(LICENSE); + sb.append(doc("Build hints expressed as annotations, so the compiler checks them.", "")); + sb.append("///\n"); + sb.append(doc("A build hint used to be a `codename1.arg.=` line in " + + "`codenameone_settings.properties`. Nothing validated it, so a misspelled " + + "name was copied into the build request, never read, and silently dropped: " + + "the build stayed green and the setting simply did nothing. Written as an " + + "annotation the same mistake is an unknown symbol, a wrong value type is a " + + "type error, and a value outside a hint's supported set is an unknown enum " + + "constant.", "")); + sb.append("///\n"); + sb.append(doc("Put the annotations on your application's main class:", "")); + sb.append("///\n"); + sb.append("/// ```java\n"); + sb.append("/// @Ios(newStorageLocation = true, themeMode = IosThemeMode.MODERN)\n"); + sb.append("/// @Android(themeMode = AndroidThemeMode.MODERN)\n"); + sb.append("/// @Desktop(titleBar = DesktopTitleBar.NATIVE)\n"); + sb.append("/// public class MyApplication {\n"); + sb.append("/// }\n"); + sb.append("/// ```\n"); + sb.append("///\n"); + sb.append(doc("These annotations cover the hints most applications set. The rest, and " + + "the open-ended families such as `android.permission.` that an " + + "annotation cannot express, are still set in " + + "`codenameone_settings.properties`, which continues to work exactly as " + + "before. Setting the same hint in both places is a build error.", "")); + sb.append("///\n"); + sb.append(doc("A project generated recently already runs the goal that turns these into " + + "build hints. An older one may not: a goal's default phase does not add an " + + "execution to a project, so the annotations would compile and then be ignored. " + + "The build refuses rather than shipping without them, and the module that " + + "compiles the main class needs:", "")); + sb.append("///\n"); + sb.append("/// ```xml\n"); + sb.append("/// \n"); + sb.append("/// cn1-process-classes\n"); + sb.append("/// process-classes\n"); + sb.append("/// \n"); + sb.append("/// process-annotations\n"); + sb.append("/// \n"); + sb.append("/// \n"); + sb.append("/// ```\n"); + sb.append("///\n"); + sb.append(GENERATED_NOTE); + sb.append("package ").append(PKG).append(";\n"); + return sb.toString(); + } + + private static String bindingSource(Map> byGroup, + Map enums) { + StringBuilder sb = new StringBuilder(LICENSE); + sb.append("package com.codename1.build.shared;\n\n"); + sb.append("import java.util.Collections;\n"); + sb.append("import java.util.HashMap;\n"); + sb.append("import java.util.Map;\n\n"); + sb.append("/**\n"); + sb.append(" * Maps a build hint annotation back to the hint it sets.\n"); + sb.append(" *\n"); + sb.append(" *

The annotation processor reads bytecode, where an annotation member is\n"); + sb.append(" * just a name and an enum value is just a constant name. It must not\n"); + sb.append(" * re-derive the hint name or the wire value from those strings: the folding\n"); + sb.append(" * rule would then exist in two places, and a builder silently falls back to\n"); + sb.append(" * its default on a value it does not recognise, so a mismatch would be\n"); + sb.append(" * invisible. This table is generated from the same catalog as the\n"); + sb.append(" * annotations, so the two cannot drift.

\n"); + sb.append(" *\n"); + sb.append(" *

Generated by BuildHintCodeGenerator. Do not edit by hand.

\n"); + sb.append(" */\n"); + sb.append("public final class BuildHintAnnotationBinding {\n\n"); + sb.append(" /** JVM descriptor of an annotation type, by its simple name. */\n"); + sb.append(" private static final Map DESCRIPTORS =\n"); + sb.append(" new HashMap();\n"); + sb.append(" /** \"#\" to hint name. */\n"); + sb.append(" private static final Map HINTS = new HashMap();\n"); + sb.append(" /** \"#\" to the value the build receives. */\n"); + sb.append(" private static final Map WIRE = new HashMap();\n\n"); + sb.append(" static {\n"); + for (Map.Entry> e : byGroup.entrySet()) { + String simple = e.getKey().annotationSimpleName(); + String desc = "L" + PKG_PATH + "/" + simple + ";"; + sb.append(" DESCRIPTORS.put(\"").append(simple).append("\", \"") + .append(desc).append("\");\n"); + for (BuildHints.Hint h : e.getValue()) { + sb.append(" HINTS.put(\"").append(desc).append("#").append(h.attr()) + .append("\", \"").append(esc(h.name())).append("\");\n"); + } + } + sb.append("\n"); + for (Map.Entry e : enums.entrySet()) { + for (String v : e.getValue().values()) { + sb.append(" WIRE.put(\"").append(e.getKey()).append("#") + .append(enumConstant(v)).append("\", \"").append(esc(v)).append("\");\n"); + } + } + sb.append(" }\n\n"); + sb.append(" private BuildHintAnnotationBinding() {\n }\n\n"); + sb.append(" /** Every build hint annotation descriptor, in JVM internal form. */\n"); + sb.append(" public static java.util.Collection descriptors() {\n"); + sb.append(" return Collections.unmodifiableCollection(DESCRIPTORS.values());\n }\n\n"); + sb.append(" /**\n"); + sb.append(" * The hint an annotation member sets.\n"); + sb.append(" *\n"); + sb.append(" * @param descriptor the annotation's JVM descriptor\n"); + sb.append(" * @param member the annotation member name\n"); + sb.append(" * @return the bare hint name, or null when the pair is not a build hint\n"); + sb.append(" */\n"); + sb.append(" public static String hintFor(String descriptor, String member) {\n"); + sb.append(" return HINTS.get(descriptor + \"#\" + member);\n }\n\n"); + sb.append(" /**\n"); + sb.append(" * The value the build receives for an enum constant.\n"); + sb.append(" *\n"); + sb.append(" * @param enumDescriptorOrName the enum type, as a descriptor or a simple name\n"); + sb.append(" * @param constant the constant name as it appears in the class file\n"); + sb.append(" * @return the wire value, or null when the constant is unknown\n"); + sb.append(" */\n"); + sb.append(" public static String wireValue(String enumDescriptorOrName, String constant) {\n"); + sb.append(" String simple = enumDescriptorOrName;\n"); + sb.append(" int slash = simple.lastIndexOf('/');\n"); + sb.append(" if (slash >= 0) {\n"); + sb.append(" simple = simple.substring(slash + 1);\n }\n"); + sb.append(" if (simple.endsWith(\";\")) {\n"); + sb.append(" simple = simple.substring(0, simple.length() - 1);\n }\n"); + sb.append(" return WIRE.get(simple + \"#\" + constant);\n }\n"); + sb.append("}\n"); + return sb.toString(); + } + + /** + * The simulator's Build Hint editor schema for every annotated hint. + * + *

Emitted as a companion to the hand-written BuildHintSchemaDefaults + * rather than replacing it: that file carries carefully written labels and + * group descriptions for fifteen hints, and regenerating it would trade real + * prose for mechanical text. Its registrations run first and {@code set} does + * not overwrite, so anything it describes by hand wins and this fills in the + * rest.

+ * + *

Generated as source rather than read from the catalog jar at runtime + * because Ports/JavaSE is built by Ant as well as Maven, and the Ant build + * has a hand-maintained classpath that a new jar would have to be added to.

+ */ + private static String simulatorSchemaSource(Map> byGroup) { + StringBuilder sb = new StringBuilder(LICENSE); + sb.append("package com.codename1.impl.javase;\n\n"); + sb.append("/**\n"); + sb.append(" * Build Hint editor schema for every hint that has a build hint annotation.\n"); + sb.append(" *\n"); + sb.append(" *

Generated from com.codename1.build.shared.BuildHints by\n"); + sb.append(" * BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and re-run\n"); + sb.append(" * scripts/gen-build-hint-annotations.sh.

\n"); + sb.append(" *\n"); + sb.append(" *

Registered after {@link BuildHintSchemaDefaults} and skipping every hint\n"); + sb.append(" * that class already describes. Precedence cannot be left to the setter:\n"); + sb.append(" * the group name is part of the property key, so registering harden.level\n"); + sb.append(" * under both `hardening` and `Hardening` does not overwrite anything -- it\n"); + sb.append(" * makes a second group, and the editor renders both, giving the user\n"); + sb.append(" * duplicate controls for one setting.

\n"); + sb.append(" */\n"); + sb.append("final class BuildHintCatalogDefaults {\n\n"); + sb.append(" private BuildHintCatalogDefaults() {\n }\n\n"); + sb.append(" static void register() {\n"); + sb.append(" java.util.Set handWritten = BuildHintSchemaDefaults.declaredHints();\n"); + for (Map.Entry> e : byGroup.entrySet()) { + String group = e.getKey().annotationSimpleName(); + sb.append("\n set(\"{{@").append(group).append("}}.label\", ") + .append(quote(toAscii(groupLabel(e.getKey())))).append(");\n"); + for (BuildHints.Hint h : e.getValue()) { + String key = "{{#" + group + "#" + h.name() + "}}"; + sb.append(" if (!handWritten.contains(\"").append(esc(h.name())) + .append("\")) {\n"); + sb.append(" set(\"").append(key).append(".label\", ") + .append(quote(humanize(h.attr()))).append(");\n"); + sb.append(" set(\"").append(key).append(".type\", \"") + .append(BuildHints.editorWidget(h.type())).append("\");\n"); + if (h.type() == HintType.ENUM) { + StringBuilder values = new StringBuilder(); + for (String v : h.values()) { + if (values.length() > 0) { + values.append(','); + } + values.append(v); + } + sb.append(" set(\"").append(key).append(".values\", \"") + .append(values).append("\");\n"); + } + if (h.doc() != null && h.doc().length() > 0) { + sb.append(" set(\"").append(key).append(".description\", ") + .append(quote(toAscii(h.doc()))).append(");\n"); + } + sb.append(" }\n"); + } + } + sb.append(" }\n\n"); + sb.append(" /** Idempotent setter: does not overwrite user or project-level metadata. */\n"); + sb.append(" private static void set(String suffix, String value) {\n"); + sb.append(" String key = \"codename1.arg.\" + suffix;\n"); + sb.append(" if (System.getProperty(key) == null) {\n"); + sb.append(" System.setProperty(key, value);\n }\n }\n}\n"); + return sb.toString(); + } + + /** + * The developer guide's build hint table. + * + *

The hand-written table it replaces had a Name and a Description column + * and nothing else, so the Settings tool had to guess each hint's type by + * string-matching the description prose. Generating it adds the type and the + * default the builders actually use, and means a hint added to a builder can + * no longer be missing from the guide.

+ */ + private static String asciidocTable() { + List all = new ArrayList(BuildHints.entries()); + Collections.sort(all, new Comparator() { + public int compare(BuildHints.Hint a, BuildHints.Hint b) { + int byPlatform = a.platform().compareTo(b.platform()); + return byPlatform != 0 ? byPlatform : a.name().compareTo(b.name()); + } + }); + StringBuilder sb = new StringBuilder(); + sb.append("// Generated from com.codename1.build.shared.BuildHints by\n"); + sb.append("// BuildHintCodeGenerator. Do not edit by hand -- edit the catalog and re-run\n"); + sb.append("// scripts/gen-build-hint-annotations.sh.\n"); + sb.append("//\n"); + sb.append("// The Annotation column names the compiler-checked form where one exists;\n"); + sb.append("// those hints can be written on the application's main class instead of in\n"); + sb.append("// codenameone_settings.properties.\n\n"); + sb.append("[cols=\"2,1,1,2,4\"]\n"); + sb.append("|===\n"); + sb.append("|Name |Type |Default |Annotation |Description\n\n"); + for (BuildHints.Hint h : all) { + // Dynamic families are listed too: their names are patterns rather than + // keys, but they are real settings a reader needs to find. + sb.append('|').append(cell(h.name())).append('\n'); + sb.append('|').append(cell(adocType(h))).append('\n'); + // A default is a literal value, not prose. One containing a quote -- + // android.file_paths defaults to an XML fragment -- trips Vale's + // Microsoft.Quotes rule, which the developer guide enforces as an + // error. Protect just that line using the mechanism .vale.ini + // documents for individual false positives. + if (h.def() != null && h.def().indexOf('"') >= 0) { + sb.append("// vale-skip: Microsoft.Quotes: this is a literal default value, ") + .append("not prose -- the quotes belong to the value.\n"); + } + sb.append('|').append(h.def() == null || h.def().length() == 0 + ? "_(none)_" : "`" + cell(h.def()) + "`").append('\n'); + sb.append('|').append(h.isAnnotated() + ? "`@" + h.group().annotationSimpleName() + "(" + h.attr() + ")`" + : (h.isDynamic() ? "_(properties file only)_" : "_(none)_")).append('\n'); + String doc = h.doc(); + if (doc == null || doc.length() == 0) { + doc = h.isExternal() + ? "Consumed by the build service. Not read by anything in the framework " + + "repository, so there is no in-repo reference for it." + : ""; + } + sb.append('|').append(cell(doc)).append("\n\n"); + } + sb.append("|===\n"); + return sb.toString(); + } + + /** + * Escapes a value for an AsciiDoc table cell. + * + *

A bare {@code |} starts a new cell, so a hint whose documentation + * contains one -- {@code ios.spm.packages} is written + * {@code identity|url|requirement} -- silently shifts every following column + * and asciidoctor reports "dropping cells from incomplete row" for the whole + * table.

+ */ + private static String cell(String text) { + return text == null ? "" : text.replace("|", "\\|"); + } + + private static String adocType(BuildHints.Hint h) { + if (h.type() == HintType.ENUM) { + StringBuilder sb = new StringBuilder(); + for (String v : h.values()) { + sb.append(sb.length() == 0 ? "" : ", ").append('`').append(v).append('`'); + } + return sb.toString(); + } + if (h.type() == HintType.STRING_LIST) { + String sep = "\n".equals(h.separator()) ? "newline" : "`" + h.separator() + "`"; + return "list (" + sep + " delimited)"; + } + return h.type().name().toLowerCase(); + } + + private static String groupLabel(HintGroup g) { + switch (g) { + case IOS: return "iOS"; + case ANDROID: return "Android"; + case DESKTOP: return "Desktop"; + case HARDENING: return "App Hardening"; + case ON_DEVICE_DEBUG: return "On-Device Debugging"; + case IOS_PRIVACY: return "iOS Privacy Strings"; + case GENERAL: return "General"; + default: return g.annotationSimpleName(); + } + } + + /** newStorageLocation -> "New storage location". */ + private static String humanize(String attr) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < attr.length(); i++) { + char c = attr.charAt(i); + if (i > 0 && Character.isUpperCase(c) && !Character.isUpperCase(attr.charAt(i - 1))) { + sb.append(' ').append(Character.toLowerCase(c)); + } else { + sb.append(i == 0 ? Character.toUpperCase(c) : c); + } + } + return sb.toString(); + } + + /** Java string literal, wrapped so the generated line stays readable. */ + private static String quote(String s) { + return "\"" + esc(s) + "\""; + } + + + /** + * Folds text to ASCII. + * + *

The prose is imported from the developer guide, which uses typographic + * punctuation. {@code CodenameOne/src} is also compiled by an Ant javac step + * with ASCII encoding, where a single em dash is + * {@code error: unmappable character for encoding ASCII} -- a build failure, + * not a warning. A Unicode escape would not help: javac processes + * {@code \\uXXXX} before it strips comments, so the character would simply + * reappear.

+ */ + static String toAscii(String text) { + if (text == null) { + return null; + } + StringBuilder sb = new StringBuilder(text.length()); + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + switch (c) { + case '\u2014': sb.append("--"); break; // em dash + case '\u2013': sb.append('-'); break; // en dash + case '\u2018': + case '\u2019': sb.append('\''); break; // curly single quotes + case '\u201c': + case '\u201d': sb.append('"'); break; // curly double quotes + case '\u2026': sb.append("..."); break; // ellipsis + case '\u2192': sb.append("->"); break; // right arrow + case '\u00d7': sb.append('x'); break; // multiplication sign + case '\u00a0': sb.append(' '); break; // non-breaking space + default: + if (c < 0x80) { + sb.append(c); + break; + } + // Refuse rather than drop it. Silently deleting a character + // from a hint's documentation is a worse outcome than telling + // whoever edited the catalog to add a mapping here. + throw new IllegalArgumentException("Build hint documentation contains '" + + c + "' (U+" + Integer.toHexString(c).toUpperCase() + + "), which has no ASCII equivalent in toAscii(). The Ant javac step " + + "compiles CodenameOne/src as ASCII and rejects it as unmappable. " + + "Add a mapping, or reword the text."); + } + } + return sb.toString(); + } + + /** Wraps text as /// markdown doc comment lines. */ + private static String doc(String text, String indent) { + String clean = toAscii(text).replace("@since", "since").replaceAll("\\s+", " ").trim(); + StringBuilder sb = new StringBuilder(); + StringBuilder line = new StringBuilder(); + for (String word : clean.split(" ")) { + if (line.length() > 0 && line.length() + word.length() + 1 > 76) { + sb.append(indent).append("/// ").append(line).append("\n"); + line.setLength(0); + } + if (line.length() > 0) { + line.append(' '); + } + line.append(word); + } + if (line.length() > 0) { + sb.append(indent).append("/// ").append(line).append("\n"); + } + return sb.toString(); + } + + private static String visible(String sep) { + if ("\n".equals(sep)) { + return "\\n"; + } + return sep; + } + + private static String esc(String s) { + return s.replace("\\", "\\\\").replace("\"", "\\\"") + .replace("\n", "\\n").replace("\t", "\\t").replace("\r", ""); + } + + private static void write(File f, String content) throws IOException { + if (f.getName().endsWith(".java")) { + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) >= 0x80) { + throw new IOException(f.getName() + " would contain the non-ASCII character '" + + content.charAt(i) + "' (U+" + + Integer.toHexString(content.charAt(i)).toUpperCase() + + "), which the Ant javac step rejects as unmappable. Add it to " + + "toAscii()."); + } + } + } + File parent = f.getParentFile(); + if (parent != null && !parent.isDirectory() && !parent.mkdirs()) { + throw new IOException("Could not create " + parent); + } + Writer w = new OutputStreamWriter(new FileOutputStream(f), "UTF-8"); + try { + w.write(content); + } finally { + w.close(); + } + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHints.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHints.java new file mode 100644 index 00000000000..b2517111d71 --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHints.java @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * The single source of truth for Codename One build hints. + * + *

A build hint is a {@code codename1.arg.=} entry that reaches + * a builder as {@code BuildRequest.getArg(name, default)}. Historically the set + * of hints was described in five places that drifted apart: a prose AsciiDoc + * table in the developer guide, a runtime scraper of that table in the Settings + * tool, a fifteen-entry schema in the simulator, a fourteen-entry separator map + * in the Maven plugin, and a hand-written reference shipped to coding agents. + * None of them was checked against the builders, so a hint could be documented + * and unread, or read and undocumented, or simply misspelled in the reference + * with nothing to catch it.

+ * + *

This table replaces all five. It is Java rather than a data file because + * its consumers span five classpaths with no JSON library in common — the + * Java 5 core, the Java 7 JavaSE port, the Java 8 Maven plugin + * and build daemon, and the Java 17 Settings tool — and because a + * catalog that javac itself checks is the same argument the annotation feature + * rests on.

+ * + *

Keep this file in sync with the BuildDaemon copy. Like + * {@link PlatformFeatureCatalog}, this class is mirrored into the out-of-repo + * build service; a single {@code .java} file is the sync unit.

+ * + *

Registration is split into one method per group rather than a single + * static block on purpose: a class initializer carrying every entry would + * exceed the JVM's 64KB per-method bytecode limit.

+ */ +public final class BuildHints { + + /** Prefix every build hint carries inside a settings or library properties file. */ + public static final String ARG_PREFIX = "codename1.arg."; + + private static final List ENTRIES; + private static final Map BY_NAME; + + static { + List h = new ArrayList(); + BuildHintsIos.register(h); + BuildHintsAndroid.register(h); + BuildHintsApple.register(h); + BuildHintsDesktop.register(h); + BuildHintsGeneral.register(h); + BuildHintsDynamic.register(h); + BuildHintsExternal.register(h); + + Map byName = new LinkedHashMap(); + for (Hint entry : h) { + if (byName.put(entry.name(), entry) != null) { + throw new IllegalStateException("Duplicate build hint: " + entry.name()); + } + } + ENTRIES = Collections.unmodifiableList(h); + BY_NAME = Collections.unmodifiableMap(byName); + } + + private BuildHints() { + } + + /** Every catalogued hint, in registration order. */ + public static List entries() { + return ENTRIES; + } + + /** + * Looks up a hint by its bare name. + * + * @param name the hint name, with or without the {@link #ARG_PREFIX} + * @return the hint, or null when the catalog does not describe it + */ + public static Hint byName(String name) { + if (name == null) { + return null; + } + return BY_NAME.get(strip(name)); + } + + /** Removes the {@link #ARG_PREFIX} if present. */ + public static String strip(String name) { + if (name != null && name.startsWith(ARG_PREFIX)) { + return name.substring(ARG_PREFIX.length()); + } + return name; + } + + /** + * The string that joins two values of this hint when a cn1lib appends to a + * project's value, and that splits an annotation's {@code String[]} back + * into wire form. + * + *

Returns the empty string for a hint the catalog does not describe, + * which is the historical bare-concatenation behaviour that the XML + * fragment hints depend on.

+ */ + public static String separatorFor(String name) { + Hint entry = byName(name); + if (entry == null || entry.separator() == null) { + return ""; + } + return entry.separator(); + } + + /** + * Resolves an alias to the hint whose value it overrides. A few Android + * hints have a short {@code and.} spelling that takes precedence over the + * {@code android.} one; both names denote a single effective setting, so + * conflict detection has to collapse them. + * + * @return the aliased hint, or the argument itself when it is not an alias + */ + public static Hint resolve(Hint entry) { + if (entry == null || entry.aliasOf() == null) { + return entry; + } + Hint target = byName(entry.aliasOf()); + return target == null ? entry : target; + } + + /** The hint a name ultimately denotes, following an alias if there is one. */ + public static String canonicalName(String name) { + Hint entry = byName(name); + if (entry == null) { + return strip(name); + } + return resolve(entry).name(); + } + + /** + * The type vocabulary the Settings tool searches and validates by. Derived + * so it can no longer drift from {@link HintType}. + * + * @return one of BOOLEAN, INTEGER, VERSION, ENUM, XML, PATH, URL, CSV, + * SECRET, TEXT + */ + public static String settingsType(HintType type) { + switch (type) { + case BOOLEAN: return "BOOLEAN"; + case INT: return "INTEGER"; + case VERSION: return "VERSION"; + case ENUM: return "ENUM"; + case XML: return "XML"; + case PATH: return "PATH"; + case URL: return "URL"; + case STRING_LIST: return "CSV"; + case SECRET: return "SECRET"; + default: return "TEXT"; + } + } + + /** + * The widget the simulator's Build Hint editor renders. Derived so it can + * no longer drift from {@link HintType}. + * + * @return one of TextField, TextArea, Checkbox, Select + */ + public static String editorWidget(HintType type) { + switch (type) { + case BOOLEAN: return "Checkbox"; + case ENUM: return "Select"; + case TEXT_BLOCK: + case STRING_LIST: + case XML: return "TextArea"; + default: return "TextField"; + } + } + + /** + * One build hint. + * + *

Built fluently. Only {@link #name} is required; everything else + * defaults to "plain string, no default, not annotated", which is the + * correct shallow description of a hint nobody has curated yet.

+ */ + public static final class Hint { + private final String name; + private String aliasOf; + private String deprecated; + private HintGroup group = HintGroup.NONE; + private String attr; + private HintType type = HintType.STRING; + private String enumName; + private final List values = new ArrayList(); + private final Map valueAliases = new LinkedHashMap(); + private final List valueLabels = new ArrayList(); + private String def; + private String separator; + private String platform = "general"; + private boolean dynamic; + private String pattern; + private final List consumedBy = new ArrayList(); + private boolean external; + private boolean enterpriseOnly; + private String link; + private String doc = ""; + + Hint(String name) { + if (name == null || name.length() == 0) { + throw new IllegalArgumentException("Build hint name is required"); + } + this.name = name; + } + + /** Marks this hint as an override alias of another. */ + public Hint aliasOf(String other) { + this.aliasOf = other; + return this; + } + + /** Records that this hint is deprecated, naming what replaces it. */ + public Hint deprecated(String reason) { + this.deprecated = reason; + return this; + } + + /** Assigns the annotation type and the attribute name it is exposed as. */ + public Hint annotatedAs(HintGroup g, String attribute) { + this.group = g; + this.attr = attribute; + return this; + } + + /** Sets the group without exposing the hint as an annotation attribute. */ + public Hint group(HintGroup g) { + this.group = g; + return this; + } + + public Hint type(HintType t) { + this.type = t; + return this; + } + + /** + * Extra wire values the runtime accepts for an already-declared domain, + * each mapped to the canonical value it means. + * + *

Deliberately separate from {@link #values}: these do NOT become enum + * constants, because two constants for one behaviour is an API that asks + * a question with no right answer. They exist so that validation accepts + * what the runtime accepts — {@code ios.themeMode=flat} and + * {@code and.themeMode=material} are real, documented spellings, and + * rejecting them told a developer their working configuration was + * invalid — and so a migration can render one as the canonical + * constant rather than refusing it.

+ * + * @param pairs alias then canonical, repeated + */ + public Hint valueAliases(String... pairs) { + if (pairs.length % 2 != 0) { + throw new IllegalArgumentException( + "Build hint " + name + ": valueAliases takes alias/canonical pairs"); + } + for (int i = 0; i < pairs.length; i += 2) { + if (!values.contains(pairs[i + 1])) { + throw new IllegalArgumentException("Build hint " + name + " aliases " + + pairs[i] + " to " + pairs[i + 1] + ", which is not in its domain"); + } + valueAliases.put(pairs[i], pairs[i + 1]); + } + return this; + } + + /** + * Declares a closed value domain. Values are in wire form, i.e. + * exactly what the builder compares against, never the enum constant + * name. + */ + public Hint values(String enumTypeName, String... wireValues) { + this.type = HintType.ENUM; + this.enumName = enumTypeName; + this.values.clear(); + for (String v : wireValues) { + if (v.indexOf(',') >= 0) { + throw new IllegalArgumentException( + "Build hint " + name + " value '" + v + "' contains a comma, which the " + + "simulator's Build Hint editor uses to delimit its value list"); + } + this.values.add(v); + } + return this; + } + + /** Optional human labels for the value domain, parallel to the values. */ + public Hint valueLabels(String... labels) { + this.valueLabels.clear(); + Collections.addAll(this.valueLabels, labels); + return this; + } + + /** + * The builder's own default, i.e. the second argument of the + * {@code getArg} call that reads this hint. + */ + public Hint def(String value) { + this.def = value; + return this; + } + + /** + * The string that joins appended values. Empty string means the values + * abut directly, which is what the XML-fragment hints want. + */ + public Hint separator(String sep) { + this.separator = sep; + return this; + } + + public Hint platform(String p) { + this.platform = p; + return this; + } + + /** Declares an open-ended family of hints matching a name pattern. */ + public Hint dynamic(String namePattern) { + this.dynamic = true; + this.pattern = namePattern; + return this; + } + + /** Names the builders or mojos that read this hint. */ + public Hint consumedBy(String... classSimpleNames) { + Collections.addAll(this.consumedBy, classSimpleNames); + return this; + } + + /** + * Marks a hint that is read outside this repository, by a build-daemon + * lane whose source is not mirrored here. Such a hint has no in-repo + * consumer and that is not evidence it is dead. + */ + public Hint external() { + this.external = true; + return this; + } + + public Hint enterpriseOnly() { + this.enterpriseOnly = true; + return this; + } + + public Hint link(String url) { + this.link = url; + return this; + } + + /** One paragraph, reused verbatim by the docs, the javadoc and the UI. */ + public Hint doc(String text) { + this.doc = text == null ? "" : text; + return this; + } + + public String name() { return name; } + public String aliasOf() { return aliasOf; } + public String deprecated() { return deprecated; } + public HintGroup group() { return group; } + public String attr() { return attr; } + public HintType type() { return type; } + public String enumName() { return enumName; } + public List values() { return Collections.unmodifiableList(values); } + + /** Accepted spellings that are not their own value, alias to canonical. */ + public Map valueAliases() { + return Collections.unmodifiableMap(valueAliases); + } + + /** + * The canonical form of {@code value}, or null when the domain does not + * accept it. Case-insensitive, matching every reader of these hints. + */ + public String canonicalValue(String value) { + if (value == null) { + return null; + } + for (String allowed : values) { + if (allowed.equalsIgnoreCase(value)) { + return allowed; + } + } + for (Map.Entry e : valueAliases.entrySet()) { + if (e.getKey().equalsIgnoreCase(value)) { + return e.getValue(); + } + } + return null; + } + public List valueLabels() { return Collections.unmodifiableList(valueLabels); } + public String def() { return def; } + public String separator() { return separator; } + public String platform() { return platform; } + public boolean isDynamic() { return dynamic; } + public String pattern() { return pattern; } + public List consumedBy() { return Collections.unmodifiableList(consumedBy); } + public boolean isExternal() { return external; } + public boolean isEnterpriseOnly() { return enterpriseOnly; } + public String link() { return link; } + public String doc() { return doc; } + + /** Whether this hint is exposed as an annotation attribute. */ + public boolean isAnnotated() { + return attr != null && group.isAnnotated(); + } + + /** The full settings-file key, including the {@link #ARG_PREFIX}. */ + public String propertyKey() { + return ARG_PREFIX + name; + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsAndroid.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsAndroid.java new file mode 100644 index 00000000000..da6159c6a8d --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsAndroid.java @@ -0,0 +1,1588 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * Android build hints, including the {@code and.} override aliases. + * + *

Seeded by mining every {@code getArg} call site in the builders, so the + * name and the default match what the build actually reads. Curated entries + * carry an annotation attribute and, where the domain is provably closed, an + * enum; the rest are described but set through + * {@code codenameone_settings.properties}.

+ * + *

Split out of {@link BuildHints} because a single class initializer + * holding every entry would exceed the JVM's 64KB per-method limit.

+ */ +final class BuildHintsAndroid { + + private BuildHintsAndroid() { + } + + static void register(List h) { + // Not an abbreviation: the builder reads android.captureRecord and then + // lets and.captureRecord override it, so the two name ONE setting. + // Without the alias, @Android(captureRecord) and a properties line + // spelling it the short way are not seen as a conflict -- and the + // properties line wins, leaving the compile-checked annotation silently + // ineffective, which is the whole failure this feature exists to remove. + h.add(new Hint("and.captureRecord") + .aliasOf("android.captureRecord") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Override alias of `android.captureRecord`, read after it and winning when set.")); + + // Same override relationship (AndroidGradleBuilder reads the long name and + // then this one). Not annotated today, so nothing can conflict with it yet + // -- recorded so Settings collapses the pair, and so annotating the long + // name later cannot reintroduce the captureRecord bug. + h.add(new Hint("and.facebook_permissions") + .aliasOf("android.facebook_permissions") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder") + .doc("Override alias of `android.facebook_permissions`, read after it and winning " + + "when set. `IPhoneBuilder` also falls back to it when " + + "`ios.facebook_permissions` is unset.")); + + h.add(new Hint("and.themeMode") + .annotatedAs(HintGroup.ANDROID, "themeMode") + .values("AndroidThemeMode", "auto", "modern", "hololight", "legacy") + // AndroidImplementation.installNativeTheme compares against these + // too; see the note on ios.themeMode about why they are not + // constants. + .valueAliases("material", "modern", "holo", "hololight") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("`auto`, `modern` / `material`, `hololight` (default for existing apps), `legacy`. `auto` " + + "and `modern` / `material` opt in to the CSS-generated Android Material 3 theme from " + + "`native-themes/android-material/theme.css`. `hololight` is Android Holo Light (what the " + + "framework shipped on API 14+ before this refactor). `legacy` loads the pre-Holo Android " + + "theme. The legacy alias `cn1.androidTheme` is still accepted, and `and.hololight=true` " + + "still maps to `hololight`. The default stays on `hololight` for existing apps until you " + + "flip in a future release.")); + + h.add(new Hint("android.NotificationChannel.description") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("Remote notifications") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.enableLights") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.enableVibration") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.id") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("cn1-channel") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.importance") + .group(HintGroup.ANDROID) + .type(HintType.INT) + .def("2") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.lightColor") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.name") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("Notifications") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.NotificationChannel.vibrationPattern") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.accessibilityGuard") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.accessibilityGuard.allow") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.accessibilityGuard.mode") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("exit") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.activity.launchMode") + .annotatedAs(HintGroup.ANDROID, "activityLaunchMode") + .type(HintType.STRING) + .def("singleTop") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows explicitly setting the `android:launchMode` attribute of the main activity in " + + "android. Default is \"singleTop,\" but for some applications you may need to change this " + + "behaviour. In particular, apps that are meant to open a file type will need to set this " + + "to \"singleTask.\" See " + + "https://developer.android.com/guide/topics/manifest/activity-element.html[Android docs " + + "for the activity element] for more information about the `android:launchMode` attribute.")); + + h.add(new Hint("android.activityClassBody") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.activityClassImports") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.adaptiveIconBackground") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("#ffffff") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Background color to use for adaptive icons when `android.enableAdaptiveIcons=true` and " + + "no background image is supplied. Defaults to `#ffffff` and is written as " + + "`@color/ic_launcher_background`.")); + + h.add(new Hint("android.adaptiveIconBackgroundImage") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Optional path (relative to the root of the native Android project) to an image file to " + + "use as the adaptive icon background when `android.enableAdaptiveIcons=true`. If this " + + "property is set, it overrides `android.adaptiveIconBackground`.")); + + h.add(new Hint("android.allowBackup") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.androidAuto.messaging") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.androidAuto.minCarApiLevel") + .group(HintGroup.ANDROID) + .type(HintType.INT) + .def("1") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.androidAuto.navigation") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.androidAuto.poi") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.anyDensity") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.apacheLegacy") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.appBundle") + .annotatedAs(HintGroup.ANDROID, "appBundle") + .type(HintType.BOOLEAN) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Produces an Android App Bundle (.aab) rather than an APK. Required for new Play Store " + + "submissions.")); + + h.add(new Hint("android.appReview.version") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("2.0.1") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.ar.required") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.arrcompile") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.arrimplementation") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.asyncPaint") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Toggles the Android pipeline between the legacy " + + "pipeline (false) and new pipeline (true)")); + + h.add(new Hint("android.background_push_handling") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.billingclient.version") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("4.0.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.blockExternalStoragePermission") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Disables the external storage (SD card) permission")); + + h.add(new Hint("android.blockLabel") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Leaves `android:label` off the generated " + + "`` tag so a label set through `android.xapplication_attr` or a merged " + + "manifest is the one that survives. Honoured by the wear module's tag as well as the " + + "phone's.")); + + h.add(new Hint("android.blockReadMediaPermissions") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false, defaults to the value of `android.blockExternalStoragePermission`. " + + "Suppresses the `READ_MEDIA_VIDEO` and `READ_MEDIA_AUDIO` permissions that playing a URI " + + "adds on API 33 and above")); + + h.add(new Hint("android.bluetooth.neverForLocation") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.bluetooth.required") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.buildToolsVersion") + .annotatedAs(HintGroup.ANDROID, "buildToolsVersion") + .type(HintType.VERSION) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Android build-tools version. It also selects the compile SDK, so there is no separate " + + "compile-SDK hint.")); + + h.add(new Hint("android.captureRecord") + .annotatedAs(HintGroup.ANDROID, "captureRecord") + .type(HintType.STRING) + .def("enabled") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Indicates whether the `RECORD_AUDIO` permission should be requested. Can be `enabled` or " + + "any other value to disable this option")); + + h.add(new Hint("android.carAppVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("1.4.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.credentialsPlayServicesVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.credentialsVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("1.3.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.cusom_layout") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.cusom_layout1") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Applies to any number of layouts as long as they're in sequence (for example, " + + "android.cusom_layout2, android.cusom_layout3 etc.). Will write the content of the " + + "argument as a layout XML file and give it the name `cusom_layout1.xml` onwards. This can " + + "be used by native code to work with XML files")); + + h.add(new Hint("android.customActivity") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("CodenameOneActivity") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.customTabsVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("1.8.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.debug") + .annotatedAs(HintGroup.ANDROID, "debug") + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("true/false defaults to true - indicates whether to include the debug version in the " + + "build. Defaults conditionally rather than to a fixed value: when android.release is on " + + "it defaults to false, and when release is off it defaults to true, so a build that " + + "selects neither still produces something installable " + + "(AndroidGradleBuilder.java:447-451).")); + + h.add(new Hint("android.decouplePlayServiceVersions") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.delayPushCompletion") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.disableR8") + .annotatedAs(HintGroup.ANDROID, "disableR8") + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Turns off R8, falling back to the older shrinker. Note that hardening requires R8, so " + + "this conflicts with harden.level.")); + + h.add(new Hint("android.disableR8FullMode") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.disableScreenshots") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.enableAdaptiveIcons") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder", "CN1BuildMojo") + .doc("Boolean true/false defaults to false. Enables Android adaptive icon generation in " + + "Android Gradle builds. When enabled, Codename One generates `mipmap` launcher resources " + + "(`ic_launcher`, `ic_launcher_foreground`, and adaptive XML in `mipmap-anydpi-v26`) and " + + "uses them in the application manifest (`android:icon` and `android:roundIcon`).")); + + h.add(new Hint("android.enableProguard") + .annotatedAs(HintGroup.ANDROID, "enableProguard") + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Allows disabling the proguard obfuscation even on " + + "release builds, notice that this isn't recommended")); + + h.add(new Hint("android.excludeBolts") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.extendAppCompatActivity") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.facebookSdkVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("16.2.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.facebook_permissions") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("\"public_profile\",\"email\",\"user_friends\"") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Permissions for Facebook used in the Android build target, applicable only if Facebook " + + "native integration is used.")); + + h.add(new Hint("android.file_paths") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def(" ") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.firebaseAnalytics") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.firebaseAnalyticsVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("21.5.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.firebaseCoreVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.firebaseMessagingVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.foldableSupport") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.forceJava8Builder") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.foregroundServiceType") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("dataSync") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.fridaDetection") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Indicates whether the app should check for the " + + "presence of the https://www.frida.re/[Frida] dynamic instrumentation toolkit on the " + + "device. If Frida is detected, the app will exit. This uses the " + + "[frida-blocker](https://github.com/shannah/frida-blocker) library to perform the frida " + + "detection.")); + + h.add(new Hint("android.fullScreenIntent") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.googleAdUnitId") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows integrating admob/google play ads, this is effectively identical to " + + "google.adUnitId but only applies to Android")); + + h.add(new Hint("android.googleAdUnitTestDevice") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("C6783E2486F0931D9D09FABC65094FDF") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Device key used to mark a specific Android device as a test device for Google Play ads " + + "defaults to C6783E2486F0931D9D09FABC65094FDF")); + + h.add(new Hint("android.gpsPermission") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Indicates whether the GPS permission should be requested, it's autodetected by default " + + "if you use the location API. But, some code might want to explicitly define it")); + + h.add(new Hint("android.gradle.androidx") + .group(HintGroup.ANDROID) + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.gradleDep") + .annotatedAs(HintGroup.ANDROID, "gradleDep") + .type(HintType.STRING_LIST) + .separator(";") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Gradle dependency statements to add to the app module, such as implementation " + + "'com.example:lib:1.0'.")); + + h.add(new Hint("android.gradlePlugin") + .group(HintGroup.ANDROID) + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.hce") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.hceAids") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("F0010203040506") + .platform("android") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder")); + + h.add(new Hint("android.hceCategory") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("other") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.hceDescription") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.hceRequireUnlock") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.headphoneCallback") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. When set to true it assumes the main class has two " + + "methods: `headphonesConnected` & `headphonesDisconnected` which it invokes appropriately " + + "as needed")); + + h.add(new Hint("android.health.background") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.health.connectVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("1.1.0-alpha07") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.health.history") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.health.privacyPolicyUrl") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.health.read") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.health.write") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.hideOverlayWindows") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Declares the " + + "`android.permission.HIDE_OVERLAY_WINDOWS` permission needed by " + + "`DeviceIntegrity.setHideOverlayWindows()` on Android 12+, for apps that call the runtime " + + "API without enabling `android.tapjackingGuard`. A normal install-time permission, so the " + + "user sees no prompt.")); + + h.add(new Hint("android.hideStatusBar") + .annotatedAs(HintGroup.ANDROID, "hideStatusBar") + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Hides the Android status bar.")); + + h.add(new Hint("android.hms.pushVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("6.3.0.302") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.home.playServicesVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("16.0.0-beta1") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.includeGPlayServices") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("*Deprecated, please android.playService.+++*+++!* Indicates whether Google Play Services " + + "should be included into the build, defaults to false but that might change based on the " + + "functionality of the application and other build hints. Adding Google Play Services " + + "support allows you to use a more refined location implementation and invoke some Google " + + "specific functionality from native code.")); + + h.add(new Hint("android.includeMavenCentral") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.installLocation") + .annotatedAs(HintGroup.ANDROID, "installLocation") + .values("InstallLocation", "auto", "internalOnly", "preferExternal") + .def("auto") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Maps to android:installLocation manifest entry defaults to auto. Can also be set to " + + "internalOnly or preferExternal.")); + + h.add(new Hint("android.java8") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.keyboardOpen") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Toggles the new async keyboard mode that leaves the " + + "keyboard open while you move between text components")); + + h.add(new Hint("android.largeScreens") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.licenseKey") + .annotatedAs(HintGroup.ANDROID, "licenseKey") + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("The license key for the Android app, this is required if you use in-app purchase on " + + "Android")); + + h.add(new Hint("android.locales") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.manifest.queries") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Embeds XML content into the section of the Android manifest file. This is " + + "https://developer.android.com/training/package-visibility[required in Android 11 for " + + "package visibility]. See " + + "https://developer.android.com/guide/topics/manifest/queries-element[queries element " + + "Android documentation].")); + + h.add(new Hint("android.messagingService") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.migrateToAndroidX") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.maps.provider") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("MapsProviderInjector") + .doc("Android's own native map provider, overriding `maps.provider`.")); + + h.add(new Hint("android.min_sdk_version") + .annotatedAs(HintGroup.ANDROID, "minSdkVersion") + .type(HintType.INT) + .def("19") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("The least SDK required to run this app, the default value changes based on functionality " + + "but can be as low as 7. This corresponds to the XML attribute `android:minSdkVersion`.")); + + h.add(new Hint("android.mockLocation") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Toggles the mock location permission which is on by " + + "default, this allows easier debugging of Android device location based services")); + + h.add(new Hint("android.mopubId") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.multidex") + .annotatedAs(HintGroup.ANDROID, "multidex") + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Multidex allows Android binaries to reference more " + + "than 65536 methods. This slows builds a bit so you have it off by default but if you get " + + "a build error mentioning this limit you should turn this on.")); + + h.add(new Hint("android.nearby.computerProfile") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Offers the `computer` device profile in the companion-device chooser. " + + "Only read when the app uses nearby ranging, transport or companion " + + "association.")); + + h.add(new Hint("android.nearby.glassesProfile") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Offers the `glasses` device profile in the companion-device chooser, on " + + "the same terms as `android.nearby.computerProfile`.")); + + h.add(new Hint("android.nearby.watchProfile") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Offers the `watch` device profile in the companion-device chooser, on the " + + "same terms as `android.nearby.computerProfile`.")); + + h.add(new Hint("android.newFirebaseMessaging") + .annotatedAs(HintGroup.ANDROID, "newFirebaseMessaging") + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Uses the current Firebase Cloud Messaging integration. Requires AndroidX and Gradle 8.13 " + + "or newer.")); + + h.add(new Hint("android.nonconsumable") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Comma delimited string of items that are non-consumable in the in-app purchase API")); + + h.add(new Hint("android.normalScreens") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.onCreate") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playIntegrity") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playIntegrity.verifyUrl") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playIntegrityVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("1.4.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.ads") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.analytics") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.appInvite") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.auth") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.base") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.cast") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.drive") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.fitness") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.games") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.gcm") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.identity") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.indexing") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.location") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.maps") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.nearby") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.panorama") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.plus") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.safetynet") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.vision") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.wallet") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playService.wearable") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.playServicesVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("The version number of play services to build against. Experimental. **Use with caution** " + + "as building against versions other than the server default may introduce " + + "incompatibilities with some Codename One APIs.")); + + h.add(new Hint("android.proguardKeep") + .annotatedAs(HintGroup.ANDROID, "proguardKeep") + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Arguments for the keep option in proguard allowing you to keep a pattern of files for " + + "example, `-keep class com.mypackage.ProblemClass { *; }`")); + + h.add(new Hint("android.proguardKeepOverride") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("Exceptions, InnerClasses, Signature, Deprecated, SourceFile, LineNumberTable, *Annotation*, EnclosingMethod") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.pushSound") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.pushVibratePattern") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Comma delimited long values to describe the push pattern of vibrate used for the " + + "`setVibrate` native method")); + + h.add(new Hint("android.release") + .annotatedAs(HintGroup.ANDROID, "release") + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("true/false defaults to true - indicates whether to include the release version in the " + + "build")); + + h.add(new Hint("android.removeBasePermissions") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Disables the built-in permissions specifically " + + "`INTERNET` permission (that is, no networking...)")); + + h.add(new Hint("android.repositories") + .annotatedAs(HintGroup.ANDROID, "repositories") + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder", "MapsProviderInjector") + .doc("Extra Gradle repositories to resolve dependencies from.")); + + h.add(new Hint("android.requestReadMediaPermissions") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Declares `READ_MEDIA_IMAGES`, `READ_MEDIA_VIDEO` " + + "and `READ_MEDIA_AUDIO` on API 33 and above even when the build detected no media " + + "playback. `READ_MEDIA_IMAGES` is only ever added by this hint")); + + h.add(new Hint("android.rootCheck") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Indicates whether the app should check for root " + + "access on the device. If root access is detected, the app will exit.")); + + h.add(new Hint("android.rootbeerVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("0.1.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.shareFilter") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.sharedUserId") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows adding a manifest attribute for the sharedUserId option")); + + h.add(new Hint("android.sharedUserLabel") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows adding a manifest attribute for the sharedUserLabel option")); + + h.add(new Hint("android.shrinkResources") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Used only in conjunction with " + + "android.enableProguard. Strips out unused resources to reduce apk size. Since 7.0")); + + h.add(new Hint("android.smallScreens") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Corresponds to the `android:smallScreens` XML " + + "attribute and allows disabling the support for small phones")); + + h.add(new Hint("android.stack_size") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Size in bytes for the Android stack thread")); + + h.add(new Hint("android.statusbar_hidden") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("true/false defaults to false. When set to true hides the status bar on Android devices.")); + + h.add(new Hint("android.store_ids") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.streamMode") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("The mode in which the volume key should behave, defaults to OS default. Allows setting " + + "it to `music` for music playback apps")); + + h.add(new Hint("android.stringsXml") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows injecting more entries into the strings.xml file using a value that includes " + + "something like this `value1value2`")); + + h.add(new Hint("android.style") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows injecting more data into the `styles.xml` file right before the closing resources " + + "tag")); + + h.add(new Hint("android.supportScreens") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.supportv4Dep") + .group(HintGroup.ANDROID) + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.surfaces.complicationUpdateSeconds") + .group(HintGroup.ANDROID) + .type(HintType.INT) + .def("0") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("`UPDATE_PERIOD_SECONDS` on the generated complication service. Zero, the default, means " + + "the system never polls on a timer and the complication updates only when the app " + + "pushes new data.")); + + h.add(new Hint("android.surfaces.exactAlarms") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.tapjackingGuard") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to false. Switches on tapjacking / screen-overlay protection " + + "at launch, so touches that arrive while another app's window covers this one are " + + "detected and dropped. See the security chapter.")); + + h.add(new Hint("android.tapjackingGuard.hideOverlays") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Also asks Android 12+ to hide overlay windows drawn " + + "over the app, which is the only mitigation that covers native peer components, and " + + "declares the `HIDE_OVERLAY_WINDOWS` permission it requires. Only relevant if " + + "`android.tapjackingGuard=true`.")); + + h.add(new Hint("android.tapjackingGuard.mode") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("block") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("`block` (default), `strict`, `report` or `off`. `block` drops gestures that start on a " + + "fully obscured window, `report` only observes, `strict` also drops touches where only " + + "part of the window is covered (which benign system UI can trigger). Only relevant if " + + "`android.tapjackingGuard=true`.")); + + h.add(new Hint("android.targetSDKVersion") + .annotatedAs(HintGroup.ANDROID, "targetSDKVersion") + .type(HintType.INT) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("The Android SDK the build compiles against. Unset, the build server uses the " + + "highest platform it has installed, so leaving this alone tracks the " + + "server rather than pinning a number. Not every target works: the source " + + "may have limitations, and not all SDK targets are installed.")); + + h.add(new Hint("android.textureView") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.theme") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("Light") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Light or Dark defaults to Light. On Android 4+ the default Holo theme is used to render " + + "the native widgets sometimes and this indicates whether holo light or holo dark is used. " + + "This doesn't affect the Codename One theme but that might change in the future.")); + + h.add(new Hint("android.topDependency") + .annotatedAs(HintGroup.ANDROID, "topDependency") + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Statements added to the top-level Gradle build file rather than the app module.")); + + h.add(new Hint("android.tv") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("true/false (defaults to false). Marks the build as an Android TV / Google TV app. Adds " + + "the `LEANBACK_LAUNCHER` intent category to the launcher activity (so the app appears on " + + "the TV home screen), declares the `android.software.leanback` feature, makes " + + "`android.hardware.touchscreen` optional (so it installs on touchless TVs), and generates " + + "a 320×180 launcher banner (`@drawable/tv_banner`) from the app icon. The same APK still " + + "installs and runs on phones and tablets, and `CN.isTV()` returns true at runtime on a " + + "TV.")); + + h.add(new Hint("android.useAndroidX") + .annotatedAs(HintGroup.ANDROID, "useAndroidX") + .type(HintType.BOOLEAN) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Use Android X instead of support libraries. This will also run a find/replace on all " + + "source files to replace support libraries and artifacts with AndroidX equivalents.")); + + h.add(new Hint("android.useGradle8") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.versionCode") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows overriding the auto generated version number with a custom internal version " + + "number specifically used for the XML attribute `android:versionCode`")); + + h.add(new Hint("android.watchModule") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Boolean true/false defaults to true. Set to false to build the phone app alone in a " + + "companion build: the wearable link stays, no watch module is generated, and the " + + "phone output matches what it was before the watch app existed.")); + + h.add(new Hint("android.watchVersionCode") + .group(HintGroup.ANDROID) + .type(HintType.INT) + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("The wear module's version code, stated outright. Play requires it to be higher than the " + + "phone's, so a value other than a whole number above `android.versionCode` fails the " + + "build rather than being replaced without a word. Leave it unset to derive the value " + + "from `android.watchVersionCodeOffset`.")); + + h.add(new Hint("android.watchVersionCodeOffset") + .group(HintGroup.ANDROID) + .type(HintType.INT) + .def("100000000") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("How far above the phone's version code the wear module's sits when " + + "`android.watchVersionCode` is unset. The default leaves room for the phone app to " + + "keep incrementing without ever catching up.")); + + h.add(new Hint("android.wear") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.wear.complicationsVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("1.2.1") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Version of `androidx.wear.watchface:watchface-complications-data-source` added to the " + + "wear module. Kept out of `android.gradleDependencies` because that hint feeds the " + + "phone module too, and these libraries declare minSdk 26.")); + + h.add(new Hint("android.wear.guavaVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("31.1-android") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Version of `com.google.guava:guava` added to the wear module alongside the tiles and " + + "complications libraries, which need it at runtime.")); + + h.add(new Hint("android.wear.protoLayoutVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("1.2.1") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Version of the `androidx.wear.protolayout` libraries the generated tile service builds " + + "its layout with.")); + + h.add(new Hint("android.wear.tilesVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .def("1.4.1") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Version of `androidx.wear.tiles` added to the wear module when the app declares a tile.")); + + h.add(new Hint("android.wear.standalone") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.web_loading_hidden") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("true/false defaults to false - set to true to hide the progress indicator that appears " + + "when loading a web page on Android.")); + + h.add(new Hint("android.windowVersion") + .group(HintGroup.ANDROID) + .type(HintType.VERSION) + .def("1.3.0") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.xactivity") + .group(HintGroup.ANDROID) + .type(HintType.XML) + .separator("") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows injecting more attributes into the `activity` tag in the Android XML")); + + h.add(new Hint("android.xapplication") + .annotatedAs(HintGroup.ANDROID, "xapplication") + .type(HintType.XML) + .separator("") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("defaults to an empty string. Allows developers of native Android code to add text within " + + "the application block to define things such as widgets, services etc.")); + + h.add(new Hint("android.xapplication_attr") + .group(HintGroup.ANDROID) + .type(HintType.XML) + .separator(" ") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows injecting more attributes into the `application`` tag in the Android XML")); + + h.add(new Hint("android.xgradle") + .annotatedAs(HintGroup.ANDROID, "xgradle") + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Arbitrary text spliced into the generated app-module Gradle file.")); + + h.add(new Hint("android.xgradle_default_config") + .group(HintGroup.ANDROID) + .type(HintType.STRING_LIST) + .separator("\n") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.xintent_filter") + .group(HintGroup.ANDROID) + .type(HintType.XML) + .separator("") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("Allows adding an intent filter to the main android activity")); + + h.add(new Hint("android.xlargeScreens") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .def("true") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.xlayout_attr") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.xmanifest") + .group(HintGroup.ANDROID) + .type(HintType.XML) + .separator("") + .platform("android") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.xpermissions") + .annotatedAs(HintGroup.ANDROID, "xpermissions") + .type(HintType.XML) + .separator("") + .platform("android") + .consumedBy("AndroidGradleBuilder") + .doc("more permissions for the Android manifest")); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsApple.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsApple.java new file mode 100644 index 00000000000..a5cfc130d1b --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsApple.java @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * macOS Catalyst, tvOS and watchOS native-slice build hints. + * + *

Seeded by mining every {@code getArg} call site in the builders, so the + * name and the default match what the build actually reads. Curated entries + * carry an annotation attribute and, where the domain is provably closed, an + * enum; the rest are described but set through + * {@code codenameone_settings.properties}.

+ * + *

Split out of {@link BuildHints} because a single class initializer + * holding every entry would exceed the JVM's 64KB per-method limit.

+ */ +final class BuildHintsApple { + + private BuildHintsApple() { + } + + static void register(List h) { + h.add(new Hint("macNative.appCategory") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .def("public.app-category.utilities") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. `LSApplicationCategoryType` in the generated Info.plist. Default " + + "`public.app-category.utilities`. See " + + "https://developer.apple.com/documentation/bundleresources/information_property_list/lsapplicationcategorytype[Apple's " + + "category list].")); + + h.add(new Hint("macNative.bundleId") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Used only when `macNative.deriveBundleId=false`. Default: " + + "`.mac`.")); + + h.add(new Hint("macNative.copyright") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. `NSHumanReadableCopyright` in the Info.plist. Defaults to " + + "`Copyright (c) `.")); + + h.add(new Hint("macNative.deriveBundleId") + .group(HintGroup.MAC_NATIVE) + .type(HintType.BOOLEAN) + .def("true") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. `true` (default) maps to Xcode's " + + "`DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER=YES` (Xcode appends `.maccatalyst` to the " + + "iOS bundle ID). Set to `false` to take the bundle ID verbatim from `macNative.bundleId`.")); + + h.add(new Hint("macNative.distribution") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .def("appStore") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. `appStore` (default), `developerID`, or `both`. Selects which " + + "entitlements + ExportOptions plist + signing certificate to emit. `both` emits parallel " + + "`*-AppStore.entitlements` / `*-DeveloperID.entitlements` and matching " + + "`ExportOptions-*-Mac.plist` files so a single project can be archived to either channel.")); + + h.add(new Hint("macNative.enabled") + .group(HintGroup.MAC_NATIVE) + .type(HintType.BOOLEAN) + .def("false") + .platform("mac") + .consumedBy("CN1BuildMojo", "IPhoneBuilder", "MacNativeBuilder")); + + h.add(new Hint("macNative.entitlements.device.camera") + .group(HintGroup.MAC_NATIVE) + .type(HintType.BOOLEAN) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Sandboxed Mac Native builds only. Toggles " + + "`com.apple.security.device.camera`. Defaults to whether the app sets " + + "`ios.NSCameraUsageDescription`, so an app that asks for the camera gets " + + "the entitlement without naming it twice.")); + + h.add(new Hint("macNative.entitlements.device.microphone") + .group(HintGroup.MAC_NATIVE) + .type(HintType.BOOLEAN) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Sandboxed Mac Native builds only. Toggles " + + "`com.apple.security.device.microphone`. Defaults to whether the app sets " + + "`ios.NSMicrophoneUsageDescription`.")); + + h.add(new Hint("macNative.entitlements.personalInformation.calendars") + .group(HintGroup.MAC_NATIVE) + .type(HintType.BOOLEAN) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Sandboxed Mac Native builds only. Toggles " + + "`com.apple.security.personal-information.calendars`, which gates all " + + "EventKit access. Defaults to whether the app sets any calendar or " + + "reminder usage description, including the write-only and reminders-only " + + "ones.")); + + h.add(new Hint("macNative.entitlements.extra") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Free-form XML inserted verbatim inside the `` of " + + "the generated entitlements plist. Use for entitlements Codename One doesn't expose " + + "individually.")); + + h.add(new Hint("macNative.entitlements.files.userSelected") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .def("readwrite") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. `readwrite` (default), `readonly`, or `none`. Sets the matching " + + "`com.apple.security.files.user-selected.*` entitlement.")); + + h.add(new Hint("macNative.fixedWindowSize") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Opt-in. Format `x` — for example `1024x685`. When " + + "set, the Catalyst window's `UISceneSession.sizeRestrictions` minimum and maximum are " + + "pinned to the requested size so every launch produces a byte-identical window. Default " + + "unset, in which case the window is resizable. The CI screenshot pipeline turns this on " + + "to keep the strict-pixel golden comparison stable; production apps should leave it off.")); + + h.add(new Hint("macNative.iosMinDeploymentTarget") + .group(HintGroup.MAC_NATIVE) + .type(HintType.VERSION) + .def("13.1") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. iOS deployment-target floor for the Catalyst slice " + + "(`IPHONEOS_DEPLOYMENT_TARGET`). Default `13.1`. The plugin coerces the iOS slice's " + + "minimum upward when set.")); + + h.add(new Hint("macNative.minDeploymentTarget") + .group(HintGroup.MAC_NATIVE) + .type(HintType.VERSION) + .def("10.15") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Minimum macOS version (`MACOSX_DEPLOYMENT_TARGET`). Default " + + "`10.15` — earlier versions don't support Mac Catalyst.")); + + h.add(new Hint("macNative.notarize") + .group(HintGroup.MAC_NATIVE) + .type(HintType.BOOLEAN) + .def("false") + .platform("mac") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("macNative.notarize.appleId") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("macNative.notarize.keychainProfile") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("macNative.notarize.password") + .group(HintGroup.MAC_NATIVE) + .type(HintType.SECRET) + .platform("mac") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("macNative.notarize.teamId") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("macNative.signing.style") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .def("automatic") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. `automatic` (default) lets Xcode pick the signing certificate; " + + "`manual` forces the certificate identity hints below to be respected verbatim.")); + + h.add(new Hint("macNative.signingIdentity.appStore") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .def("Apple Distribution") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Signing certificate identity for the App Store channel. Default " + + "`Apple Distribution`.")); + + h.add(new Hint("macNative.signingIdentity.developerID") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .def("Developer ID Application") + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Signing certificate identity for the Developer ID channel. " + + "Default `Developer ID Application`.")); + + h.add(new Hint("macNative.teamId") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .consumedBy("MacNativeBuilder") + .doc("Mac Native builds only. Apple Developer Team ID (alphanumeric). Falls back to " + + "`ios.release.teamId` → `ios.teamId` → `ios.debug.teamId` since most apps share a single " + + "Apple Developer Team for iOS and Mac.")); + + h.add(new Hint("tvNative.bundleId") + .group(HintGroup.TV_NATIVE) + .type(HintType.STRING) + .platform("tv") + .consumedBy("TvNativeBuilder") + .doc("Bundle identifier of the tvOS app. Defaults to `.tvos`.")); + + h.add(new Hint("tvNative.displayName") + .group(HintGroup.TV_NATIVE) + .type(HintType.STRING) + .platform("tv") + .consumedBy("TvNativeBuilder") + .doc("The tvOS app name shown on Apple TV. Defaults to the app's display name.")); + + h.add(new Hint("tvNative.enabled") + .group(HintGroup.TV_NATIVE) + .type(HintType.BOOLEAN) + .def("false") + .platform("tv") + .consumedBy("IPhoneBuilder", "TvNativeBuilder") + .doc("true/false (defaults to false). Adds an Apple TV (tvOS) application target to the iOS " + + "build. The tvOS app is a separate `appletvos` target built from the same Java/Kotlin " + + "sources through ParparVM (UIKit + Metal; tvOS has no OpenGL ES). Enabling it doesn't " + + "change the iOS app -- in particular it doesn't override the iOS app's `ios.metal` " + + "setting. Also turned on implicitly by `codename1.tvMain`.")); + + h.add(new Hint("tvNative.mainClass") + .group(HintGroup.TV_NATIVE) + .type(HintType.STRING) + .platform("tv") + .consumedBy("IPhoneBuilder", "TvNativeBuilder")); + + h.add(new Hint("tvNative.minDeploymentTarget") + .group(HintGroup.TV_NATIVE) + .type(HintType.VERSION) + .def("13.0") + .platform("tv") + .consumedBy("TvNativeBuilder") + .doc("`TVOS_DEPLOYMENT_TARGET` for the tvOS target. Defaults to `13.0`.")); + + h.add(new Hint("tvNative.teamId") + .group(HintGroup.TV_NATIVE) + .type(HintType.STRING) + .platform("tv") + .consumedBy("TvNativeBuilder") + .doc("Apple Developer Team ID used to sign the tvOS target. Falls back to the iOS team id " + + "(`ios.release.teamId` / `ios.teamId` / `ios.debug.teamId`).")); + + h.add(new Hint("watchNative.enabled") + .group(HintGroup.WATCH_NATIVE) + .type(HintType.BOOLEAN) + .def("false") + .platform("watch") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("watchNative.health") + .group(HintGroup.WATCH_NATIVE) + .type(HintType.STRING) + .platform("watch") + .consumedBy("WatchNativeBuilder")); + + h.add(new Hint("watchNative.health.workoutProcessing") + .group(HintGroup.WATCH_NATIVE) + .type(HintType.BOOLEAN) + .def("false") + .platform("watch") + .consumedBy("WatchNativeBuilder")); + + h.add(new Hint("watchNative.surfaces.deploymentTarget") + .group(HintGroup.WATCH_NATIVE) + .type(HintType.STRING) + .def("10.0") + .platform("watch") + .consumedBy("IPhoneBuilder") + .doc("Deployment target of the WidgetKit extension that carries the watch complication. This " + + "is the WATCH APP's floor rather than the extension's own: WidgetKit reaches back to " + + "watchOS 9, but the extension is embedded in the watch app, so advertising a version " + + "the app itself refuses to install on claims support the user never gets.")); + + h.add(new Hint("watchNative.mainClass") + .group(HintGroup.WATCH_NATIVE) + .type(HintType.STRING) + .platform("watch") + .consumedBy("IPhoneBuilder")); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsDesktop.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsDesktop.java new file mode 100644 index 00000000000..58aa72d4642 --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsDesktop.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * Desktop, native Windows, native Linux and JavaScript build hints. + * + *

Seeded by mining every {@code getArg} call site in the builders, so the + * name and the default match what the build actually reads. Curated entries + * carry an annotation attribute and, where the domain is provably closed, an + * enum; the rest are described but set through + * {@code codenameone_settings.properties}.

+ * + *

Split out of {@link BuildHints} because a single class initializer + * holding every entry would exceed the JVM's 64KB per-method limit.

+ */ +final class BuildHintsDesktop { + + private BuildHintsDesktop() { + } + + static void register(List h) { + h.add(new Hint("desktop.adaptToRetina") + .annotatedAs(HintGroup.DESKTOP, "adaptToRetina") + .type(HintType.BOOLEAN) + .def("true") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("Boolean true/false defaults to true. When set to true some values will ve implicitly " + + "doubled to deal with retina displays and icons etc. Will use higher DPI's")); + + h.add(new Hint("desktop.fullscreen") + .annotatedAs(HintGroup.DESKTOP, "fullscreen") + .type(HintType.BOOLEAN) + .def("false") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("Starts the desktop build in full-screen mode.")); + + h.add(new Hint("desktop.height") + .annotatedAs(HintGroup.DESKTOP, "height") + .type(HintType.INT) + .def("600") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("Height in pixels for the form in desktop builds, will be doubled for retina grade " + + "displays. Defaults to 600.")); + + h.add(new Hint("desktop.interactiveScrollbars") + .annotatedAs(HintGroup.DESKTOP, "interactiveScrollbars") + .type(HintType.BOOLEAN) + .def("true") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("Enables grab-able, click-to-page desktop scrollbars.")); + + h.add(new Hint("desktop.resizable") + .annotatedAs(HintGroup.DESKTOP, "resizable") + .type(HintType.BOOLEAN) + .def("true") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("Boolean true/false defaults to true. Indicates whether the UI in the desktop build is " + + "resizable")); + + h.add(new Hint("desktop.title") + .group(HintGroup.DESKTOP) + .type(HintType.STRING) + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo")); + + h.add(new Hint("desktop.titleBar") + .annotatedAs(HintGroup.DESKTOP, "titleBar") + .values("DesktopTitleBar", "native", "custom", "toolbar") + .def("native") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("How the desktop window is framed: native for the OS title bar and menu bar, custom for " + + "an undecorated window with a Codename One drawn title bar, or toolbar for the legacy " + + "in-app Toolbar. An unrecognized value falls back to native with a warning.")); + + h.add(new Hint("desktop.width") + .annotatedAs(HintGroup.DESKTOP, "width") + .type(HintType.INT) + .def("800") + .platform("desktop") + .consumedBy("GenerateDesktopAppWrapperMojo") + .doc("Width in pixels for the form in desktop builds, will be doubled for retina grade " + + "displays. Defaults to 800.")); + + h.add(new Hint("javascript.includeVideoJS") + .group(HintGroup.JAVASCRIPT) + .type(HintType.BOOLEAN) + .def("false") + .platform("javascript") + .consumedBy("JavaScriptBuilder")); + + h.add(new Hint("javascript.inject_proxy") + .group(HintGroup.JAVASCRIPT) + .type(HintType.BOOLEAN) + .def("true") + .platform("javascript") + .consumedBy("JavaScriptProxyPackager") + .doc("true/false (defaults to `true`). The ParparVM builder generates a same-origin proxy " + + "bundle and configures the app to use it. Setting this to `false` disables both proxy " + + "generation and proxy URL injection.")); + + h.add(new Hint("javascript.portSources") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .consumedBy("JavaScriptBuilder")); + + h.add(new Hint("javascript.proxy.allowedTargets") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .consumedBy("JavaScriptProxyPackager") + .doc("Comma-separated target origins, host names, or wildcard subdomains that a generated " + + "proxy may access, for example `https://api.example.com,*.services.example.org`. If " + + "omitted, the proxy accepts any HTTP or HTTPS target and the build emits a warning.")); + + h.add(new Hint("javascript.proxy.target") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .def("jakarta-servlet") + .platform("javascript") + .consumedBy("CN1BuildMojo", "JavaScriptProxyPackager") + .doc("The generated ParparVM proxy deployment platform. Supported values are `jakarta-servlet` " + + "(default), `javax-servlet`, `node`, `php`, `aws-lambda`, `google-cloud-functions`, " + + "`cloudflare-workers`, and `none`.")); + + h.add(new Hint("javascript.proxy.url") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .consumedBy("JavaScriptProxyPackager") + .doc("The URL of an existing proxy to use for network requests. Setting it suppresses " + + "generated proxy packaging unless `javascript.proxy.target` is also set. If " + + "`javascript.inject_proxy` is `false`, this build hint is ignored.")); + + h.add(new Hint("linux.arch") + .group(HintGroup.LINUX) + .type(HintType.STRING) + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("linux.nativeVerify") + .group(HintGroup.LINUX) + .type(HintType.STRING) + .platform("linux") + .consumedBy("LinuxNativeBuilder") + .doc("`nativeVerify` for the native Linux translation alone.")); + + h.add(new Hint("linux.cc") + .group(HintGroup.LINUX) + .type(HintType.STRING) + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("linux.debug") + .group(HintGroup.LINUX) + .type(HintType.BOOLEAN) + .def("false") + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("linux.libc") + .group(HintGroup.LINUX) + .type(HintType.STRING) + .def("glibc") + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("linux.musl") + .group(HintGroup.LINUX) + .type(HintType.BOOLEAN) + .def("false") + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("linux.muslNativeCc") + .group(HintGroup.LINUX) + .type(HintType.BOOLEAN) + .def("false") + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("linux.toolchain") + .group(HintGroup.LINUX) + .type(HintType.STRING) + .platform("linux") + .consumedBy("LinuxNativeBuilder")); + + h.add(new Hint("windows.arch") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("Native Windows port only (the `windows-native` build target -- not the JVM `win.*` " + + "desktop hints above). Target CPU architecture for the standalone `.exe`: `x64` (the " + + "default) or `arm64`. Accepts the usual synonyms (`x86_64`/`amd64`, `aarch64`). clang-cl " + + "cross-compiles to the chosen architecture from either host. See the " + + "link:#_working_with_the_native_windows_port[Working with the native Windows port " + + "chapter].")); + + h.add(new Hint("windows.calendar.restrictedCapability") + .group(HintGroup.WINDOWS) + .type(HintType.BOOLEAN) + .def("false") + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.nativeVerify") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("`nativeVerify` for the native Windows translation alone.")); + + h.add(new Hint("windows.debug") + .group(HintGroup.WINDOWS) + .type(HintType.BOOLEAN) + .def("false") + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("Native Windows port only. true/false (defaults to false). When `false` the `.exe` is " + + "built optimized and *stripped* -- no PDB, dead-stripped unreferenced code (`/OPT:REF`) " + + "and folded identical functions (`/OPT:ICF`) -- which is the shipping default. Set `true` " + + "to keep debug symbols (a `.pdb` next to the exe, via `RelWithDebInfo` / clang-cl `/Zi` + " + + "linker `/DEBUG`) so a native crash address can be symbolized during development. " + + "Optimizations stay on in both cases.")); + + h.add(new Hint("windows.msix") + .group(HintGroup.WINDOWS) + .type(HintType.BOOLEAN) + .def("false") + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.msix.identityName") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.msix.password") + .group(HintGroup.WINDOWS) + .type(HintType.SECRET) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.msix.pfx") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.msix.publisher") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.msix.version") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.sdkRoot") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("Native Windows port only; used when building on a *non-Windows* host (for example a " + + "Linux build server). Path to a Windows SDK laid out by " + + "https://github.com/Jake-Shadle/xwin[`xwin splat`] (a directory containing `crt/include` " + + "and `sdk/include/um`), used to cross-compile the `.exe` with clang-cl + lld-link instead " + + "of a Visual Studio environment. If unset, the `CN1_XWIN_SYSROOT` environment variable is " + + "used. Ignored on Windows hosts, which build through Visual Studio. The same SDK serves " + + "both `windows.arch` targets (its `x86_64` / `aarch64` lib subdirs).")); + + h.add(new Hint("windows.signing") + .group(HintGroup.WINDOWS) + .type(HintType.BOOLEAN) + .def("true") + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("Native Windows port only. `true`/`false` (default `true`). Set `false` to force an " + + "unsigned build even when a certificate is available.")); + + h.add(new Hint("windows.signing.digest") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .def("sha256") + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("Native Windows port only. Signature digest algorithm. Default `sha256`.")); + + h.add(new Hint("windows.signing.name") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.signing.password") + .group(HintGroup.WINDOWS) + .type(HintType.SECRET) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.signing.pkcs12") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + + h.add(new Hint("windows.signing.timestampUrl") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .def("http://timestamp.digicert.com") + .platform("windows") + .consumedBy("WindowsNativeBuilder") + .doc("Native Windows port only. RFC 3161 timestamp server used when signing, so the " + + "signature stays valid after the certificate expires. Default " + + "`http://timestamp.digicert.com`; set empty to disable timestamping.")); + + h.add(new Hint("windows.signing.url") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .consumedBy("WindowsNativeBuilder")); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsDynamic.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsDynamic.java new file mode 100644 index 00000000000..9f3a99ee178 --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsDynamic.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * Open-ended hint families whose names are built by concatenation, so the set + * of valid keys is unbounded. + * + *

These are deliberately not exposed as annotation attributes. Each + * one is really a map — permission name to setting, entitlement key to + * value — and a Java annotation member cannot express a + * {@code Map}. The shapes that could work (a nested + * {@code @Permission[]}, or a {@code String[]} of {@code "KEY=VALUE"} pairs) + * are a materially different design; until one is chosen these are set through + * {@code codenameone_settings.properties}.

+ * + *

They are catalogued anyway because the drift gate needs them: a mined key + * that matches one of these patterns is accounted for rather than reported as + * an unknown hint.

+ */ +final class BuildHintsDynamic { + + private BuildHintsDynamic() { + } + + static void register(List h) { + family(h, "android.permission.*", "android", "AndroidGradleBuilder", + "true/false. Whether to include a particular permission. Preferred over " + + "android.xpermissions because it avoids conflicts with libraries. See " + + "Android's Manifest.permission documentation for the full list. The " + + "optional .maxSdkVersion suffix becomes the maxSdkVersion attribute of " + + "the generated tag, and .required marks the " + + "permission required."); + family(h, "android.uses_feature.*", "android", "AndroidGradleBuilder", + "Adds a element named by the suffix."); + family(h, "android.uses_permission.*", "android", "AndroidGradleBuilder", + "Adds a element named by the suffix."); + family(h, "android.playService.*", "android", "AndroidGradleBuilder", + "Opts a single Google Play service in or out. The sibling " + + ".minPlayServicesVersion pins its version."); + family(h, "android.cusom_layout*", "android", "AndroidGradleBuilder", + "Numbered custom layout resources: android.cusom_layout1, android.cusom_layout2 " + + "and upward. The misspelling is load-bearing: it's the key the " + + "builder actually reads, so correcting it drops the layout with " + + "no warning."); + family(h, "ios.NS*UsageDescription", "ios", "IPhoneBuilder", + "Info.plist privacy strings. The commonly used keys are catalogued " + + "individually and exposed through @IosPrivacy; this entry covers the " + + "open tail that the builder sweeps by prefix."); + family(h, "ios.entitlements.*", "ios", "IPhoneBuilder", + "Adds an arbitrary entitlement key to the generated entitlements file."); + family(h, "ios.spm.products.*", "ios", "IPhoneBuilder", + "Selects which products of a Swift Package Manager package to link, keyed " + + "by package identity."); + family(h, "ios.pods.build.*", "ios", "IPhoneBuilder", + "Overrides an Xcode build setting for the generated CocoaPods project."); + family(h, "ios.home.commissioning.buildSettings.*", "ios", "IPhoneBuilder", + "Overrides an Xcode build setting for the Matter commissioning extension."); + family(h, "ios.surfaces.buildSettings.*", "ios", "IPhoneBuilder", + "Overrides an Xcode build setting for the external-surfaces extension."); + family(h, "ios.*.appext.*", "ios", "IPhoneBuilder", + "Per-app-extension signing. ios.debug.appext..* and " + + "ios.release.appext..* are collapsed to unqualified keys before " + + "the request is sent."); + family(h, "harden.*.enabled", "general", "Executor", + "Enables or disables hardening for one platform slice."); + family(h, "harden.*", "general", "Executor", + "The whole hardening namespace is swept into the hardening engine's " + + "configuration, so a hint added there reaches it without a dedicated " + + "reader."); + family(h, "macNative.provisioningProfile.*", "mac", "MacNativeBuilder", + "Per-profile provisioning data for a native macOS build, keyed by profile " + + "name."); + family(h, "var.*", "general", "BuildRequest", + "Defines a variable that any other hint can interpolate as ${var.name}, " + + "with ${var.name:default} for a fallback."); + } + + private static void family(List h, String pattern, String platform, + String consumer, String doc) { + h.add(new Hint(pattern) + .group(HintGroup.NONE) + .type(HintType.STRING) + .dynamic(pattern) + .platform(platform) + .consumedBy(consumer) + .doc(doc)); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsExternal.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsExternal.java new file mode 100644 index 00000000000..3cdc2f5a517 --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsExternal.java @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * Hints the developer guide documents that nothing in this repository reads. + * + *

Most are consumed by build-daemon lanes whose source is not mirrored here, + * so having no in-repo consumer is not evidence that a hint is dead. A few are + * probably genuinely obsolete. Recording the distinction as + * {@link Hint#isExternal()} keeps both the drift gate and the Settings tool + * honest: the gate does not demand a consumer for these, and the tool still + * offers them for editing.

+ * + *

They are deliberately not annotated. Exposing a hint as a typed attribute + * is a promise that setting it does something, and for these that promise + * cannot be checked from this repository.

+ */ +final class BuildHintsExternal { + + private BuildHintsExternal() { + } + + static void register(List h) { + h.add(new Hint("android.fridaDebugLogging") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .external() + .doc("Boolean true/false defaults to false. If true, it will add verbose debug logs during " + + "frida detection to show which check if fails on.")); + + h.add(new Hint("android.fridaVersion") + .group(HintGroup.ANDROID) + .type(HintType.STRING) + .platform("android") + .external() + .doc("x.y.z The version of [frida-blocker](https://github.com/shannah/frida-blocker) to use to " + + "perform frida detection. This is only relevant if `android.fridaDetection=true`. If " + + "omitted, it will use the latest tested version in the build server.")); + + h.add(new Hint("android.signingV1") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .external() + .doc("true/false Default true. See " + + "https://source.android.com/docs/security/features/apksigning")); + + h.add(new Hint("android.signingV2") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .external() + .doc("true/false Default true. See " + + "https://source.android.com/docs/security/features/apksigning")); + + h.add(new Hint("android.signingV3") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .external() + .doc("true/false Default true. See " + + "https://source.android.com/docs/security/features/apksigning")); + + h.add(new Hint("android.signingV4") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .external() + .doc("true/false Default true. See " + + "https://source.android.com/docs/security/features/apksigning")); + + h.add(new Hint("android.supportV4") + .group(HintGroup.ANDROID) + .type(HintType.BOOLEAN) + .platform("android") + .external() + .doc("Boolean true/false defaults to false but that can change based on usage (for example, " + + "push implicitly activates this). Indicates whether the android support v4 library should " + + "be included in the build")); + + h.add(new Hint("block_server_registration") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .platform("general") + .external() + .doc("true/false flag defaults to false. By default Codename One applications register with " + + "the Codename One server. Setting this to true blocks them from sending information to " + + "the Codename One cloud, which is kept for statistical purposes and may be used to " + + "provide more installation stats in the future.")); + + h.add(new Hint("build.cn1Version") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .external() + .doc("Pro/Enterprise only. Pins the cloud build to a specific released Codename One version " + + "using the Maven release scheme (for example `7.0.182`), or to `master` to build against " + + "the current development head. The build server fetches that version's framework " + + "artifacts. Pro accounts can target versions published within the last two months; " + + "Enterprise within the last six months. Requesting an older version, a version that was " + + "never published, or using this hint without a Pro/Enterprise subscription fails the " + + "build with an explanatory error. See Versioned builds.")); + + h.add(new Hint("codename1.mac.appid") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .external() + .doc("Mac Native cloud builds only. The Mac bundle identifier registered in App Store Connect " + + "/ Apple Developer. Distinct from `codename1.ios.appid` because Apple treats the iOS and " + + "Mac App Store records as separate products. Required for cloud Mac builds.")); + + h.add(new Hint("codename1.mac.certificate") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .external() + .doc("Mac Native cloud builds only. Path to the `.p12` file containing the Mac signing " + + "certificate(s) — _Mac App Distribution_ (3rd Party Mac Developer Application) for App " + + "Store builds, _Developer ID Application_ for Developer ID builds, or both bundled into " + + "the same P12 when `macNative.distribution=both`. Not interchangeable with the iOS " + + "distribution certificate. Required for cloud Mac builds.")); + + h.add(new Hint("codename1.mac.certificatePassword") + .group(HintGroup.GENERAL) + .type(HintType.SECRET) + .platform("general") + .external() + .doc("Mac Native cloud builds only. Password to unlock the P12 referenced by " + + "`codename1.mac.certificate`. Required for cloud Mac builds.")); + + h.add(new Hint("codename1.mac.provision") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .external() + .doc("Mac Native cloud builds only. Path to the Mac provisioning profile " + + "(`.provisionprofile`). Apple issues distinct provisioning profiles for Mac App Store and " + + "Developer ID distribution — pass the one that matches the chosen channel.")); + + h.add(new Hint("desktop.fontSizes") + .group(HintGroup.DESKTOP) + .type(HintType.STRING) + .platform("desktop") + .external() + .doc("Indicates the sizes in pixels for the system fonts as a comma delimited string " + + "containing 3 numbers for small,medium,large fonts.")); + + h.add(new Hint("desktop.mac.cef") + .group(HintGroup.DESKTOP) + .type(HintType.BOOLEAN) + .platform("mac") + .external() + .doc("Whetherto use CEF for media or BrowserComponent instead of JavaFX in Mac desktop builds. " + + "true/false. Default value is `false` (Jan 2021), but this will be changed to `true` in a " + + "future version.")); + + h.add(new Hint("desktop.theme") + .group(HintGroup.DESKTOP) + .type(HintType.STRING) + .platform("desktop") + .external() + .doc("Name of the theme res file (without the \".res\" extension) to use as the \"native\" theme. " + + "By default this is native indicating iOS theme on Mac and Windows Metro on Windows. If " + + "its something else then the app will try to load the file /themeName.res (placed in " + + "native/Java SE directory).")); + + h.add(new Hint("desktop.themeMac") + .group(HintGroup.DESKTOP) + .type(HintType.STRING) + .platform("desktop") + .external() + .doc("Same as `desktop.theme` but specific to macOS")); + + h.add(new Hint("desktop.themeWin") + .group(HintGroup.DESKTOP) + .type(HintType.STRING) + .platform("desktop") + .external() + .doc("Same as `desktop.theme` but specific to Windows")); + + h.add(new Hint("desktop.win.cef") + .group(HintGroup.DESKTOP) + .type(HintType.BOOLEAN) + .platform("desktop") + .external() + .doc("Whether to use CEF for media and BrowserComponent instead of JavaFX in windows desktop " + + "builds. true/false. Default value is `false` (Jan 2021), but this will be changed to " + + "`true` in a future version.")); + + h.add(new Hint("desktop.windowsOutput") + .group(HintGroup.DESKTOP) + .type(HintType.STRING) + .platform("desktop") + .external() + .doc("Can be exe or msi depending on desired results")); + + h.add(new Hint("ios.NSXXXUsageDescription") + .group(HintGroup.IOS_PRIVACY) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("iOS privacy flags for using certain APIs. Starting with Xcode 8, you're required to add " + + "usage description strings for certain APIs. Find a full list of the available keys in " + + "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html[Apple's " + + "docs]. Some relevant ones include `ios.NSCameraUsageDescription`, " + + "`ios.NSContactsUsageDescription`, `ios.NSLocationAlwaysUsageDescription`, " + + "`NSLocationUsageDescription`, `ios.NSMicrophoneUsageDescription`, " + + "`ios.NSPhotoLibraryAddUsageDescription`, `ios.NSSpeechRecognitionUsageDescription`, " + + "`ios.NSSiriUsageDescription`")); + + h.add(new Hint("ios.appext.NAME.provisioningURL") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Cloud device builds only. URL of the provisioning profile for a generic app extension " + + "dropped into `ios/app_extensions/NAME/` (or a generated extension such as `CN1Widgets`), " + + "used when the extension folder doesn't bundle a `.mobileprovision` itself. The profile " + + "is installed on the build machine and added to the export options per bundle id. Used " + + "for both debug and release builds unless a qualified variant (below) is set. An " + + "extension is signed against its own App ID, so a device build with no profile for it -- " + + "by any of the three carriers -- is refused unless the app's own profile is a wildcard " + + "that covers the extension's bundle id.")); + + h.add(new Hint("ios.application_exits") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .platform("ios") + .external() + .doc("true/false (defaults to false). Indicates whether the application should exit on home " + + "button press. The default is to exit, leaving the application running is only tested at " + + "the moment.")); + + h.add(new Hint("ios.debug.archs") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Can be set to \"armv7\" to force iOS debug builds to be 32 bit. By default, debug builds " + + "are 64 bit only.")); + + h.add(new Hint("ios.debug.distributionMethod") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Specifies distribution type for debug iOS builds only. This is used for enterprise or " + + "ad-hoc builds (using values \"enterprise\" and \"ad-hoc\" respectively).")); + + h.add(new Hint("ios.distributionMethod") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Specifies distribution type for debug iOS builds. This is used for enterprise or ad-hoc " + + "builds (using values \"enterprise\" and \"ad-hoc\" respectively).")); + + h.add(new Hint("ios.entitlementsInject") + .group(HintGroup.IOS) + .type(HintType.XML) + .separator("") + .platform("ios") + .external() + .doc("Content to inject into the iOS entitlements file. This should be in the Plist XML " + + "format. See " + + "https://developer.apple.com/documentation/bundleresources/entitlements?language=objc[Apple " + + "Entitlements Documentation].")); + + h.add(new Hint("ios.keychainAccessGroup") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Space-delimited list of keychain access groups that this app has access to as described " + + "in " + + "https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html#//apple_ref/doc/uid/TP30000897-CH204-SW11[Apple's " + + "documentation]. These are added to the entitlements file with the key " + + "`keychain-access-groups`.")); + + h.add(new Hint("ios.newPipeline") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .platform("ios") + .external() + .doc("Boolean true/false defaults to true. Allows toggling the OpenGL ES 2.0 drawing pipeline " + + "off to the older OGL ES 1.0 pipeline.")); + + h.add(new Hint("ios.release.archs") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Can be set to \"arm64\" to only build iOS release builds for 64 bit. By default, release " + + "builds are both 32 and 64 bit.")); + + h.add(new Hint("ios.release.distributionMethod") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("Specifies distribution type for release iOS builds only. This is used for enterprise or " + + "ad-hoc builds (using values \"enterprise\" and \"ad-hoc\" respectively).")); + + h.add(new Hint("ios.rpmalloc") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("`true`/`false` Use https://github.com/rampantpixels/rpmalloc[rpmalloc] instead of " + + "malloc/free for memory allocation in ParparVM. This will cause the deployment target to " + + "be changed to a minimum of iOS 8.0.")); + + h.add(new Hint("ios.statusbar_hidden") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .platform("ios") + .external() + .doc("true/false defaults to false. Hides the iOS status bar if set to true.")); + + h.add(new Hint("ios.testFlight") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .platform("ios") + .external() + .doc("Boolean true/false defaults to false and works only for pro accounts. Enables the " + + "testflight support in the release binaries for easy beta testing. Notice that the IDE " + + "plugin has a \"Test Flight\" check box you *should* use under the iOS section.")); + + h.add(new Hint("ios.xcode_version") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .external() + .doc("The version of Xcode used on the server. Defaults to 4.5; accepts 5.0 as an option and " + + "nothing else.")); + + h.add(new Hint("javascript.inject.afterHead") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .external() + .doc("Content to be injected into the index.html file at the end of the `` tag.")); + + h.add(new Hint("javascript.inject.beforeHead") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .external() + .doc("Content to be injected into the index.html file at the beginning of the `` tag.")); + + h.add(new Hint("javascript.minifying") + .group(HintGroup.JAVASCRIPT) + .type(HintType.BOOLEAN) + .platform("javascript") + .external() + .doc("true/false (defaults to `true`). By default the JavaScript code is minified to reduce " + + "file size. You may optionally disable minification by setting `javascript.minifying` to " + + "`false`.")); + + h.add(new Hint("javascript.port") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .external() + .doc("`parparvm` (default) or `teavm`. Selects the public JavaScript compiler for cloud " + + "builds. `teavm` retains the original builder as a compatibility fallback.")); + + h.add(new Hint("javascript.sourceFilesCopied") + .group(HintGroup.JAVASCRIPT) + .type(HintType.BOOLEAN) + .platform("javascript") + .external() + .doc("true/false (defaults to `false`). Setting this flag to `true` will cause available java " + + "source files to be included in the resulting .zip and .war files. These may be used by " + + "Chrome during debugging.")); + + h.add(new Hint("javascript.stopOnErrors") + .group(HintGroup.JAVASCRIPT) + .type(HintType.BOOLEAN) + .platform("javascript") + .external() + .doc("true/false (defaults to `true`). Causes a TeaVM JavaScript build to fail when the " + + "compiler reports warnings. Setting this to `false` may allow the fallback builder to " + + "complete, but can turn compiler diagnostics into runtime failures that are more " + + "difficult to debug.")); + + h.add(new Hint("javascript.teavm.version") + .group(HintGroup.JAVASCRIPT) + .type(HintType.STRING) + .platform("javascript") + .external() + .doc("(Optional) The version of TeaVM to use for the build. *Use caution*, only use this " + + "property if you know what you're doing!")); + + h.add(new Hint("mac.desktop-vm") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .external() + .doc("The JVM the should be bundled with Mac desktop build. Mac desktop builds only. Supported " + + "values: zuluFx8, zulu11, zuluFx11")); + + h.add(new Hint("macNative.entitlements.allowJit") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. `true` enables `com.apple.security.cs.allow-jit` for hardened " + + "runtime. ParparVM is AOT-compiled so this is `false` by default; flip when bundling a " + + "JIT-using cn1lib.")); + + h.add(new Hint("macNative.entitlements.appSandbox") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. `true` enables `com.apple.security.app-sandbox`. Default is " + + "`true` for the `appStore` channel (Mac App Store requires the sandbox), `false` for " + + "`developerID`.")); + + h.add(new Hint("macNative.entitlements.hardenedRuntime") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. `true` enables hardened runtime restrictions. Default is `true` " + + "for `developerID` (notarization requires it), `false` for `appStore`.")); + + h.add(new Hint("macNative.entitlements.network.client") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. Toggles `com.apple.security.network.client`. Default `true`.")); + + h.add(new Hint("macNative.entitlements.network.server") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. Toggles `com.apple.security.network.server`. Default `false`.")); + + h.add(new Hint("macNative.provisioningProfile.appStore") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. Provisioning profile name for App Store distribution — used only " + + "when `macNative.signing.style=manual`.")); + + h.add(new Hint("macNative.provisioningProfile.developerID") + .group(HintGroup.MAC_NATIVE) + .type(HintType.STRING) + .platform("mac") + .external() + .doc("Mac Native builds only. Provisioning profile name for Developer ID distribution — used " + + "only when `macNative.signing.style=manual`.")); + + h.add(new Hint("win.desktop-vm") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("windows") + .external() + .doc("The JVM that should be bundled in the Windows desktop build. Windows desktop builds " + + "only. Supported values: zulu8, zuluFx8, zulu8-32bit, zuluFx8-32bit, zulu11, zuluFx11, " + + "zulu11-32bit, zuluFx11-32bit")); + + h.add(new Hint("win.installDirName") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("windows") + .external() + .doc("Windows desktop builds only. Overrides the default installation folder name suggested by " + + "the installer (under `Program Files`). Defaults to the application's main class name for " + + "backward compatibility. Use this build hint to set a user-friendly installation folder " + + "name (for example, `win.installDirName=My Application`). The application ID used by " + + "Windows for upgrade detection is unaffected, so existing installations continue to " + + "upgrade.")); + + h.add(new Hint("win.shortcutName") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("windows") + .external() + .doc("Windows desktop builds only. Overrides the name used for the Start Menu shortcut, the " + + "Desktop shortcut and (when `win.launchOnStart=true`) the autostart shortcut. Defaults to " + + "the application's main class name for backward compatibility. Use this build hint to set " + + "a user-friendly shortcut label (for example, `win.shortcutName=My Application`).")); + + h.add(new Hint("win.vm32bit") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .platform("windows") + .external() + .doc("true/false (defaults to false). Forces windows desktop builds to use the Win32 JVM " + + "instead of the 64 bit VM making them compatible with older Windows Machines. This is off " + + "by default at the moment because of a bug in JDK 8 update 112 that might cause this to " + + "fail for some cases")); + + h.add(new Hint("windows.extensions") + .group(HintGroup.WINDOWS) + .type(HintType.STRING) + .platform("windows") + .external() + .doc("Historical build hint for the discontinued UWP target. It's retained here only for " + + "legacy reference and isn't used by current supported build targets.")); + + h.add(new Hint("xxx.minPlayServicesVersion") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .external() + .doc("This is a special case build hint. You can use any prefix to the build hint and the " + + "convention is to use your cn1lib name. It's identical to " + + "`android.minPlayServicesVersion` with the exception that the \"highest version wins.\" " + + "That way if your cn1lib requires play services 9+ and uses: " + + "`myLib.minPlayServicesVersion=9.0.0` and another library has " + + "`otherLib.minPlayServicesVersion=10.0.0` then play services will be 10.0.0")); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsGeneral.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsGeneral.java new file mode 100644 index 00000000000..c96693cc6cc --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsGeneral.java @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * Hints with no platform prefix, plus hardening and on-device debugging. + * + *

Seeded by mining every {@code getArg} call site in the builders, so the + * name and the default match what the build actually reads. Curated entries + * carry an annotation attribute and, where the domain is provably closed, an + * enum; the rest are described but set through + * {@code codenameone_settings.properties}.

+ * + *

Split out of {@link BuildHints} because a single class initializer + * holding every entry would exceed the JVM's 64KB per-method limit.

+ */ +final class BuildHintsGeneral { + + private BuildHintsGeneral() { + } + + static void register(List h) { + h.add(new Hint("KeepScreenOn") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("android.onDeviceDebug") + .annotatedAs(HintGroup.ON_DEVICE_DEBUG, "android") + .type(HintType.BOOLEAN) + .def("false") + .platform("android") + .consumedBy("AndroidGradleBuilder", "CN1BuildMojo") + .doc("Boolean true/false defaults to false. When `true`, the generated `AndroidManifest.xml` " + + "is marked `android:debuggable=\"true\"`, R8/proguard is disabled, and the build is pinned " + + "to debug-only (`android.release` is forced off and `android.debug` is forced on) so a " + + "stray hint can't ship a release-signed APK that's `debuggable=\"true\"`. Pair with the " + + "`cn1:android-on-device-debugging` Maven goal (or the bundled IntelliJ run configs) to " + + "install, launch, forward JDWP, and stream logcat through adb. Has no effect on builds " + + "that don't carry it — release builds are unaffected. See the On-Device Debugging " + + "(Android) chapter for the full flow.")); + + h.add(new Hint("androidx.appcompat.version") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("build.incSources") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("CN1BuildMojo")); + + h.add(new Hint("build.testReporter") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("build.unitTest") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("CN1BuildMojo")); + + h.add(new Hint("cn1.androidTheme") + .aliasOf("and.themeMode") + .deprecated("Use and.themeMode, or @Android(themeMode = ...).") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder") + .doc("Deprecated alias for and.themeMode (AndroidGradleBuilder.java:4097). " + + "Both names configure one setting, so declaring this alongside " + + "@Android(themeMode) is a conflict.")); + + h.add(new Hint("cn1.buildKey") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("cn1.entitled") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("true") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("cn1.harden.forceOff") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("cn1.hardenLevel") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .def("off") + .platform("general") + .consumedBy("AndroidGradleBuilder", "Executor")); + + h.add(new Hint("cn1.hardened") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("AndroidGradleBuilder", "Executor")); + + h.add(new Hint("cn1.hardening.libraryJars") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("cn1.mappingId") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("cn1.nativeTheme") + .aliasOf("nativeTheme") + .deprecated("Use nativeTheme, or @Build(nativeTheme = ...).") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder") + .doc("Deprecated alias for nativeTheme (AndroidGradleBuilder.java:4099, " + + "IPhoneBuilder.java:947). Both names configure one setting, so " + + "declaring this alongside @Build(nativeTheme) is a conflict.")); + + h.add(new Hint("db.legacy") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor", "GenerateDesktopAppWrapperMojo")); + + h.add(new Hint("delayPushCompletion") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder")); + + // NO default, whatever the literal at the call site says. Both builders + // decide whether Facebook support is in the app at all by asking whether + // this hint is null, so the 706695982682332 further down is a fallback + // reached only once the feature is already on -- never a value the build + // uses by default. Recording it made Add enable Facebook integration + // against an unrelated shared app ID the moment the row was clicked. + h.add(new Hint("facebook.appId") + .annotatedAs(HintGroup.GENERAL, "facebookAppId") + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder") + .doc("The application ID for an app that requires native Facebook login integration, this " + + "defaults to null which means native Facebook support shouldn't be in the app")); + + h.add(new Hint("facebook.clientToken") + .group(HintGroup.GENERAL) + .type(HintType.SECRET) + .platform("general") + .consumedBy("AndroidGradleBuilder") + .doc("The client token for an app that requires native Facebook login integration, this is " + + "required if the facebook.appId is set.")); + + h.add(new Hint("gcm.sender_id") + .annotatedAs(HintGroup.GENERAL, "gcmSenderId") + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder") + .doc("The Android/chrome push identifier, see the push section for more details")); + + h.add(new Hint("google.adUnitId") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder") + .doc("Allows integrating Admob/Google Play ads into the application see " + + "link:https://www.codenameone.com/blog/adding-google-play-ads.html[this]")); + + h.add(new Hint("gradleDependencies") + .group(HintGroup.GENERAL) + .type(HintType.STRING_LIST) + .separator("\n") + .platform("general") + .consumedBy("AndroidGradleBuilder", "MapsProviderInjector")); + + h.add(new Hint("harden.allowUnhardenedLocalBuild") + .annotatedAs(HintGroup.HARDENING, "allowUnhardenedLocalBuild") + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("CN1BuildMojo") + .doc("Permits a local or source build to run with hardening requested but not applied. Without " + + "it such a build is refused, so a hardened app is never shipped from a target that " + + "can't actually harden it.")); + + h.add(new Hint("harden.controlFlow") + .annotatedAs(HintGroup.HARDENING, "controlFlow") + .values("HardenControlFlow", "off", "on") + .platform("general") + .consumedBy("CN1BuildMojo") + .doc("Overrides control-flow obfuscation independently of harden.level.")); + + h.add(new Hint("harden.ios.enabled") + .group(HintGroup.HARDENING) + .type(HintType.BOOLEAN) + .def("true") + .platform("general") + .consumedBy("CN1BuildMojo")); + + h.add(new Hint("harden.keep") + .annotatedAs(HintGroup.HARDENING, "keep") + .type(HintType.TEXT_BLOCK) + .platform("general") + .consumedBy("AndroidGradleBuilder") + .doc("Keep rules in ProGuard syntax, one per line, for classes that are resolved by name at " + + "runtime and so can't be found by the automatic analysis. Same syntax as " + + "android.proguardKeep, so existing rules port directly. Rules are separated by newlines " + + "only, because a semicolon is legal inside a rule body such as { *; }.")); + + h.add(new Hint("harden.level") + .annotatedAs(HintGroup.HARDENING, "level") + .values("HardenLevel", "off", "standard", "aggressive", "paranoid") + .def("off") + .platform("general") + .consumedBy("AndroidGradleBuilder", "CN1BuildMojo", "Executor") + .doc("Master switch for app hardening: off, standard, aggressive or paranoid. An unrecognized " + + "value fails the build rather than being treated as off.")); + + h.add(new Hint("harden.mac.enabled") + .group(HintGroup.HARDENING) + .type(HintType.BOOLEAN) + .def("true") + .platform("general") + .consumedBy("CN1BuildMojo")); + + h.add(new Hint("harden.rename") + .annotatedAs(HintGroup.HARDENING, "rename") + .type(HintType.BOOLEAN) + .platform("general") + .consumedBy("CN1BuildMojo") + .doc("Overrides symbol renaming independently of harden.level.")); + + h.add(new Hint("harden.strings") + .annotatedAs(HintGroup.HARDENING, "strings") + .values("HardenStrings", "off", "constants", "all") + .platform("general") + .consumedBy("CN1BuildMojo") + .doc("Overrides string obfuscation independently of harden.level: off, constants or all.")); + + h.add(new Hint("harden.tv.enabled") + .group(HintGroup.HARDENING) + .type(HintType.BOOLEAN) + .def("true") + .platform("general") + .consumedBy("CN1BuildMojo")); + + h.add(new Hint("harden.watch.enabled") + .group(HintGroup.HARDENING) + .type(HintType.BOOLEAN) + .def("true") + .platform("general") + .consumedBy("CN1BuildMojo")); + + h.add(new Hint("ios.onDeviceDebug") + .annotatedAs(HintGroup.ON_DEVICE_DEBUG, "ios") + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. When `true`, the iOS build links a small JDWP " + + "listener thread (`cn1_debugger`) into the binary and the ParparVM translator emits " + + "source-line and locals metadata so a desktop proxy can serve the running app to any " + + "JDWP-speaking debugger. Has no effect on release builds. See the On-Device Debugging " + + "(iOS) chapter for the full flow.")); + + h.add(new Hint("ios.onDeviceDebug.proxyHost") + .annotatedAs(HintGroup.ON_DEVICE_DEBUG, "iosProxyHost") + .type(HintType.STRING) + .def("127.0.0.1") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Hostname or IP address the device-side listener dials to reach the desktop proxy. " + + "Default `127.0.0.1` (correct for the native iOS simulator). For a physical device, set " + + "this to the developer laptop's LAN IP. Has no effect unless `ios.onDeviceDebug=true`.")); + + h.add(new Hint("ios.onDeviceDebug.proxyPort") + .annotatedAs(HintGroup.ON_DEVICE_DEBUG, "iosProxyPort") + .type(HintType.INT) + .def("55333") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("TCP port on `ios.onDeviceDebug.proxyHost` where the proxy is listening for the device. " + + "Default `55333`. Has no effect unless `ios.onDeviceDebug=true`.")); + + h.add(new Hint("ios.onDeviceDebug.waitForAttach") + .annotatedAs(HintGroup.ON_DEVICE_DEBUG, "iosWaitForAttach") + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. When `true`, the app blocks at startup until the " + + "proxy connects and the IDE tells the VM to continue. Useful when the breakpoint to " + + "investigate fires during app boot. Has no effect unless `ios.onDeviceDebug=true`.")); + + h.add(new Hint("java.version") + .group(HintGroup.GENERAL) + .type(HintType.INT) + .def("8") + .platform("general") + .consumedBy("AndroidGradleBuilder", "CN1BuildMojo", "CreateGameSceneMojo", "InstallCn1libsMojo", "OpenGameBuilderMojo") + .doc("Valid values include 5 or 8. Indicates the JVM version that should be used for server " + + "compilation, this is defined by default for newly created apps based on the Java 8 mode " + + "selection")); + + h.add(new Hint("maps.provider") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("MapsProviderInjector") + .doc("Selects the native map provider. `android.maps.provider` and " + + "`ios.maps.provider` override it for one platform.")); + + h.add(new Hint("nativeVerify") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("IPhoneBuilder", "LinuxNativeBuilder", "WindowsNativeBuilder") + .doc("`strict` or `warn` turns on ParparVM's native signature check for this build; " + + "anything else leaves it off, which is the default. ParparVM encodes the whole " + + "Java signature in the C function name, so a native spelled even slightly " + + "differently never reaches the linker as an error: the correctly named symbol " + + "is simply absent, " + + "the dead-code pass reads that as unused, and the feature ships inert. " + + "`ios.nativeVerify`, `linux.nativeVerify` and `windows.nativeVerify` override " + + "it for one platform.")); + + h.add(new Hint("nativeTheme") + .annotatedAs(HintGroup.GENERAL, "nativeTheme") + .values("NativeThemeMode", "modern", "legacy", "custom") + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder") + .doc("`modern`, `legacy`, `custom` (default unset). Cross-platform override that sets both " + + "`ios.themeMode` and `and.themeMode` together when those aren't set explicitly. `modern` " + + "= liquid glass + Material 3, `legacy` = iOS 7 flat + Holo Light, `custom` disables the " + + "framework native theme entirely. The legacy alias `cn1.nativeTheme` is still accepted.")); + + h.add(new Hint("noExtraResources") + .annotatedAs(HintGroup.GENERAL, "noExtraResources") + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder") + .doc("true/false (defaults to false). Blocks codename one from injecting its own resources " + + "when set to true, the only effect this has is in slightly reducing archive size. This " + + "might have adverse effects on some features of Codename One so it isn't recommended.")); + + h.add(new Hint("requireKotlinStdlib") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder")); + + h.add(new Hint("tvMain") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("IPhoneBuilder", "TvNativeBuilder")); + + h.add(new Hint("vserv.allowSkipping") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("true") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.category") + .group(HintGroup.GENERAL) + .type(HintType.INT) + .def("29") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.countryCode") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .def("null") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.locale") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .def("en_US") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.networkCode") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .def("null") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.scaleMode") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.transition") + .group(HintGroup.GENERAL) + .type(HintType.INT) + .def("300000") + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("vserv.zone") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("Executor")); + + h.add(new Hint("watchMain") + .group(HintGroup.GENERAL) + .type(HintType.STRING) + .platform("general") + .consumedBy("AndroidGradleBuilder", "IPhoneBuilder", "WatchNativeBuilder")); + + h.add(new Hint("watchStandalone") + .group(HintGroup.GENERAL) + .type(HintType.BOOLEAN) + .def("false") + .platform("general") + .consumedBy("AndroidGradleBuilder", "WatchNativeBuilder")); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsIos.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsIos.java new file mode 100644 index 00000000000..feab38a974f --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintsIos.java @@ -0,0 +1,1363 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * iOS build hints, including the Info.plist privacy strings. + * + *

Seeded by mining every {@code getArg} call site in the builders, so the + * name and the default match what the build actually reads. Curated entries + * carry an annotation attribute and, where the domain is provably closed, an + * enum; the rest are described but set through + * {@code codenameone_settings.properties}.

+ * + *

Split out of {@link BuildHints} because a single class initializer + * holding every entry would exceed the JVM's 64KB per-method limit.

+ */ +final class BuildHintsIos { + + private BuildHintsIos() { + } + + static void register(List h) { + h.add(new Hint("ios.NFCReaderUsageDescription") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSBonjourServices") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSCalendarsFullAccessUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "calendarsFullAccessUsageDescription") + .type(HintType.STRING) + .def("This app uses your calendars to read and schedule events.") + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder")); + + h.add(new Hint("ios.NSCalendarsUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "calendarsUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder")); + + h.add(new Hint("ios.NSCalendarsWriteOnlyAccessUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "calendarsWriteOnlyAccessUsageDescription") + .type(HintType.STRING) + .def("This app uses your calendar to schedule events.") + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder")); + + h.add(new Hint("ios.NSBluetoothAlwaysUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "bluetoothAlwaysUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Why the app uses Bluetooth. Supplied automatically when the app references " + + "`com.codename1.bluetooth`; set it to say something more specific than " + + "the default.")); + + h.add(new Hint("ios.NSBluetoothPeripheralUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "bluetoothPeripheralUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("The pre-iOS 13 spelling of the Bluetooth usage description, supplied and " + + "overridable on the same terms.")); + + h.add(new Hint("ios.NSCameraUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "cameraUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("ios.NSNearbyInteractionAllowOnceUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "nearbyInteractionAllowOnceUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("The pre-iOS 16 spelling of the nearby-interaction usage description, " + + "supplied automatically when the app references the nearby APIs.")); + + h.add(new Hint("ios.NSNearbyInteractionUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "nearbyInteractionUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Why the app measures distance and direction to nearby devices. Supplied " + + "automatically when the app references the nearby APIs; set it to say " + + "something more specific than the default.")); + + h.add(new Hint("ios.NSSpeechRecognitionUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "speechRecognitionUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Why the app sends speech for recognition. Supplied automatically when the " + + "app references the speech APIs; set it to say something more specific.")); + + h.add(new Hint("ios.NSHealthShareUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "healthShareUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSHealthUpdateUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "healthUpdateUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSLocalNetworkUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "localNetworkUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSLocationAlwaysAndWhenInUseUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "locationAlwaysAndWhenInUseUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSLocationAlwaysUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "locationAlwaysUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSLocationWhenInUseUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "locationWhenInUseUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.NSMicrophoneUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "microphoneUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("MacNativeBuilder")); + + h.add(new Hint("ios.NSRemindersFullAccessUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "remindersFullAccessUsageDescription") + .type(HintType.STRING) + .def("This app uses your reminders to read and schedule tasks.") + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder")); + + h.add(new Hint("ios.NSRemindersUsageDescription") + .annotatedAs(HintGroup.IOS_PRIVACY, "remindersUsageDescription") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder")); + + h.add(new Hint("ios.UIRequiredDeviceCapabilities") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.actionSheetStyle") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.add_libs") + .annotatedAs(HintGroup.IOS, "addLibs") + .type(HintType.STRING_LIST) + .separator(";") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("A semicolon separated list of libraries that should be linked to the app to build it")); + + h.add(new Hint("ios.afterFinishLaunching") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Objective-C code that can be injected into the iOS app delegate at the bottom of the " + + "body of the didFinishLaunchingWithOptions callback method")); + + h.add(new Hint("ios.appAttest") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.appAttest.environment") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.appUsesNonExemptEncryption") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.app_groups") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Space-delimited list of app groups that this app belongs to as described in " + + "https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW19[Apple's " + + "documentation]. These are added to the entitlements file with key " + + "`com.apple.security.application-groups`.")); + + h.add(new Hint("ios.applicationDidEnterBackground") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Objective-C code that can be injected into the iOS callback method (message) " + + "`applicationDidEnterBackground`.")); + + h.add(new Hint("ios.applicationQueriesSchemes") + .annotatedAs(HintGroup.IOS, "applicationQueriesSchemes") + .type(HintType.STRING_LIST) + .separator(",") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Comma separated list of url schemes that `canExecute` will respect on iOS. If the url " + + "scheme isn't mentioned here `canExecute` will return false starting with iOS 9. Notice " + + "that this collides with `ios.plistInject` when used with the " + + "`LSApplicationQueriesSchemes...` value so you should use one or the other. " + + "For example, to enable `canExecute` for a url like `myurl://xys` you can use: " + + "`myurl,myotherurl`")); + + h.add(new Hint("ios.associatedDomains") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Comma-delimited list of domains associated with this app. Each domain should be prefixed " + + "by a supported prefix. For example, \"applinks:\" or \"webcredentials:.\" See " + + "https://developer.apple.com/documentation/security/password_autofill/setting_up_an_app_s_associated_domains?language=objc[Apple's " + + "documentation on Associated domains] for more information.")); + + h.add(new Hint("ios.backgroundProcessingIds") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.background_modes") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.beforeFinishLaunching") + .annotatedAs(HintGroup.IOS, "beforeFinishLaunching") + .type(HintType.TEXT_BLOCK) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Objective-C code that can be injected into the iOS app delegate at the top of the body " + + "of the didFinishLaunchingWithOptions callback method")); + + h.add(new Hint("ios.bitcode") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false defaults to false. Enables bitcode support for the build.")); + + h.add(new Hint("ios.blockScreenshotsOnEnterBackground") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false (defaults to false). Indicates that app should prevent iOS from taking " + + "screenshots when app enters background. Described " + + "https://shannah.github.io/cn1-recipes/#_hiding_sensitive_data_when_entering_background[here].")); + + h.add(new Hint("ios.bluetooth.background") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.buildType") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("debug") + .platform("ios") + .consumedBy("IPhoneBuilder", "WatchNativeBuilder")); + + h.add(new Hint("ios.bundleVersion") + .annotatedAs(HintGroup.IOS, "bundleVersion") + .type(HintType.VERSION) + .platform("ios") + .consumedBy("IPhoneBuilder", "WatchNativeBuilder") + .doc("Indicates the version number of the bundle, this is useful if you want to create a minor " + + "version number change for the beta testing support")); + + h.add(new Hint("ios.carplay.audio") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.carplay.messaging") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.carplay.navigation") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.carplay.poi") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.convertSignalsToExceptions") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.criticalAlerts") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.crypto.gcm") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.debug.teamId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder", "TvNativeBuilder", "WatchNativeBuilder") + .doc("Specifies the team ID associated with the iOS debug provisioning profile and " + + "certificate.")); + + h.add(new Hint("ios.delayPushCompletion") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.dependencyManager") + .annotatedAs(HintGroup.IOS, "dependencyManager") + .values("IosDependencyManager", "auto", "cocoapods", "spm", "both", "none") + .def("auto") + .platform("ios") + .consumedBy("IOSDependencyManager") + .doc("Which native dependency manager to use: auto picks one from whichever of ios.pods and " + + "ios.spm.packages is set, and cocoapods, spm or both require the matching hint to be set. " + + "An unrecognized value fails the build.")); + + h.add(new Hint("ios.deployment_target") + .annotatedAs(HintGroup.IOS, "deploymentTarget") + .type(HintType.VERSION) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Minimum iOS version the build targets. Set it to the lowest iOS you actually support; a " + + "higher value excludes older devices from the App Store listing.")); + + h.add(new Hint("ios.detectJailbreak") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false (defaults to false). When true, the iOS app will exit on launch if it detects " + + "that it's running on a jailbroken device.")); + + h.add(new Hint("ios.devLocale") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.disableScreenshots") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.enableAutoplayVideo") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. Makes videos \"autoplay\" when loaded on iOS")); + + h.add(new Hint("ios.enableBadgeClear") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to true. Clears the badge value with every load of the app, " + + "this is useful if the app doesn't manually keep track of number values for the badge")); + + h.add(new Hint("ios.enableGalleryMultiselect") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.enableStatusBar7") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer.applesignin") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer.healthkit") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer.homekit") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer.networking.HotspotConfiguration") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer.nfc.hce") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.entitlements.com.apple.developer.nfc.readersession.formats") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.facebook.usePods") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.facebook.version") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("~>5.6.0") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.facebook_permissions") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Permissions for Facebook used in the Android build target, applicable only if Facebook " + + "native integration is used.")); + + h.add(new Hint("ios.failOnWarning") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.fieldNullChecks") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.fileSharingEnabled") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.firebaseAnalytics") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.firebaseAnalyticsVersion") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.force64") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.generateSplashScreens") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. Enables legacy generation of splash screen images " + + "instead of the current launch storyboards.")); + + h.add(new Hint("ios.glAppDelegateBody") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Objective-C code that can be injected into the iOS app delegate within the body of the " + + "file before the end. This only makes sence for methods that aren't already declared in " + + "the class")); + + h.add(new Hint("ios.glAppDelegateHeader") + .annotatedAs(HintGroup.IOS, "glAppDelegateHeader") + .type(HintType.TEXT_BLOCK) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Objective-C code that can be injected into the iOS app delegate at the top of the file. " + + "For example, if you need to include headers or make special imports for other injected " + + "code")); + + h.add(new Hint("ios.googleAdUnitId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Allows integrating admob/google play ads, this is effectively identical to " + + "google.adUnitId but only applies to iOS")); + + h.add(new Hint("ios.googleAdUnitIdPadding") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Indicates the amount of padding to pass to the Google Ads placed at the bottom of the " + + "screen with `google.adUnitId`")); + + h.add(new Hint("ios.googleAdUnitTestDevice") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("97cfc76e5efbc6dfa7eb2e6857b613a0") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.gplus.clientId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.hceAids") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.headphoneCallback") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. When set to true it assumes the main class has two " + + "methods: `headphonesConnected` & `headphonesDisconnected` which it invokes appropriately " + + "as needed")); + + h.add(new Hint("ios.health.backgroundDelivery") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.health.recalibrateEstimates") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.health.required") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.home.appGroup") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.home.commissioning") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.home.commissioning.displayName") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.home.commissioning.fabric") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.home.commissioning.vendorId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("0xFFF1") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.home.required") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.includeNullChecks") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.includePush") + .annotatedAs(HintGroup.IOS, "includePush") + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false (defaults to false). Whether to include the push capabilities in the iOS " + + "build. Notice that the IDE plugin has an \"Include Push\" check box you *should* use under " + + "the iOS section.")); + + h.add(new Hint("ios.intents.appIntents") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.intents.minDeploymentTarget") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.interface_orientation") + .annotatedAs(HintGroup.IOS, "interfaceOrientation") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("UIInterfaceOrientationPortrait by default. Indicates the orientation, one or more of " + + "(separated by colon :): `UIInterfaceOrientationPortrait`, " + + "`UIInterfaceOrientationPortraitUpsideDown`, `UIInterfaceOrientationLandscapeLeft`, " + + "`UIInterfaceOrientationLandscapeRight`. Notice that the IDE plugin has an \"Interface " + + "Orientation\" combo box you *should* use under the iOS section.")); + + h.add(new Hint("ios.keyboardOpen") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Flips between iOS keyboard open mode and autofold keyboard mode. Defaults to true which " + + "means the keyboard will remain open and not fold automatically when editing moves to " + + "another field.")); + + h.add(new Hint("ios.launchPlaceholder") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.launchStoryboardName") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("LaunchScreen") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.locationUsageDescription") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder", "WatchNativeBuilder") + .doc("This flag is required for iOS 8 and newer if you're using the location API. It needs to " + + "include a description of the reason for which you need access to the users location")); + + h.add(new Hint("ios.lowMemCamera") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.maps.provider") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("MapsProviderInjector") + .doc("iOS's own native map provider, overriding `maps.provider`.")); + + h.add(new Hint("ios.metal") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to true. Selects the Metal rendering backend " + + "(`CAMetalLayer`) over the legacy OpenGL ES 2 path (`CAEAGLLayer`). Metal is the " + + "supported iOS graphics API; OpenGL ES is deprecated. Set to `false` to opt out if you " + + "hit a Metal-only rendering regression. See link:#_metal_renderer[Working with iOS / " + + "Metal renderer] for details.")); + + h.add(new Hint("ios.metal.colorSpace") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("sRGB") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Selects the `CAMetalLayer.colorspace` for the Metal renderer. Accepts `sRGB` (default), " + + "`displayP3`, `deviceRGB`, `linearSRGB`, `extendedSRGB`, `extendedLinearSRGB`, or `none`. " + + "Has no effect when `ios.metal=false`. See " + + "link:#_choosing_a_color_space_for_the_metal_renderer[Working with iOS / Choosing a color " + + "space] for the full table.")); + + h.add(new Hint("ios.minDeploymentTarget") + .annotatedAs(HintGroup.IOS, "minDeploymentTarget") + .type(HintType.VERSION) + .def("6.0") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("The null and empty-string reads of this hint are presence checks; 6.0 is the substantive " + + "default (IPhoneBuilder.java:4671).")); + + h.add(new Hint("ios.mopubAdSize") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("MOPUB_BANNER_SIZE") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.mopubId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.mopubTabletAdSize") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("MOPUB_LEADERBOARD_SIZE") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.mopubTabletId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.multitasking") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Set to true to enable iOS multitasking and split-screen support. This only works if " + + "`ios.xcode_verson=9.2`.")); + + h.add(new Hint("ios.nativeVerify") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("`nativeVerify` for the iOS translation alone.")); + + h.add(new Hint("ios.nearby.accessoryServices") + .group(HintGroup.IOS) + .type(HintType.STRING_LIST) + .separator(",") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Bluetooth service UUIDs published as `NSAccessorySetupBluetoothServices`, " + + "so AccessorySetupKit can show a picker for them. Unset publishes " + + "none.")); + + h.add(new Hint("ios.nearby.background") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Requests the nearby-interaction entitlement and the background mode that " + + "go with ranging while backgrounded. Off by default because the " + + "entitlement has to be on the provisioning profile, and requesting it " + + "without one fails signing for every ranging app.")); + + h.add(new Hint("ios.nearby.serviceType") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Bonjour service type the nearby transport advertises. Derived from the " + + "package name when unset.")); + + h.add(new Hint("ios.newStorageLocation") + .annotatedAs(HintGroup.IOS, "newStorageLocation") + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false defaults to false but defined on new projects as true by default. This " + + "changes the storage directory on iOS from using caches to using the documents directory " + + "which is the recommended location but might break compatibility. This is described in " + + "https://github.com/codenameone/CodenameOne/issues/1480[this issue]")); + + h.add(new Hint("ios.noUIWebView") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.no_strip") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.notificationPermissionAtLaunch") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false (defaults to false). Backward-compatibility flag for the pre-issue-#4876 " + + "behavior. By default, the iOS notification permission prompt is deferred until the app " + + "calls `Push.register()` or schedules a `LocalNotification`, matching the Android flow " + + "and giving the developer a chance to display a rationale screen first. Set this hint to " + + "`true` to restore the legacy behavior in which the prompt fires automatically inside " + + "`application:didFinishLaunchingWithOptions:` as soon as the app launches. Existing apps " + + "relying on the prompt being shown at launch should set this to `true`; new apps should " + + "leave it disabled and trigger the prompt explicitly when they're ready to ask for " + + "permission.")); + + h.add(new Hint("ios.objC") + .annotatedAs(HintGroup.IOS, "objC") + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Added the `-ObjC` compile flag to the project files which some native libraries require")); + + h.add(new Hint("ios.openURLInject") + .group(HintGroup.IOS) + .type(HintType.XML) + .separator("") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.optimizer") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("on") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.plistInject") + .annotatedAs(HintGroup.IOS, "plistInject") + .type(HintType.XML) + .separator("") + .platform("ios") + .consumedBy("IPhoneBuilder", "WatchNativeBuilder") + .doc("entries to inject into the iOS plist file during build.")); + + h.add(new Hint("ios.pods") + .annotatedAs(HintGroup.IOS, "pods") + .type(HintType.STRING_LIST) + .separator(",") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("A comma separated list of https://cocoapods.org/[Cocoa Pods] that should be linked to " + + "the app to build it. For example, `AFNetworking ~> 2.6, ORStackView ~> 3.0, SwiftyJSON " + + "~> 2.3`")); + + h.add(new Hint("ios.pods.build.CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.pods.build.CLANG_ENABLE_MODULES") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.pods.platform") + .annotatedAs(HintGroup.IOS, "podsPlatform") + .type(HintType.VERSION) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Sets the Cocoapods 'platform' for the Cocoapods. Some Cocoapods require a minimum " + + "platform level. For example, `ios.pods.platform=7.0`.")); + + h.add(new Hint("ios.pods.sources") + .annotatedAs(HintGroup.IOS, "podsSources") + .type(HintType.STRING_LIST) + .separator(",") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Extra CocoaPods spec repositories to search, in addition to the default trunk.")); + + h.add(new Hint("ios.pods.use_frameworks!") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.prerendered_icon") + .annotatedAs(HintGroup.IOS, "prerenderedIcon") + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false defaults to false. The iOS build process adapts the submitted icon for iOS " + + "conventions (adding an overlay) that might not be appropriate on some icons. Setting " + + "this to true leaves the icon unchanged (only scaled).")); + + h.add(new Hint("ios.project_type") + .annotatedAs(HintGroup.IOS, "projectType") + .values("IosProjectType", "ios", "ipad", "iphone") + .def("ios") + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder") + .doc("one of ios, ipad, iphone (defaults to ios). Indicates whether the resulting binary is " + + "targeted to the iphone only or ipad only. Notice that the IDE plugin has a \"Project " + + "Type\" combo box you *should* use under the iOS section.")); + + h.add(new Hint("ios.release.teamId") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder", "TvNativeBuilder", "WatchNativeBuilder") + .doc("Specifies the team ID associated with the iOS release provisioning profile and " + + "certificate.")); + + h.add(new Hint("ios.shareAppGroup") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.spm.packages") + .annotatedAs(HintGroup.IOS, "spmPackages") + .type(HintType.STRING_LIST) + .separator(";") + .platform("ios") + .consumedBy("IOSDependencyManager", "IPhoneBuilder") + .doc("Swift Package Manager packages to link, one per entry, each written as " + + "identity|url|requirement.")); + + h.add(new Hint("ios.statusBarFG") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.superfastBuild") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.surfaces.appGroup") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.surfaces.deploymentTarget") + .group(HintGroup.IOS) + .type(HintType.VERSION) + .def("16.1") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.surfaces.extension") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.surfaces.frequentUpdates") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.swiftVersion") + .group(HintGroup.IOS) + .type(HintType.VERSION) + .def("5.0") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.teamId") + .annotatedAs(HintGroup.IOS, "teamId") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder", "MacNativeBuilder", "TvNativeBuilder", "WatchNativeBuilder") + .doc("Specifies the team ID associated with the iOS provisioning profile and certificate. Use " + + "`ios.debug.teamId` and `ios.release.teamId` to specify different team IDs for debug and " + + "release builds respectively.")); + + h.add(new Hint("ios.themeMode") + .annotatedAs(HintGroup.IOS, "themeMode") + .values("IosThemeMode", "auto", "modern", "ios7", "legacy") + // Spellings IOSImplementation.installNativeTheme accepts for the + // same two themes. Not enum constants: one behaviour, one + // constant, or the annotation asks a question with no right + // answer. + .valueAliases("flat", "ios7", "liquid", "modern", "iphone", "legacy") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("`auto` (default), `modern`, `ios7`, `legacy`. `auto` (unset) keeps the existing iOS 7 " + + "flat theme so pre-refactor screenshot goldens and apps see no behavior change. `modern` " + + "/ `liquid` opts in to the CSS-generated iOS Modern (liquid-glass) theme shipped from " + + "`native-themes/ios-modern/theme.css`. `ios7` / `flat` is the same as `auto` - pre-liquid " + + "iOS 7 flat theme; `legacy` / `iphone` loads the pre-iOS 7 iPhone theme. The `auto` -> " + + "modern flip is planned for a future release.")); + + h.add(new Hint("ios.timeSensitiveNotifications") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.twoDigitVersion") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder", "WatchNativeBuilder")); + + h.add(new Hint("ios.uiscene") + .annotatedAs(HintGroup.IOS, "uiscene") + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("true/false (defaults to true). Enables iOS UIScene lifecycle support. UIScene lets iOS " + + "manage one or more app UI sessions independently, improving lifecycle handling in modern " + + "iOS versions. Apple has indicated UIScene will be required starting with iOS 27, so this " + + "is now on by default; set the flag to `false` only if you need to temporarily fall back " + + "to the legacy `UIApplicationDelegate` lifecycle.")); + + h.add(new Hint("ios.urlScheme") + .annotatedAs(HintGroup.IOS, "urlScheme") + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Allows intercepting a URL call using the syntax `urlPrefix`")); + + h.add(new Hint("ios.urlSchemes") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.useAVKit") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Use AVKit for video components on iOS rather than `MPMoviePlayerController` on iOS " + + "versions 8 through 12. iOS 13 will always use AVKit, and iOS 7 and lower will always use " + + "`MPMoviePlayerController`. Default value `false`")); + + h.add(new Hint("ios.useJavascriptCore") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.usePhotoKitForMultigallery") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.usePrintf") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.useWKWebView") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.usesBackgroundProcessing") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.viewDidLoad") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Objective-C code that can be injected into the iOS callback method (message) " + + "`viewDidLoad`")); + + h.add(new Hint("ios.viewDidLoadInclude") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.wallet.appGroup") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("App Group id starting with `group.` shared by the app and the generated Wallet " + + "extensions. The app publishes pass entries into this group through " + + "`com.codename1.payment.WalletExtension` and the group is added to the app and extension " + + "entitlements automatically. Required when `ios.wallet.extension=true`.")); + + h.add(new Hint("ios.wallet.authEndpoint") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("HTTPS URL the generated login UI extension POSTs `{\"username\",\"password\"}` to; the JSON " + + "response's `token` is stored in the App Group for the provisioning request. Required " + + "when `ios.wallet.includeUI=true`.")); + + h.add(new Hint("ios.wallet.extension") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. Generates an Apple Wallet issuer provisioning " + + "extension (the \"From apps on your iPhone\" flow in the Wallet app) and embeds it in the " + + "build. Requires `ios.wallet.appGroup` and `ios.wallet.issuerEndpoint`. See the Apple " + + "Wallet Extension chapter.")); + + h.add(new Hint("ios.wallet.includeUI") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("false") + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Boolean true/false defaults to false. Also generates the Wallet authorization UI " + + "extension - a login form shown inside the Wallet app when the app reports that " + + "authentication is required. Requires `ios.wallet.authEndpoint`.")); + + h.add(new Hint("ios.wallet.issuerEndpoint") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("HTTPS URL of the issuer backend endpoint that produces the encrypted provisioning " + + "payload. The generated extension POSTs Apple's certificates/nonce plus the card " + + "identifier and auth token there as JSON. Required when `ios.wallet.extension=true`.")); + + h.add(new Hint("ios.wallet.nonuiExtensionName") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("WalletNonUIExtension") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.wallet.uiExtensionName") + .group(HintGroup.IOS) + .type(HintType.STRING) + .def("WalletUIExtension") + .platform("ios") + .consumedBy("IPhoneBuilder")); + + h.add(new Hint("ios.wallet.generateRequestInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected at the generate-request marker of the non-UI Wallet extension.")); + + h.add(new Hint("ios.wallet.generateResponseInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected at the generate-response marker of the non-UI Wallet extension.")); + + h.add(new Hint("ios.wallet.nonuiImportsInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Extra `import` lines for the non-UI Wallet extension.")); + + h.add(new Hint("ios.wallet.passEntriesInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected where the non-UI Wallet extension lists its pass entries.")); + + h.add(new Hint("ios.wallet.remotePassEntriesInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected where the non-UI Wallet extension lists its remote pass entries.")); + + h.add(new Hint("ios.wallet.statusInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected at the status marker of the non-UI Wallet extension.")); + + h.add(new Hint("ios.wallet.uiAuthRequestInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected at the auth-request marker of the UI Wallet extension.")); + + h.add(new Hint("ios.wallet.uiAuthResponseInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected at the auth-response marker of the UI Wallet extension.")); + + h.add(new Hint("ios.wallet.uiImportsInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Extra `import` lines for the UI Wallet extension.")); + + h.add(new Hint("ios.wallet.uiViewDidLoadInject") + .group(HintGroup.IOS) + .type(HintType.STRING) + .platform("ios") + .consumedBy("IPhoneBuilder") + .doc("Swift injected into `viewDidLoad` of the UI Wallet extension.")); + + h.add(new Hint("ios.zbar_flash") + .group(HintGroup.IOS) + .type(HintType.BOOLEAN) + .def("true") + .platform("ios") + .consumedBy("IPhoneBuilder")); + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/HintGroup.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/HintGroup.java new file mode 100644 index 00000000000..d10c5eb294a --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/HintGroup.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +/** + * Which annotation type a hint is exposed through, and which section of the + * documentation and the Settings UI it belongs to. + * + *

Assignment is by name prefix, except that two feature groups deliberately + * claim a subtree across platforms: {@link #ON_DEVICE_DEBUG} takes the + * {@code ios.onDeviceDebug*} and {@code android.onDeviceDebug} hints out of + * their platform groups, and {@link #IOS_PRIVACY} takes the literal + * {@code ios.NS*UsageDescription} keys out of {@link #IOS}.

+ * + *

{@link #NONE} means catalogued but not annotated — the hint is still + * described here for the documentation, the Settings tool and the drift gate, + * but it is set through {@code codenameone_settings.properties}. Every dynamic + * hint family is NONE, because a Java annotation cannot express a map.

+ */ +public enum HintGroup { + IOS("Ios", "ios."), + ANDROID("Android", "android."), + DESKTOP("Desktop", "desktop."), + MAC_NATIVE("MacNative", "macNative."), + WINDOWS("Windows", "windows."), + LINUX("Linux", "linux."), + JAVASCRIPT("JavaScript", "javascript."), + TV_NATIVE("TvNative", "tvNative."), + WATCH_NATIVE("WatchNative", "watchNative."), + HARDENING("Hardening", "harden."), + ON_DEVICE_DEBUG("OnDeviceDebug", null), + IOS_PRIVACY("IosPrivacy", null), + /** Unprefixed and one-off-prefix hints, exposed through {@code @Build}. */ + GENERAL("Build", null), + /** Catalogued but not annotated. */ + NONE(null, null); + + private final String annotationSimpleName; + private final String keyPrefix; + + HintGroup(String annotationSimpleName, String keyPrefix) { + this.annotationSimpleName = annotationSimpleName; + this.keyPrefix = keyPrefix; + } + + /** Simple name of the generated annotation type, or null for {@link #NONE}. */ + public String annotationSimpleName() { + return annotationSimpleName; + } + + /** + * The hint-name prefix this group owns, or null when membership is not + * decided by prefix. + */ + public String keyPrefix() { + return keyPrefix; + } + + /** Whether hints in this group are exposed as annotation attributes. */ + public boolean isAnnotated() { + return annotationSimpleName != null; + } +} diff --git a/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/HintType.java b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/HintType.java new file mode 100644 index 00000000000..551a6dea287 --- /dev/null +++ b/maven/build-hint-catalog/src/main/java/com/codename1/build/shared/HintType.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +/** + * The kind of value a build hint carries. + * + *

This is the single source of truth for hint typing. Three other + * vocabularies used to describe the same thing and drifted apart from each + * other; they are now derived from this one via + * {@link BuildHints#settingsType(HintType)} and + * {@link BuildHints#editorWidget(HintType)}.

+ */ +public enum HintType { + /** {@code "true"} or {@code "false"}. Maps to a Java {@code boolean}. */ + BOOLEAN, + /** A decimal integer. Maps to a Java {@code int}. */ + INT, + /** Free text on a single line. */ + STRING, + /** Free text that is expected to span lines. Same Java type as STRING. */ + TEXT_BLOCK, + /** A delimited list. Maps to {@code String[]}; requires a separator. */ + STRING_LIST, + /** A closed set of values. Maps to a generated Java enum. */ + ENUM, + /** An XML fragment spliced into a manifest or plist. */ + XML, + /** A filesystem path. */ + PATH, + /** An absolute URL. */ + URL, + /** A dotted version number. */ + VERSION, + /** A credential. Never echoed in logs or diagnostics. */ + SECRET +} diff --git a/maven/build-hint-catalog/src/test/java/com/codename1/build/shared/BuildHintsTest.java b/maven/build-hint-catalog/src/test/java/com/codename1/build/shared/BuildHintsTest.java new file mode 100644 index 00000000000..a1b8040a6bb --- /dev/null +++ b/maven/build-hint-catalog/src/test/java/com/codename1/build/shared/BuildHintsTest.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2012, 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.codename1.build.shared; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * Self-consistency of the build hint catalog. + * + *

Everything downstream is generated from this table, so a defect here + * becomes a broken annotation, a wrong manifest entry, or a hint that silently + * does nothing. These checks are the reason the catalog is Java rather than a + * data file.

+ */ +class BuildHintsTest { + + /** + * Annotation members cannot be named after a public method of Object or + * Annotation: JLS 9.6.1 makes that a compile error, and it is not a keyword + * rule so it is easy to miss until the generated source will not build. + */ + private static final Set ILLEGAL_MEMBER_NAMES = new HashSet(Arrays.asList( + "equals", "hashCode", "toString", "annotationType", "clone", "getClass", + "notify", "notifyAll", "wait", "finalize")); + + private static final Set JAVA_KEYWORDS = new HashSet(Arrays.asList( + "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", + "class", "const", "continue", "default", "do", "double", "else", "enum", + "extends", "final", "finally", "float", "for", "goto", "if", "implements", + "import", "instanceof", "int", "interface", "long", "native", "new", + "package", "private", "protected", "public", "return", "short", "static", + "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", + "transient", "try", "void", "volatile", "while", + "true", "false", "null", "_", "var", "record", "yield", "sealed", "permits")); + + private static final Set LEGAL_SEPARATORS = new HashSet(Arrays.asList( + "", ";", ",", "\n", " ")); + + /** + * The separators {@code LibraryHintMerger} defines today. The catalog has to + * agree with all of them before that map can be deleted in favour of + * {@link BuildHints#separatorFor(String)} -- if the two disagree, a cn1lib's + * contribution is spliced onto the project's value with the wrong delimiter + * and the resulting Gradle or plist fragment is malformed. + */ + private static Map libraryHintMergerSeparators() { + Map m = new LinkedHashMap(); + m.put("android.gradleDep", ";"); + m.put("gradleDependencies", "\n"); + m.put("android.topDependency", "\n"); + m.put("android.repositories", "\n"); + m.put("android.xgradle", "\n"); + m.put("android.gradle.androidx", "\n"); + m.put("android.xgradle_default_config", "\n"); + m.put("android.gradlePlugin", "\n"); + m.put("android.supportv4Dep", "\n"); + m.put("android.proguardKeep", "\n"); + m.put("ios.pods", ","); + m.put("ios.applicationQueriesSchemes", ","); + m.put("ios.add_libs", ";"); + m.put("android.xapplication_attr", " "); + return m; + } + + @Test + void theCatalogIsNotEmpty() { + assertTrue(BuildHints.entries().size() > 400, + "expected the mined hint set, got " + BuildHints.entries().size()); + } + + @Test + void namesAreUniqueAndLookupWorksWithOrWithoutThePrefix() { + for (BuildHints.Hint h : BuildHints.entries()) { + assertSame(h, BuildHints.byName(h.name())); + assertSame(h, BuildHints.byName(BuildHints.ARG_PREFIX + h.name())); + } + } + + private static void assertSame(BuildHints.Hint expected, BuildHints.Hint actual) { + if (expected != actual) { + fail("lookup returned a different entry for " + expected.name()); + } + } + + @Test + void aliasesResolveToARealNonAliasHint() { + for (BuildHints.Hint h : BuildHints.entries()) { + if (h.aliasOf() == null) { + continue; + } + BuildHints.Hint target = BuildHints.byName(h.aliasOf()); + assertNotNull(target, h.name() + " aliases unknown hint " + h.aliasOf()); + assertTrue(target.aliasOf() == null, + h.name() + " aliases " + target.name() + ", which is itself an alias"); + assertEquals(target.name(), BuildHints.canonicalName(h.name())); + } + } + + @Test + void everyAnnotationAttributeIsClaimedExactlyOnce() { + Map claimed = new HashMap(); + for (BuildHints.Hint h : BuildHints.entries()) { + if (!h.isAnnotated()) { + continue; + } + String key = h.group().annotationSimpleName() + "#" + h.attr(); + String previous = claimed.put(key, h.name()); + assertTrue(previous == null, + "@" + key + " is claimed by both " + previous + " and " + h.name()); + } + } + + @Test + void annotationAttributeNamesAreLegalJavaMembers() { + for (BuildHints.Hint h : BuildHints.entries()) { + if (!h.isAnnotated()) { + continue; + } + String a = h.attr(); + assertTrue(a.length() > 0, h.name() + " has an empty attribute name"); + assertTrue(Character.isJavaIdentifierStart(a.charAt(0)), + h.name() + " -> '" + a + "' is not a legal identifier start"); + for (int i = 1; i < a.length(); i++) { + assertTrue(Character.isJavaIdentifierPart(a.charAt(i)), + h.name() + " -> '" + a + "' has an illegal identifier character"); + } + assertFalse(JAVA_KEYWORDS.contains(a), + h.name() + " -> '" + a + "' is a Java keyword"); + assertFalse(ILLEGAL_MEMBER_NAMES.contains(a), + h.name() + " -> '" + a + "' is override-equivalent to a method of " + + "Object or Annotation, which JLS 9.6.1 forbids as an " + + "annotation member name"); + } + } + + @Test + void anAnnotatedHintIsNeverDynamicAndNeverAnAlias() { + for (BuildHints.Hint h : BuildHints.entries()) { + if (!h.isAnnotated()) { + continue; + } + assertFalse(h.isDynamic(), + h.name() + " is a dynamic family; a Java annotation cannot express a map"); + assertTrue(h.aliasOf() == null, + h.name() + " is an alias, so annotating it would create two attributes " + + "for one effective setting"); + } + } + + @Test + void declaredDefaultsMatchTheirDeclaredType() { + for (BuildHints.Hint h : BuildHints.entries()) { + String d = h.def(); + if (d == null || d.length() == 0) { + continue; + } + switch (h.type()) { + case BOOLEAN: + assertTrue("true".equals(d) || "false".equals(d), + h.name() + " is BOOLEAN but defaults to '" + d + "'"); + break; + case INT: + try { + Integer.parseInt(d.trim()); + } catch (NumberFormatException e) { + fail(h.name() + " is INT but defaults to '" + d + "'"); + } + break; + case ENUM: + assertTrue(h.values().contains(d), + h.name() + " defaults to '" + d + "', which is outside its domain " + + h.values()); + break; + default: + break; + } + } + } + + @Test + void everyEnumHasAUsableDomain() { + for (BuildHints.Hint h : BuildHints.entries()) { + if (h.type() != HintType.ENUM) { + continue; + } + assertNotNull(h.enumName(), h.name() + " is ENUM with no enum type name"); + assertTrue(h.values().size() >= 2, + h.name() + " is ENUM with fewer than two values: " + h.values()); + for (String v : h.values()) { + assertFalse(v.indexOf(',') >= 0, + h.name() + " value '" + v + "' contains a comma, which the simulator's " + + "Build Hint editor uses to delimit its value list"); + } + if (!h.valueLabels().isEmpty()) { + assertEquals(h.values().size(), h.valueLabels().size(), + h.name() + " has a label list of a different length to its values"); + } + } + } + + /** + * One-way, deliberately. A list needs a delimiter, but a hint can carry a + * delimiter without being a list the user edits as items -- + * {@code android.xapplication_attr} joins XML attributes with a space. + */ + @Test + void everyListHintHasANonEmptySeparator() { + for (BuildHints.Hint h : BuildHints.entries()) { + if (h.type() == HintType.STRING_LIST) { + assertNotNull(h.separator(), h.name() + " is a list with no separator"); + assertFalse(h.separator().isEmpty(), + h.name() + " is a list with an empty separator, so its values would " + + "run together"); + } + if (h.separator() != null) { + assertTrue(LEGAL_SEPARATORS.contains(h.separator()), + h.name() + " uses an unsupported separator " + quote(h.separator())); + } + } + } + + @Test + void theCatalogAgreesWithLibraryHintMergerOnEverySeparatorItDefines() { + for (Map.Entry e : libraryHintMergerSeparators().entrySet()) { + BuildHints.Hint h = BuildHints.byName(e.getKey()); + assertNotNull(h, "LibraryHintMerger defines a separator for " + e.getKey() + + " but the catalog does not describe it"); + assertEquals(e.getValue(), BuildHints.separatorFor(e.getKey()), + "separator mismatch for " + e.getKey() + ": LibraryHintMerger says " + + quote(e.getValue()) + ", catalog says " + + quote(BuildHints.separatorFor(e.getKey()))); + } + } + + @Test + void anUnknownHintFallsBackToBareConcatenation() { + assertEquals("", BuildHints.separatorFor("some.hint.nobody.catalogued")); + assertEquals("", BuildHints.separatorFor(null)); + } + + @Test + void everyDynamicFamilyDeclaresItsPattern() { + int found = 0; + for (BuildHints.Hint h : BuildHints.entries()) { + if (!h.isDynamic()) { + continue; + } + found++; + assertNotNull(h.pattern(), h.name() + " is dynamic with no pattern"); + assertTrue(h.pattern().indexOf('*') >= 0, + h.name() + " is dynamic but its pattern matches only itself"); + } + assertTrue(found > 10, "expected the known dynamic families, found " + found); + } + + @Test + void derivedTypeVocabulariesCoverEveryHintType() { + Set widgets = new HashSet( + Arrays.asList("TextField", "TextArea", "Checkbox", "Select")); + for (HintType t : HintType.values()) { + assertNotNull(BuildHints.settingsType(t)); + assertTrue(widgets.contains(BuildHints.editorWidget(t)), + t + " maps to '" + BuildHints.editorWidget(t) + + "', which the Build Hint editor does not recognise and would " + + "silently render as a plain text field"); + } + } + + @Test + void everyHintNamesTheCodeThatReadsIt() { + for (BuildHints.Hint h : BuildHints.entries()) { + List by = h.consumedBy(); + assertTrue(!by.isEmpty() || h.isExternal(), + h.name() + " names no consumer and is not marked external(); either it is " + + "read somewhere this catalog does not record, or it is dead"); + } + } + + private static String quote(String s) { + if (s == null) { + return "null"; + } + return "'" + s.replace("\n", "\\n") + "'"; + } +} diff --git a/maven/codenameone-maven-plugin/pom.xml b/maven/codenameone-maven-plugin/pom.xml index aff7d0c4312..1a048926888 100644 --- a/maven/codenameone-maven-plugin/pom.xml +++ b/maven/codenameone-maven-plugin/pom.xml @@ -39,6 +39,11 @@ codenameone-platform-feature-catalog ${project.version} + + ${project.groupId} + codenameone-build-hint-catalog + ${project.version} + org.jdom jdom2 diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/AbstractCN1Mojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/AbstractCN1Mojo.java index 6ad3ac33f50..2965b2ecc51 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/AbstractCN1Mojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/AbstractCN1Mojo.java @@ -222,6 +222,11 @@ private void setupAnt() throws MojoExecutionException, MojoFailureException { @Parameter(defaultValue = "${session}", readonly = true) private MavenSession session; + /** The session this mojo is running in, for a subclass that has to reproduce it. */ + protected MavenSession getSession() { + return session; + } + /** * Lets {@code -Dcodename1.arg.x=y} override the settings file. * @@ -1110,5 +1115,102 @@ protected boolean isCN1ProjectDir() { return true; } + + /** + * Every directory a source could be compiled from, not only the ones + * {@code getCompileSourceRoots} lists. + * + *

build-helper and the generated-source plugins do add their roots there, + * but the Kotlin plugin compiles its own {@code } without adding + * them back -- so in a module that configures them, a Kotlin class could + * have a perfectly good source and still look deleted. The orphan filter + * would then drop it silently and its misplaced annotation would produce + * neither its hint nor the placement error.

+ * + *

The conventional {@code src/main/kotlin} is included when it exists for + * the same reason: this list is used to decide that a source is ABSENT, and + * a list that is merely incomplete must not be read as that.

+ */ + protected static List compileSourceRoots(MavenProject project) { + if (project == null) { + return null; + } + List roots = new ArrayList(); + List configured = project.getCompileSourceRoots(); + if (configured != null) { + roots.addAll(configured); + } + File basedir = project.getBasedir(); + if (basedir != null) { + File kotlin = new File(basedir, "src" + File.separator + "main" + + File.separator + "kotlin"); + if (kotlin.isDirectory() && !roots.contains(kotlin.getAbsolutePath())) { + roots.add(kotlin.getAbsolutePath()); + } + } + addKotlinSourceDirs(project, roots); + return roots; + } + + /** The Kotlin plugin's {@code }, wherever they are configured. */ + private static void addKotlinSourceDirs(MavenProject project, List roots) { + List plugins; + try { + plugins = project.getBuildPlugins(); + } catch (RuntimeException ex) { + return; + } + if (plugins == null) { + return; + } + for (org.apache.maven.model.Plugin plugin : plugins) { + if (!"kotlin-maven-plugin".equals(plugin.getArtifactId())) { + continue; + } + addSourceDirsFrom(project, plugin.getConfiguration(), roots); + if (plugin.getExecutions() == null) { + continue; + } + for (org.apache.maven.model.PluginExecution execution : plugin.getExecutions()) { + // The `compile` goal only. A `test-compile` execution's + // sourceDirs are src/test/kotlin and friends, and adding them + // here made a deleted production class look like it still had a + // source -- because a same-named test fixture does -- so a stale + // class under target/classes kept failing the build on a + // misplaced annotation no production source declares. + List goals = execution.getGoals(); + if (goals == null || !goals.contains("compile")) { + continue; + } + addSourceDirsFrom(project, execution.getConfiguration(), roots); + } + } + } + + private static void addSourceDirsFrom(MavenProject project, Object configuration, + List roots) { + if (!(configuration instanceof org.codehaus.plexus.util.xml.Xpp3Dom)) { + return; + } + org.codehaus.plexus.util.xml.Xpp3Dom dirs = + ((org.codehaus.plexus.util.xml.Xpp3Dom) configuration).getChild("sourceDirs"); + if (dirs == null) { + return; + } + for (org.codehaus.plexus.util.xml.Xpp3Dom dir : dirs.getChildren()) { + String value = dir.getValue(); + if (value == null || value.trim().isEmpty()) { + continue; + } + File f = new File(value.trim()); + if (!f.isAbsolute() && project.getBasedir() != null) { + f = new File(project.getBasedir(), value.trim()); + } + if (!roots.contains(f.getAbsolutePath())) { + roots.add(f.getAbsolutePath()); + } + } + } + } diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CN1BuildMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CN1BuildMojo.java index 9c6c01a59f6..6a1b7380587 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CN1BuildMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CN1BuildMojo.java @@ -321,10 +321,22 @@ private void applyHardeningPreflight() throws MojoFailureException { getLog().debug("Could not read codenameone_settings.properties for hardening pre-flight", ex); } } + // A hint set by @Hardening reaches the settings only in createAntProject, which runs after + // the Android up-to-date short-circuit below and after hardeningCacheKey is read from it. + // Without this the early pass computes "unhardened" from the file while the completed build + // records "hardened:...", the two never match, and an up-to-date APK is rebuilt on every + // invocation -- and, worse, an unsupported hardening request made through an annotation + // escapes the refusal this early pass exists to perform. + try { + mergeAnnotationBuildHints(settings, project.getCompileClasspathElements()); + } catch (org.apache.maven.artifact.DependencyResolutionRequiredException ex) { + getLog().debug("Could not read annotation build hints for the hardening pre-flight", ex); + } // Overlay -D command-line hints (e.g. -Dcodename1.arg.harden.level=standard) so an explicit // hardening request made only on the command line is seen by this early check -- and, because this // runs before the Android up-to-date cache short-circuit, is not silently dropped when a prior APK // is newer than the sources (getSourcesModificationTime does not account for build hints). + // After the annotations, so -D still wins over one. overlayCommandLineBuildHints(settings); applyHardeningPreflight(settings); } @@ -1481,6 +1493,13 @@ private void createAntProject() throws IOException, LibraryPropertiesException, try (FileInputStream fis = new FileInputStream(codenameOneSettingsCopy)) { cn1SettingsProps.load(fis); } + // Build hints declared as annotations on the main class. Merged here, before + // everything that consumes the effective configuration: the command-line + // overlay below (so -D still wins), the CN1Lib appended/required merges (so a + // library appends onto an annotation-supplied value exactly as it would onto a + // file-supplied one), the gradle sanity check, both preflights, and the copy + // that is written back out and uploaded. + mergeAnnotationBuildHints(cn1SettingsProps, cpElements); // The build request is assembled from this copy, not from the mojo's // own properties, so the command-line overlay has to be applied here // too -- otherwise a hint passed with -D is read by the mojo and still @@ -2622,4 +2641,538 @@ private SortedProperties mergeRequiredProperties(String libraryName, Properties return merged; } + + /** + * Name of the resource {@code BuildHintAnnotationProcessor} emits into + * {@code target/classes} at PROCESS_CLASSES. + */ + private static final String ANNOTATION_HINTS_RESOURCE = + "META-INF/codenameone/build-hints.properties"; + + /** + * Overlays the build hints that came from annotations onto the settings the + * build request is assembled from. + * + *

Read from the compile classpath rather than from the staged fat jar. + * {@code mergeJars} builds that jar with Ant's {@code Zip} in update mode, + * which adds and overwrites entries but never removes one, and the jar is + * reused when it is not stale — so a project that had its annotations + * deleted would keep shipping yesterday's hints. The classpath directory is + * written by the annotation processor on every build and deleted by it when + * the last annotation goes away, so it always reflects the current source.

+ */ + private void mergeAnnotationBuildHints(Properties target, List classpathElements) + throws MojoFailureException { + if (target == null || classpathElements == null) { + return; + } + String expectedMain = null; + if (properties != null) { + String main = properties.getProperty("codename1.mainName"); + String pkg = properties.getProperty("codename1.packageName"); + if (main != null && main.trim().length() > 0) { + expectedMain = (pkg == null || pkg.trim().length() == 0) + ? main.trim() : pkg.trim() + "." + main.trim(); + } + } + // The manifest's presence, not its contents, is what proves the processor + // ran. An annotation with every member left at its default -- @Ios() after + // the last attribute was deleted -- is legal Java, and the processor emits + // a manifest carrying only the main-class stamp for it. Judging by the hint + // count alone would read that as "never processed" and refuse a build that + // is in fact perfectly configured. + boolean processed = false; + String stale = null; + for (String element : classpathElements) { + Properties found = readAnnotationHints(new File(element)); + if (found == null) { + continue; + } + String stamped = found.getProperty("cn1.buildHints.mainClass"); + if (expectedMain != null && stamped != null && !expectedMain.equals(stamped)) { + // A cn1lib that bound the goal itself, or a stale artifact. Merging it + // would apply another project's build configuration to this one. + getLog().debug("cn1: ignoring build hints from " + element + + " -- they were generated for " + stamped); + continue; + } + // The stamp says which class produced this file, not when. Nothing + // clears target/classes between builds, so a project that ran the + // processor once and then stopped -- goal unbound, skipped, or bound + // to a phase that no longer runs -- keeps a manifest naming the right + // class while the annotations beside it have changed. Comparing the + // recorded fingerprint against the compiled class is what tells those + // apart; without it the build silently ships the older values and the + // guard below never runs. + String mismatch = digestMismatch(new File(element), expectedMain, found); + if (mismatch != null) { + getLog().debug("cn1: ignoring build hints from " + element + " -- " + mismatch); + stale = mismatch; + continue; + } + processed = true; + int applied = 0; + for (String key : found.stringPropertyNames()) { + if (!key.startsWith("codename1.arg.")) { + continue; + } + // The processor refuses a hint declared as an annotation and as a + // properties line, but it can only refuse the builds it runs in. + // The fingerprint above covers the annotations and nothing else, + // so with processing skipped a line added to the properties file + // afterwards leaves a manifest that still matches -- and this + // overlay would quietly replace the value the developer just + // wrote, until the next clean build regenerated the manifest and + // failed. Same declaration, same answer, whether or not + // target/classes happened to be cleaned. + String conflict = conflictingPropertiesDeclaration(target, key, found); + if (conflict != null) { + throw new MojoFailureException(conflict); + } + target.setProperty(key, found.getProperty(key)); + applied++; + } + if (applied > 0) { + getLog().info("cn1: applied " + applied + " build hint(s) from annotations"); + failOnMisplacedAnnotations(classpathElements, expectedMain); + return; + } + } + if (processed) { + getLog().debug("cn1: annotations were processed and set no build hint"); + failOnMisplacedAnnotations(classpathElements, expectedMain); + return; + } + // No manifest at all. If the compiled classes carry build hint + // annotations anyway, the processor never ran -- a mojo's defaultPhase + // does not add an execution to a project's POM, so an app that adopts the + // annotations without binding process-annotations compiles cleanly and + // ships with every annotated hint missing. Refuse rather than build that. + String annotated = classCarryingBuildHintAnnotations(classpathElements, expectedMain); + if (annotated != null) { + throw new MojoFailureException(annotated + " carries build hint annotations, but " + + (stale == null + ? "no " + ANNOTATION_HINTS_RESOURCE + " was produced" + : "the only " + ANNOTATION_HINTS_RESOURCE + " on the classpath is left " + + "over from an earlier build (" + stale + ")") + + ", so none of them reached this " + + "build.\n\nThe cn1 process-annotations goal has to run on the module that " + + "compiles it:\n" + + " \n" + + " cn1-process-classes\n" + + " process-classes\n" + + " \n" + + " process-annotations\n" + + " \n" + + " "); + } + } + + /** + * Refuses a build where a class other than the main one carries build hint + * annotations. + * + *

Run even when a manifest was accepted, because accepting one does not + * mean the processor ran THIS build: the fingerprint covers the main class, + * so an annotation added to a live class beside it leaves the manifest + * looking entirely current. With the goal unbound or skipped, the hints from + * that class reach nothing and the build succeeds having neither applied + * them nor said the annotation is in the wrong place -- the silent failure + * this whole feature exists to remove. Had the processor run, it would have + * refused the build for the same class.

+ */ + private void failOnMisplacedAnnotations(List classpathElements, String expectedMain) + throws MojoFailureException { + if (expectedMain == null) { + return; + } + java.util.Collection descriptors = + com.codename1.build.shared.BuildHintAnnotationBinding.descriptors(); + for (String element : classpathElements) { + String live = liveAnnotatedClass(new File(element), descriptors, expectedMain); + if (live != null) { + throw new MojoFailureException(live + " carries build hint annotations, but they " + + "are only read from the application's main class (" + expectedMain + + "), so none of them reached this build.\n\nMove them onto " + + expectedMain + ", or set those hints in " + + "codenameone_settings.properties."); + } + } + } + + /** + * The duplicate-declaration message for a hint set by an annotation and by a + * properties line, or null when there is no clash. + * + *

Only reached when the processor did not run this build; when it did, it + * has already failed for the same reason and with more to say -- it can point + * at the offending line. An alias counts as the same setting, matching what + * the processor checks, so declaring {@code and.captureRecord} in the file + * still collides with {@code @Android(captureRecord)}.

+ */ + private String conflictingPropertiesDeclaration(Properties settings, String key, + Properties manifest) { + String name = key.substring("codename1.arg.".length()); + java.util.Set names = new java.util.LinkedHashSet(); + names.add(name); + for (com.codename1.build.shared.BuildHints.Hint h + : com.codename1.build.shared.BuildHints.entries()) { + if (name.equals(h.aliasOf()) + || name.equals(com.codename1.build.shared.BuildHints.canonicalName(h.name()))) { + names.add(h.name()); + } + } + for (String candidate : names) { + String candidateKey = "codename1.arg." + candidate; + String fromFile = settings.getProperty(candidateKey); + if (fromFile == null) { + continue; + } + String origin = manifest.getProperty("cn1.buildHints.origin." + name); + return candidateKey + " is declared twice.\n" + + " annotation : " + (origin == null ? "on the main class" : origin) + + " = " + manifest.getProperty(key) + "\n" + + " properties : codenameone_settings.properties\n" + + " " + candidateKey + "=" + fromFile + "\n" + + " A build hint has one source of truth. Delete the properties line and " + + "keep the annotation, or delete the annotation attribute and keep the line. " + + "(-D" + candidateKey + "=... overrides either and is not a conflict.)"; + } + return null; + } + + /** + * Why a manifest cannot have come from the class beside it, or null when it can. + * + *

Answered only when both halves are actually available: with no + * {@code codename1.mainName}, no class file for it in this classpath element, + * or no recorded fingerprint, there is nothing to compare and the manifest is + * taken at face value -- the same as before this check existed. It refuses + * only on positive evidence of a mismatch.

+ */ + private String digestMismatch(File element, String expectedMain, Properties manifest) { + String recorded = manifest.getProperty( + com.codename1.maven.processors.BuildHintAnnotationProcessor.SOURCE_DIGEST_KEY); + if (expectedMain == null || recorded == null || recorded.length() == 0) { + return null; + } + try { + com.codename1.maven.annotations.AnnotatedClass cls = readClass(element, expectedMain); + if (cls == null) { + return null; + } + String actual = com.codename1.maven.processors.BuildHintAnnotationProcessor + .sourceDigest(cls); + if (recorded.equals(actual)) { + return null; + } + return "it was generated from a different set of annotations on " + + expectedMain + " than the one compiled into " + element; + } catch (IOException | com.codename1.maven.annotations.ProcessingException ex) { + // Unreadable is not evidence of staleness. + getLog().debug("cn1: could not fingerprint " + expectedMain + " in " + element, ex); + return null; + } + } + + /** Reads one compiled class out of a classpath directory or jar. */ + private com.codename1.maven.annotations.AnnotatedClass readClass(File element, String binaryName) + throws IOException, com.codename1.maven.annotations.ProcessingException { + String path = binaryName.replace('.', '/') + ".class"; + if (element.isDirectory()) { + File f = new File(element, path.replace('/', File.separatorChar)); + if (!f.isFile()) { + return null; + } + try (InputStream in = new FileInputStream(f)) { + return com.codename1.maven.annotations.ClassScanner.readClass(in, f); + } + } + if (element.isFile() && element.getName().endsWith(".jar")) { + try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(element)) { + java.util.zip.ZipEntry entry = zip.getEntry(path); + if (entry == null) { + return null; + } + try (InputStream in = zip.getInputStream(entry)) { + return com.codename1.maven.annotations.ClassScanner.readClass(in, element); + } + } + } + return null; + } + + /** + * The application class carrying a build hint annotation, or null. + * + *

Read straight out of the class file's annotation table rather than from + * source, so it sees exactly what the compiler emitted.

+ * + *

The MAIN class alone when the project names one. The processor honours + * no other class, so no other class is evidence that annotations went + * unprocessed — and scanning them all meant a stale annotated + * {@code .class}, left behind by a rename without a clean, failed every build + * with "no manifest was produced" for a class the developer had already + * deleted. The processor ignores that orphan; so does this. Only when the + * project names no main class at all does this fall back to scanning + * everything, since then there is nothing more specific to ask about.

+ */ + private String classCarryingBuildHintAnnotations(List classpathElements, + String expectedMain) { + java.util.Collection descriptors = + com.codename1.build.shared.BuildHintAnnotationBinding.descriptors(); + if (expectedMain != null) { + for (String element : classpathElements) { + try { + if (mainClassCarriesAnnotation(new File(element), expectedMain, descriptors)) { + return expectedMain; + } + } catch (IOException | RuntimeException ex) { + getLog().debug("cn1: could not read " + expectedMain + " from " + element, ex); + } + } + // The main class carries none. A LIVE class elsewhere still counts: + // @Target(TYPE) accepts the placement, so without this the build + // succeeds having neither applied the hint nor said the annotation is + // in the wrong place -- which is the silent failure the whole feature + // removes. It is only stale output that must not count, and that is a + // question about the source, not about which class it is. + // + // Reported as a misplacement, because that is what it is: had the + // processor run it would have refused the build for this class. + for (String element : classpathElements) { + String live = liveAnnotatedClass(new File(element), descriptors); + if (live != null) { + return live; + } + } + return null; + } + // A reactor `package` build hands us the dependency module's jar rather + // than its output directory, which findAnnotatedClasses handles alongside + // a directory -- that is exactly the shape this check has to work in. + for (String element : classpathElements) { + String hit = findAnnotatedClass(new File(element), descriptors); + if (hit != null) { + return hit; + } + } + return null; + } + + /** + * The first annotated class in this element whose source still exists, or null. + * + *

Stale output is excluded the same way the processor excludes it — + * by asking whether the module's configured source roots still declare the + * class — so an orphan left by a rename cannot fail the build, while a + * class the developer actually wrote does.

+ */ + private String liveAnnotatedClass(File element, java.util.Collection descriptors) { + return liveAnnotatedClass(element, descriptors, null); + } + + /// As above, ignoring `exclude` -- the class the manifest was generated for, + /// which carrying annotations is the whole point of. + private String liveAnnotatedClass(File element, java.util.Collection descriptors, + String exclude) { + List roots; + try { + // The complete set, not only what getCompileSourceRoots lists: the + // Kotlin plugin compiles its own sourceDirs without adding them + // back, and this list is used to decide that a source is ABSENT. + roots = compileSourceRoots(project); + } catch (RuntimeException ex) { + return null; + } + if (roots == null || roots.isEmpty()) { + // Not told where the sources are, so staleness cannot be judged and + // an orphan would fail the build. Silence is the lesser harm: the + // processor still refuses this placement whenever it runs. + return null; + } + // Every candidate, not the first: rejecting one stale class must not end + // the search, or whether a live misplacement is reported depends on the + // order the directory happened to be listed in. + for (String hit : findAnnotatedClasses(element, descriptors)) { + if (exclude != null && exclude.equals(hit)) { + continue; + } + try { + com.codename1.maven.annotations.AnnotatedClass cls = readClass(element, hit); + if (cls != null && com.codename1.maven.processors.BuildHintAnnotationProcessor + .hasBackingSource(cls, roots)) { + return hit; + } + } catch (IOException | com.codename1.maven.annotations.ProcessingException ex) { + getLog().debug("cn1: could not read " + hit + " from " + element, ex); + } + } + return null; + } + + /** Whether the named class, read from this classpath element, is annotated. */ + private boolean mainClassCarriesAnnotation(File element, String binaryName, + java.util.Collection descriptors) + throws IOException { + String path = binaryName.replace('.', '/') + ".class"; + if (element.isDirectory()) { + File f = new File(element, path.replace('/', File.separatorChar)); + if (!f.isFile()) { + return false; + } + try (InputStream in = new FileInputStream(f)) { + return carriesBuildHintAnnotation(in, descriptors); + } + } + if (element.isFile() && element.getName().endsWith(".jar")) { + try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(element)) { + java.util.zip.ZipEntry entry = zip.getEntry(path); + if (entry == null) { + return false; + } + try (InputStream in = zip.getInputStream(entry)) { + return carriesBuildHintAnnotation(in, descriptors); + } + } + } + return false; + } + + + private boolean carriesBuildHintAnnotation(InputStream in, + java.util.Collection descriptors) + throws IOException { + final boolean[] seen = {false}; + new org.objectweb.asm.ClassReader(in).accept( + new org.objectweb.asm.ClassVisitor(org.objectweb.asm.Opcodes.ASM9) { + @Override + public org.objectweb.asm.AnnotationVisitor visitAnnotation( + String desc, boolean visible) { + if (descriptors.contains(desc)) { + seen[0] = true; + } + return null; + } + }, + org.objectweb.asm.ClassReader.SKIP_CODE + | org.objectweb.asm.ClassReader.SKIP_DEBUG + | org.objectweb.asm.ClassReader.SKIP_FRAMES); + return seen[0]; + } + + private String findAnnotatedClass(File dir, java.util.Collection descriptors) { + List all = findAnnotatedClasses(dir, descriptors); + return all.isEmpty() ? null : all.get(0); + } + + /** + * Every annotated class under this element, by BINARY name. + * + *

The binary name, not the file's own: returning {@code Wrong} for + * {@code com/example/Wrong.class} made the message name a class that does not + * exist, and made re-reading it by name fail, so the guard saw nothing.

+ * + *

All of them, not the first: an incremental output directory can hold a + * stale annotated class and a live one at once, and stopping at whichever + * {@code File.listFiles} returned first made the answer depend on directory + * order.

+ */ + private List findAnnotatedClasses(File element, java.util.Collection descriptors) { + List out = new ArrayList(); + if (element.isDirectory()) { + collectAnnotatedClasses(element, element, descriptors, out); + } else if (element.isFile() && element.getName().endsWith(".jar")) { + try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(element)) { + java.util.Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + java.util.zip.ZipEntry entry = entries.nextElement(); + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { + continue; + } + try (InputStream in = zip.getInputStream(entry)) { + if (carriesBuildHintAnnotation(in, descriptors)) { + out.add(entry.getName() + .substring(0, entry.getName().length() - ".class".length()) + .replace('/', '.')); + } + } + } + } catch (IOException | RuntimeException ex) { + getLog().debug("cn1: could not scan " + element + ": " + ex.getMessage()); + } + } + return out; + } + + private void collectAnnotatedClasses(File root, File dir, + java.util.Collection descriptors, + List out) { + File[] children = dir.listFiles(); + if (children == null) { + return; + } + for (File f : children) { + if (f.isDirectory()) { + collectAnnotatedClasses(root, f, descriptors, out); + continue; + } + if (!f.getName().endsWith(".class")) { + continue; + } + try (InputStream in = new FileInputStream(f)) { + if (carriesBuildHintAnnotation(in, descriptors)) { + String rel = f.getAbsolutePath() + .substring(root.getAbsolutePath().length()) + .replace(File.separatorChar, '/'); + while (rel.startsWith("/")) { + rel = rel.substring(1); + } + out.add(rel.substring(0, rel.length() - ".class".length()).replace('/', '.')); + } + } catch (IOException | RuntimeException ex) { + getLog().debug("cn1: could not scan " + f + ": " + ex.getMessage()); + } + } + } + + /** + * Reads the emitted hints out of a classpath element, which is either the + * module's output directory or a jar. + * + * @return the properties, or null when this element carries none + */ + private Properties readAnnotationHints(File element) { + if (element == null || !element.exists()) { + return null; + } + try { + if (element.isDirectory()) { + File f = new File(element, ANNOTATION_HINTS_RESOURCE); + if (!f.isFile()) { + return null; + } + try (FileInputStream in = new FileInputStream(f)) { + Properties p = new Properties(); + p.load(in); + return p; + } + } + try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(element)) { + java.util.zip.ZipEntry entry = zip.getEntry(ANNOTATION_HINTS_RESOURCE); + if (entry == null) { + return null; + } + try (InputStream in = zip.getInputStream(entry)) { + Properties p = new Properties(); + p.load(in); + return p; + } + } + } catch (IOException ex) { + getLog().warn("cn1: could not read build hints from " + element + ": " + + ex.getMessage()); + return null; + } + } } diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/LibraryHintMerger.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/LibraryHintMerger.java index afc9afa70fb..3649854a508 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/LibraryHintMerger.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/LibraryHintMerger.java @@ -22,8 +22,8 @@ */ package com.codename1.maven; -import java.util.HashMap; -import java.util.Map; +import com.codename1.build.shared.BuildHints; + import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -56,46 +56,6 @@ public class LibraryHintMerger { /** Prefix every build hint carries inside a settings/library properties file. */ private static final String ARG_PREFIX = "codename1.arg."; - /** - * Separator per hint, keyed by the name with {@link #ARG_PREFIX} stripped. - * - *

Read off how the builders themselves split or append each value, not invented here: - * {@code IPhoneBuilder} splits {@code ios.pods} and {@code ios.applicationQueriesSchemes} - * on {@code ","} and joins {@code ios.add_libs} with {@code ";"}, while every - * {@code AndroidGradleBuilder} injection into a Gradle text hint appends a newline-wrapped - * statement. A hint absent from this map keeps the historical bare concatenation, which is - * what the XML-fragment hints want.

- */ - private static final Map SEPARATORS = new HashMap(); - static { - // A Gradle dependency list. ';' rather than a newline because this is the hint - // users hand-edit most, every existing project and cn1lib already writes it that - // way, and keeping the value on one line survives any line-oriented tooling that - // rewrites codenameone_settings.properties. - SEPARATORS.put("android.gradleDep", ";"); - // Block structured Gradle text, where a statement per line is the only thing that - // reads correctly -- and what our own builder injections already append. - SEPARATORS.put("gradleDependencies", "\n"); - SEPARATORS.put("android.topDependency", "\n"); - SEPARATORS.put("android.repositories", "\n"); - SEPARATORS.put("android.xgradle", "\n"); - SEPARATORS.put("android.gradle.androidx", "\n"); - SEPARATORS.put("android.xgradle_default_config", "\n"); - SEPARATORS.put("android.gradlePlugin", "\n"); - SEPARATORS.put("android.supportv4Dep", "\n"); - // ProGuard/R8 directives are line oriented. - SEPARATORS.put("android.proguardKeep", "\n"); - // Comma-delimited lists. - SEPARATORS.put("ios.pods", ","); - SEPARATORS.put("ios.applicationQueriesSchemes", ","); - // Semicolon-delimited lists. - SEPARATORS.put("ios.add_libs", ";"); - // Attributes spliced into a single XML tag, so they abut with a space rather than - // directly -- android:allowBackup="false"android:hardwareAccelerated="true" is not - // a well formed tag. - SEPARATORS.put("android.xapplication_attr", " "); - } - private LibraryHintMerger() { } @@ -103,6 +63,10 @@ private LibraryHintMerger() { * The separator two values of this hint must be joined with, or an empty string when the * hint's values abut directly (the XML-fragment hints). * + *

The table lives in {@link BuildHints}, which is also what the build hint annotations + * are generated from. Keeping one copy is what stops a {@code String[]} attribute being + * joined with one delimiter here and split with another by the builder.

+ * * @param propertyName hint name, with or without the {@code codename1.arg.} prefix * @return the separator, never null */ @@ -113,8 +77,7 @@ public static String separatorFor(String propertyName) { String name = propertyName.startsWith(ARG_PREFIX) ? propertyName.substring(ARG_PREFIX.length()) : propertyName; - String separator = SEPARATORS.get(name); - return separator == null ? "" : separator; + return BuildHints.separatorFor(name); } /** diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/MigrateBuildHintsMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/MigrateBuildHintsMojo.java new file mode 100644 index 00000000000..a817eca6f62 --- /dev/null +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/MigrateBuildHintsMojo.java @@ -0,0 +1,1888 @@ +/* + * Copyright (c) 2012, 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.codename1.maven; + +import com.codename1.build.shared.BuildHints; +import com.codename1.build.shared.HintType; + +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.shared.invoker.DefaultInvocationRequest; +import org.apache.maven.shared.invoker.DefaultInvoker; +import org.apache.maven.shared.invoker.InvocationRequest; +import org.apache.maven.shared.invoker.InvocationResult; +import org.apache.maven.shared.invoker.MavenInvocationException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; + +import java.io.BufferedReader; +import java.io.Reader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +/** + * Rewrites {@code codename1.arg.*} lines in {@code codenameone_settings.properties} + * as build hint annotations on the application's main class. + * + *

A build hint written as a properties line is a string nothing checks: a + * misspelled name is accepted, never read, and silently does nothing. The same + * hint written as an annotation is checked by the compiler. This goal moves the + * ones that have an annotation and leaves the rest alone.

+ * + *

Runs in place and prints what it did. Pass {@code -Dcn1.migrate.dryRun=true} + * to see the plan without touching anything.

+ */ +// Aggregator: every module of a Codename One project resolves to the same +// codenameone_settings.properties, so running per-module would try to migrate +// the same file several times and the second pass would find its own output. +@Mojo(name = "migrate-build-hints", requiresProject = true, aggregator = true, + requiresDependencyResolution = ResolutionScope.COMPILE) +public class MigrateBuildHintsMojo extends AbstractCN1Mojo { + + /** + * The whole reactor. This goal is an aggregator, so {@code project} is the + * root pom -- which carries no codenameone-core dependency of its own. The + * core has to be looked for across the modules. + */ + @Parameter(defaultValue = "${session.projects}", readonly = true, required = true) + private java.util.List reactorProjects; + + /** Report what would change without writing anything. */ + @Parameter(property = "cn1.migrate.dryRun", defaultValue = "false") + private boolean dryRun; + + /** + * Hints to leave in the properties file even though they have an annotation. + * {@code java.version} is always kept: it selects the toolchain that compiles + * the class the annotations would live on, so it has to be readable before + * any of the project's own code exists. + */ + @Parameter(property = "cn1.migrate.keep") + private String keep; + + @Override + protected void executeImpl() throws MojoExecutionException, MojoFailureException { + File projectDir = getCN1ProjectDir(); + if (projectDir == null) { + throw new MojoExecutionException("No Codename One project directory found; " + + "this goal must run in a project with a codenameone_settings.properties."); + } + File settingsFile = new File(projectDir, "codenameone_settings.properties"); + if (!settingsFile.isFile()) { + throw new MojoExecutionException("No codenameone_settings.properties in " + projectDir); + } + + // The annotations ship in codenameone-core. A project pinned to a release + // that predates them would migrate cleanly here and then fail to compile, + // so refuse rather than hand back a broken project. + if (!coreHasBuildHintAnnotations()) { + throw new MojoFailureException("This project builds against a Codename One version " + + "whose core has no com.codename1.annotations.buildhints package, so the " + + "annotations would not resolve. Update the project's cn1.version first."); + } + + Properties settings = new Properties(); + try (FileInputStream in = new FileInputStream(settingsFile)) { + settings.load(in); + } catch (IOException ex) { + throw new MojoExecutionException("Could not read " + settingsFile, ex); + } + + List kept = new ArrayList(); + kept.add("java.version"); + if (keep != null) { + for (String k : keep.split(",")) { + if (k.trim().length() > 0) { + kept.add(k.trim()); + } + } + } + + // Resolve the target language before rendering: Kotlin writes an array + // literal as [a, b] and rejects Java's {a, b}, so the same hint renders + // differently depending on which file it is going into. + String mainSourcePath = findMainClassSource(projectDir, settings); + boolean kotlinTarget = mainSourcePath != null && mainSourcePath.endsWith(".kt"); + + // annotation simple name -> attribute -> source literal + Map> plan = new TreeMap>(); + List migratedKeys = new ArrayList(); + /// Canonical keys to look for in the emitted manifest. Not the same list: + /// a legacy spelling is deleted under the name the file used and comes + /// back under the name the annotation carries. + List verifiedKeys = new ArrayList(); + List skipped = new ArrayList(); + /// Canonical hint name to every properties key that names it. + Map> declaredAs = new TreeMap>(); + Map byHint = new TreeMap(); + + for (String key : new ArrayList(settings.stringPropertyNames())) { + if (!key.startsWith(BuildHints.ARG_PREFIX)) { + continue; + } + String name = key.substring(BuildHints.ARG_PREFIX.length()); + if (kept.contains(name)) { + skipped.add(name + " (kept by configuration)"); + continue; + } + // Through the alias, not at it. byName("cn1.androidTheme") returns the + // alias entry, whose own isAnnotated() is false even though the + // setting it names has an annotation -- so the legacy spellings, which + // are exactly the ones an existing project is most likely to be + // carrying, were reported as having no annotation and left behind. + BuildHints.Hint hint = BuildHints.resolve(BuildHints.byName(name)); + if (hint == null || !hint.isAnnotated()) { + skipped.add(name + " (no annotation for this hint yet)"); + continue; + } + List spellings = declaredAs.get(hint.name()); + if (spellings == null) { + spellings = new ArrayList(); + declaredAs.put(hint.name(), spellings); + byHint.put(hint.name(), hint); + } + spellings.add(key); + } + + for (Map.Entry> e : declaredAs.entrySet()) { + BuildHints.Hint hint = byHint.get(e.getKey()); + List spellings = e.getValue(); + + // One setting, spelled more than one way, with the two disagreeing. + // Which one the build honours is decided per hint and not always by + // the builder: and.captureRecord is read after android.captureRecord + // and overrides it, while the theme aliases are each handed to + // Display.setProperty and resolved in the framework. So there is no + // rule to apply here, and picking either value would change what the + // app builds with while reporting a successful migration -- the + // verification cannot catch it, since it checks that the hint came + // back and not what it holds. The developer decides. + String value = settings.getProperty(spellings.get(0)); + boolean disagree = false; + for (String other : spellings) { + String v = settings.getProperty(other); + if (value == null ? v != null : !value.equals(v)) { + disagree = true; + } + } + if (disagree) { + skipped.add(e.getKey() + " (declared as " + spellings + " with different values; " + + "delete all but one and run this again)"); + continue; + } + + String literal = toSourceLiteral(hint, value, kotlinTarget); + if (literal == null) { + boolean padded = value != null && !value.equals(value.trim()); + skipped.add(e.getKey() + " = '" + value + "' (" + + (padded + ? "has surrounding whitespace, which builders read differently; " + + "remove it and run this again" + : "value is outside the hint's supported set") + + ")"); + continue; + } + String annotation = hint.group().annotationSimpleName(); + Map members = plan.get(annotation); + if (members == null) { + members = new TreeMap(); + plan.put(annotation, members); + } + members.put(hint.attr(), literal); + // Every spelling goes, because they were all naming this one setting. + migratedKeys.addAll(spellings); + // Verified under the CANONICAL key: that is what the annotation makes + // the processor emit. Checking the alias the file happened to use + // reported it missing and rolled a correct migration back. + verifiedKeys.add(BuildHints.ARG_PREFIX + hint.name()); + } + + if (plan.isEmpty()) { + getLog().info("cn1: nothing to migrate -- no annotated build hint is set in " + + settingsFile.getName()); + for (String s : skipped) { + getLog().debug("cn1: left in place: " + s); + } + return; + } + + String mainSource = mainSourcePath; + StringBuilder rendered = new StringBuilder(); + for (Map.Entry> e : plan.entrySet()) { + rendered.append(render(e.getKey(), e.getValue())).append('\n'); + } + + getLog().info("cn1: move these onto " + (mainSource == null ? "your main class" + : new File(mainSource).getName()) + ":"); + for (String line : rendered.toString().split("\n")) { + getLog().info("cn1: " + line); + } + for (String s : skipped) { + getLog().info("cn1: leaving " + s); + } + + if (dryRun) { + getLog().info("cn1: dry run -- nothing written"); + return; + } + if (mainSource == null) { + throw new MojoFailureException("Could not find the source of the main class named by " + + "codename1.mainName. Add the annotations above by hand, then delete the " + + "migrated lines from " + settingsFile.getName() + "."); + } + + // Add the annotations, prove the build actually turns them back into hints, + // and only then delete the properties. Deciding that from the POM instead + // meant guessing whether process-annotations would run -- and the goal is + // skippable, bindable to a phase with no compiled classes, bindable to the + // wrong module, and skippable through a property expression. Observing the + // emitted resource answers all of those at once, and answers correctly for + // whatever the next way to not-run turns out to be. + // Apply the whole migration, prove the build turns the annotations back + // into hints, and roll both files back if it does not. + // + // Both files have to move together before the check: leaving the + // properties in place while the annotations are added *is* the + // duplicate-declaration case, so the build would fail for that reason and + // never tell us whether processing works at all. + // + // Deciding this from the POM instead meant guessing whether + // process-annotations would run, and the goal is skippable, bindable to a + // phase with no compiled classes, bindable to the wrong module, and + // skippable through a property expression. Observing the emitted resource + // answers all of those at once, and answers correctly for whatever the + // next way to not-run turns out to be. + File source = new File(mainSource); + String originalSource; + String originalSettings; + try { + originalSource = read(source); + originalSettings = readProperties(settingsFile); + } catch (IOException ex) { + throw new MojoExecutionException("Migration failed: " + ex.getMessage(), ex); + } + + // Anything that throws from here on has to put both files back. The half + // that fails is not always the second one: if the annotations go in and + // the properties rewrite then fails -- an unwritable file, a full disk, a + // partial write -- the project is left declaring the same hint twice, + // which is exactly the state the next build refuses to compile. Leaving + // the developer with that is worse than not migrating at all. + try { + insertAnnotations(source, rendered.toString(), + settings.getProperty("codename1.mainName", "").trim()); + removeMigratedLines(settingsFile, migratedKeys); + } catch (IOException | RuntimeException ex) { + throw new MojoExecutionException("Migration failed, so " + source.getName() + " and " + + settingsFile.getName() + " have been put back as they were: " + + ex.getMessage() + + restore(source, originalSource, settingsFile, originalSettings), ex); + } + + String missing = verifyAnnotationsAreProcessed(projectDir, verifiedKeys); + if (missing != null) { + String restoreFailed = restore(source, originalSource, settingsFile, originalSettings); + throw new MojoFailureException("The annotations were added but the build did not turn " + + "them into build hints, so " + source.getName() + " and " + + settingsFile.getName() + " have been put back as they were.\n\n" + + missing + "\n\nThe usual cause is that this module does not run the cn1 " + + "process-annotations goal, or runs it skipped or before compile. Add it and " + + "try again:\n" + + " \n" + + " cn1-process-classes\n" + + " process-classes\n" + + " \n" + + " process-annotations\n" + + " \n" + + " " + + restoreFailed); + } + + getLog().info("cn1: migrated " + migratedKeys.size() + " build hint(s) into " + + new File(mainSource).getName()); + } + + /** + * Puts both files back as they were. + * + * @return an empty string when both were restored, otherwise a description of + * what could not be, to append to the failure being reported + */ + private String restore(File source, String originalSource, + File settingsFile, String originalSettings) { + StringBuilder failed = new StringBuilder(); + try { + write(source, originalSource); + } catch (IOException ex) { + failed.append("\nCould not restore ").append(source).append(": ") + .append(ex.getMessage()); + } + try { + writeProperties(settingsFile, originalSettings); + } catch (IOException ex) { + failed.append("\nCould not restore ").append(settingsFile).append(": ") + .append(ex.getMessage()); + } + return failed.toString(); + } + + /** + * Runs the project's own build over the module that holds the main class and + * checks that every migrated hint came back out of it. + * + * @return null when all of them did, otherwise a description of what is + * missing, suitable for showing to the developer + */ + private String verifyAnnotationsAreProcessed(File projectDir, List migratedKeys) { + getLog().info("cn1: building " + projectDir.getName() + + " to confirm the annotations produce the hints..."); + // Delete any manifest an earlier build left behind first. Checking that + // the file exists and holds the right keys proves nothing if it was + // already there: with processing now skipped or unbound the nested build + // leaves it untouched, the check passes, the properties are deleted, and + // the next clean build removes the stale artifact and the hints with it. + // Where the processor will actually write, which is not always + // target/classes: a module is free to configure build/outputDirectory, + // and looking in the wrong place would report a successful build as + // having produced nothing and roll a correct migration back. + org.apache.maven.project.MavenProject owner = moduleAt(projectDir); + File outputDir = configuredOutputDirectory(owner, projectDir); + File emitted = new File(outputDir, ANNOTATION_HINTS_RESOURCE); + if (emitted.isFile() && !emitted.delete()) { + return "Could not remove the previous " + ANNOTATION_HINTS_RESOURCE + + ", so this build's output could not be told apart from it."; + } + // Run the REACTOR and select the owning module, rather than pointing + // Maven at that module's own POM. A module POM on its own resolves its + // siblings from the local repository, so a project whose main module + // depends on another module of the same build -- normal, and not + // necessarily installed -- fails to resolve here and the migration rolls + // back over a build that a plain `mvn package` performs happily. + File modulePom = new File(projectDir, "pom.xml"); + File reactorPom = new File(project.getBasedir(), "pom.xml"); + InvocationRequest request = new DefaultInvocationRequest(); + if (reactorPom.isFile() && owner != null) { + request.setPomFile(reactorPom); + request.setProjects(Collections.singletonList( + owner.getGroupId() + ":" + owner.getArtifactId())); + request.setAlsoMake(true); + } else { + request.setPomFile(modulePom.isFile() ? modulePom : reactorPom); + } + request.setGoals(Collections.singletonList("process-classes")); + Properties props = new Properties(); + props.setProperty("skipTests", "true"); + // Reproduce the invocation the developer actually made. A project that + // needs `-Pcustomer` to compile, or `-Dfeature=true` to bind + // process-annotations, is a different build without them: the check + // would roll back a migration that works, or -- worse -- pass a build + // whose processing an outer -D was switching off. The user properties go + // in first so skipTests below cannot be silently overridden by one. + if (getSession() != null) { + Properties user = getSession().getUserProperties(); + if (user != null) { + for (String name : user.stringPropertyNames()) { + props.setProperty(name, user.getProperty(name)); + } + } + props.setProperty("skipTests", "true"); + List profiles = activeProfileIds(); + if (!profiles.isEmpty()) { + request.setProfiles(profiles); + } + } + request.setProperties(props); + request.setBatchMode(true); + try { + InvocationResult result = new DefaultInvoker().execute(request); + if (result.getExitCode() != 0) { + return "The build failed with exit code " + result.getExitCode() + + ", so the annotations could not be checked."; + } + } catch (MavenInvocationException ex) { + return "The build could not be run (" + ex.getMessage() + + "), so the annotations could not be checked."; + } + + if (!emitted.isFile()) { + return "No " + ANNOTATION_HINTS_RESOURCE + " was written under " + outputDir + "."; + } + Properties produced = new Properties(); + try (FileInputStream in = new FileInputStream(emitted)) { + produced.load(in); + } catch (IOException ex) { + return "Could not read " + emitted + ": " + ex.getMessage(); + } + List absent = new ArrayList(); + for (String key : migratedKeys) { + if (produced.getProperty(key) == null) { + absent.add(key); + } + } + if (!absent.isEmpty()) { + return "These hints were annotated but did not come back out of the build: " + absent; + } + return null; + } + + /** + * The profiles this invocation was started with, by id. + * + *

Taken from the request rather than from the resolved project, because + * what has to be reproduced is what the developer typed: a profile activated + * by a property or a file is activated again on its own terms in the nested + * build, while one named with {@code -P} is not unless it is passed on.

+ */ + private List activeProfileIds() { + List out = new ArrayList(); + if (getSession() == null || getSession().getRequest() == null) { + return out; + } + List active = getSession().getRequest().getActiveProfiles(); + if (active != null) { + for (String id : active) { + if (id != null && id.trim().length() > 0) { + out.add(id.trim()); + } + } + } + return out; + } + + /** The reactor module whose basedir is {@code dir}, or null when none is. */ /** The reactor module whose basedir is {@code dir}, or null when none is. */ + private org.apache.maven.project.MavenProject moduleAt(File dir) { + if (reactorProjects == null || dir == null) { + return null; + } + File wanted = canonical(dir); + for (org.apache.maven.project.MavenProject p : reactorProjects) { + if (p.getBasedir() != null && canonical(p.getBasedir()).equals(wanted)) { + return p; + } + } + return null; + } + + /** + * The directory {@code process-classes} writes compiled output to. + * + *

Read off the module rather than assumed, since a POM may configure it. + * Falls back to the conventional path when the directory is not a reactor + * module at all -- an Ant-layout project, for instance.

+ */ + private static File configuredOutputDirectory(org.apache.maven.project.MavenProject owner, + File projectDir) { + if (owner != null && owner.getBuild() != null + && owner.getBuild().getOutputDirectory() != null + && owner.getBuild().getOutputDirectory().length() > 0) { + return new File(owner.getBuild().getOutputDirectory()); + } + return new File(projectDir, "target" + File.separator + "classes"); + } + + private static File canonical(File f) { + try { + return f.getCanonicalFile(); + } catch (IOException ex) { + return f.getAbsoluteFile(); + } + } + + /** Name of the resource the annotation processor emits into target/classes. */ /** Name of the resource the annotation processor emits into target/classes. */ + private static final String ANNOTATION_HINTS_RESOURCE = + "META-INF/codenameone/build-hints.properties"; + + /** + * Whether the codenameone-core on this project's compile classpath actually + * carries the annotations. + */ + private boolean coreHasBuildHintAnnotations() { + java.util.List projects = reactorProjects; + if (projects == null || projects.isEmpty()) { + projects = java.util.Collections.singletonList(project); + } + for (org.apache.maven.project.MavenProject p : projects) { + if (carriesBuildHintAnnotations(p)) { + return true; + } + } + return false; + } + + private boolean carriesBuildHintAnnotations(org.apache.maven.project.MavenProject p) { + try { + for (Object element : p.getCompileClasspathElements()) { + File f = new File((String) element); + if (f.isDirectory()) { + if (new File(f, "com/codename1/annotations/buildhints/Ios.class").isFile()) { + return true; + } + } else if (f.isFile()) { + try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(f)) { + if (zip.getEntry("com/codename1/annotations/buildhints/Ios.class") != null) { + return true; + } + } + } + } + } catch (Exception ex) { + getLog().debug("cn1: could not inspect the compile classpath: " + ex.getMessage()); + return true; + } + return false; + } + + /// Whether `value` is spelled exactly as the domain declares it, alias or not. + /// + /// canonicalValue ignores case because a reader might; the migration cannot + /// afford to, because a reader might not. + private static boolean exactlySpelled(BuildHints.Hint hint, String value) { + for (String allowed : hint.values()) { + if (allowed.equals(value)) { + return true; + } + } + return hint.valueAliases().containsKey(value); + } + + /** + * Renders a value as the Java literal for its attribute. + * + * @return the literal, or null when the value is outside a closed domain -- + * which is worth reporting rather than silently translating, because + * it means the properties file has been setting something the build + * never understood + */ + String toSourceLiteral(BuildHints.Hint hint, String value, boolean kotlin) { + if (value == null) { + return null; + } + // A scalar with surrounding whitespace is NOT migrated at all. It looks + // like it means what it says, and it does not: AndroidGradleBuilder + // compares android.hideStatusBar with .equals("true"), so `=true ` is + // false today, while other builders trim or ignore case. Trimming it into + // an annotation `true` would change what the app builds with and report a + // successful migration, since the verification asks whether the hint came + // back and not what it holds. Which reading is right differs per builder, + // so this refuses rather than picks. + if (hint.type() != HintType.STRING && hint.type() != HintType.STRING_LIST + && !value.equals(value.trim())) { + return null; + } + String v = value; + switch (hint.type()) { + case BOOLEAN: + // Exactly, not ignoring case. AndroidGradleBuilder compares + // android.hideStatusBar with .equals("true"), so `=TRUE` is false + // today, while other hints are read with equalsIgnoreCase. Which + // applies is per hint and this cannot know, so a value that is not + // already canonical is refused rather than normalised into one + // that may mean the opposite. + if ("true".equals(v)) return "true"; + if ("false".equals(v)) return "false"; + return null; + case INT: + try { + // Round-tripped for the same reason: 007 and +5 parse, and a + // builder comparing the raw string would not see the 7 or 5 + // this would otherwise write. + String canonical = String.valueOf(Integer.parseInt(v)); + return canonical.equals(v) ? canonical : null; + } catch (NumberFormatException ex) { + return null; + } + case ENUM: { + // A documented spelling that is not its own constant migrates to + // the constant it means -- ios.themeMode=flat becomes + // IosThemeMode.IOS7 -- rather than being refused as outside the + // domain, which is what an existing project setting a legacy + // spelling would have hit. + // + // Case-sensitively, though: installNativeTheme compares with + // .equals, so `MODERN` is not `modern` to the runtime and + // migrating it would change the theme rather than preserve it. + String canonical = hint.canonicalValue(v); + if (canonical == null || !exactlySpelled(hint, v)) { + return null; + } + return hint.enumName() + "." + enumConstant(canonical); + } + case STRING_LIST: { + String sep = hint.separator(); + if (sep == null || sep.length() == 0) { + return quoteFor(v, kotlin); + } + // Verbatim, and every element kept. Trimming and dropping empties + // looked tidy and is a rewrite: android.xgradle is newline + // delimited raw Groovy that AndroidGradleBuilder appends as it + // stands, so the indentation inside a multiline string is part of + // the value. Splitting on the separator and joining the elements + // back with it now reproduces the original string exactly, which + // is the only property that makes this migration lossless -- the + // verification cannot see it, since it checks that the hint came + // back and not what it holds. + String[] parts = v.split(java.util.regex.Pattern.quote(sep), -1); + StringBuilder sb = new StringBuilder(kotlin ? "[" : "{"); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(quoteFor(parts[i], kotlin)); + } + return sb.append(kotlin ? ']' : '}').toString(); + } + default: + return quoteFor(v, kotlin); + } + } + + /** Mirrors the generator's wire-value to constant-name mapping. */ + static String enumConstant(String wire) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < wire.length(); i++) { + char c = wire.charAt(i); + if (Character.isUpperCase(c) && sb.length() > 0 + && Character.isLowerCase(wire.charAt(i - 1))) { + sb.append('_'); + } + sb.append(Character.isLetterOrDigit(c) ? Character.toUpperCase(c) : '_'); + } + String out = sb.toString(); + return out.length() > 0 && Character.isDigit(out.charAt(0)) ? "V" + out : out; + } + + /** + * Renders a value as a string literal for the target language. + * + *

Kotlin interpolates {@code $} inside a string, and hint values contain + * it: an {@code android.gradleDep} of + * {@code implementation "com.x:y:${'$'}{version}"} would either fail to + * compile as an unresolved reference or silently resolve to something else. + * Java has no such construct, so the escape is emitted only for Kotlin.

+ * + *

Everything outside ASCII is written as a {@code \}{@code uXXXX} escape, + * which both languages accept. {@code Properties.load} turns a + * {@code \}{@code u20ac} in the file into a real euro sign, and the source is + * written back through ISO-8859-1 to keep the rest of the file byte-identical + * -- so emitting the character raw would replace it with {@code ?}, or write a + * high byte that corrupts a UTF-8 source. Neither shows up in the + * verification build, which checks that the hint came back, not what its + * value was.

+ */ + static String quoteFor(String s, boolean kotlin) { + StringBuilder sb = new StringBuilder("\""); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '"': sb.append("\\\""); break; + case '\\': sb.append("\\\\"); break; + case '\n': sb.append("\\n"); break; + case '\r': sb.append("\\r"); break; + case '\t': sb.append("\\t"); break; + case '$': + sb.append(kotlin ? "\\$" : "$"); + break; + default: + if (c < 0x20 || c > 0x7e) { + sb.append("\\u"); + for (int shift = 12; shift >= 0; shift -= 4) { + sb.append(Character.forDigit((c >> shift) & 0xf, 16)); + } + } else { + sb.append(c); + } + } + } + return sb.append('"').toString(); + } + + static String render(String annotation, Map members) { + StringBuilder sb = new StringBuilder("@").append(annotation).append('('); + int i = 0; + for (Map.Entry e : members.entrySet()) { + if (i++ > 0) { + sb.append(", "); + } + sb.append(e.getKey()).append(" = ").append(e.getValue()); + } + return sb.append(')').toString(); + } + + private String findMainClassSource(File projectDir, Properties settings) { + String main = settings.getProperty("codename1.mainName"); + String pkg = settings.getProperty("codename1.packageName"); + if (main == null || main.trim().length() == 0) { + return null; + } + String path = (pkg == null ? "" : pkg.trim().replace('.', File.separatorChar) + + File.separator) + main.trim(); + String simple = main.trim(); + String expectedPkg = pkg == null ? "" : pkg.trim(); + String[] roots = {"src" + File.separator + "main" + File.separator + "java", + "src" + File.separator + "main" + File.separator + "kotlin", + "src"}; + String[] extensions = {".java", ".kt"}; + for (String root : roots) { + for (String ext : extensions) { + File f = new File(projectDir, root + File.separator + path + ext); + // Declaring the class, not merely sitting at the conventional + // path: a Kotlin main class moved into a differently named file + // can leave the old one behind holding something else. + if (f.isFile() && declares(f, expectedPkg, simple)) { + return f.getAbsolutePath(); + } + } + } + // Those three are a convention. Maven is the authority on where this + // module's sources are -- a module may add src/app/java or a Kotlin root + // -- and Kotlin does not require a file to be named after its class, so + // the file is identified by what it DECLARES. Without this the goal + // aborted with "Could not find the source" on a project Maven compiles + // perfectly well. + org.apache.maven.project.MavenProject owner = moduleAt(projectDir); + // The complete set, since the Kotlin plugin compiles its own sourceDirs + // without adding them back -- a main class living only in one of those + // is compiled by Maven and was reported here as missing. + java.util.List moduleRoots = compileSourceRoots(owner); + if (moduleRoots == null) { + return null; + } + for (String root : moduleRoots) { + File dir = new File(root); + if (!dir.isDirectory()) { + continue; + } + File hit = findDeclaringFile(dir, expectedPkg, simple, 0); + if (hit != null) { + return hit.getAbsolutePath(); + } + } + return null; + } + + /// The first .java or .kt under `dir` declaring `simple` in `pkg`, or null. + private File findDeclaringFile(File dir, String pkg, String simple, int depth) { + if (depth > 24) { + return null; + } + File[] children = dir.listFiles(); + if (children == null) { + return null; + } + for (File f : children) { + if (f.isDirectory()) { + File hit = findDeclaringFile(f, pkg, simple, depth + 1); + if (hit != null) { + return hit; + } + } else if ((f.getName().endsWith(".java") || f.getName().endsWith(".kt")) + && declares(f, pkg, simple)) { + return f; + } + } + return null; + } + + /// Whether `f` declares type `simple` in package `pkg`. + /// + /// Through the annotation processor's helpers rather than a second copy: the + /// two have already drifted apart once in this change, and "what counts as a + /// declaration" should have one answer. + private boolean declares(File f, String pkg, String simple) { + String text; + try { + text = read(f); + } catch (IOException ex) { + return false; + } + boolean kotlin = f.getName().endsWith(".kt"); + // TOP LEVEL, which a single-segment nested path is exactly the test for. + // An application's main class is not nested, and accepting one at any + // depth stopped the search on a leftover Main.kt holding + // `class Outer { class Main }` -- the annotations were then inserted on + // Outer, and the verification build rejected the placement and rolled the + // migration back. + String declaredPkg = com.codename1.maven.processors.BuildHintAnnotationProcessor + .declaredPackageIn(text, kotlin); + return (pkg.equals(declaredPkg) || asWrittenInSource(pkg).equals(declaredPkg)) + && (com.codename1.maven.processors.BuildHintAnnotationProcessor + .declaresNestedPath(text, new String[] {simple}, kotlin) + || com.codename1.maven.processors.BuildHintAnnotationProcessor + .declaresNestedPath(text, new String[] {asWrittenInSource(simple)}, kotlin)); + } + + /// `name` spelled the way a UTF-8 source file reads under the + /// byte-transparent scheme, or `name` itself when it is ASCII. + /// + /// The source is read byte for byte -- see [#read(File)] -- while + /// `codename1.packageName` and `codename1.mainName` come from a properties + /// file, which is real Unicode. For an ASCII name the two are identical, but + /// `package com.应用` in a UTF-8 file reads as its individual bytes, so the + /// comparison failed and the goal refused a valid migration saying it could + /// not find the main source. + /// + /// Compared as an ALTERNATIVE rather than a replacement, so nothing is + /// assumed about the file's encoding: an ASCII file matches either way, a + /// UTF-8 one matches this spelling, and a source genuinely written in a + /// single-byte encoding still matches the plain one. Reinterpreting the file + /// instead would decide its encoding for it, which is the thing the + /// byte-transparent read exists to avoid. + static String asWrittenInSource(String name) { + try { + return new String(name.getBytes("UTF-8"), SOURCE_BYTE_TRANSPARENT_ENCODING); + } catch (java.io.UnsupportedEncodingException ex) { + return name; + } + } + + /** + * Splices the annotations in above the class declaration, with the import. + * + *

Textual rather than a parse: the file may be Java or Kotlin, it may use + * any formatting, and rewriting it through a parser would reformat code the + * developer did not ask to have touched.

+ */ + void insertAnnotations(File source, String annotations, String simpleName) + throws IOException { + String text = read(source); + boolean kotlin = source.getName().endsWith(".kt"); + String blanked = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(text, kotlin); + // A live import, not the words anywhere in the file. A comment or a + // string mentioning the package -- a javadoc line about build hints, say + // -- aborted the migration on a source that compiles perfectly well and + // has no import at all. + if (importsBuildHints(blanked)) { + throw new IOException(source.getName() + " already imports the build hint " + + "annotations; migrate the remaining hints by hand so nothing is " + + "overwritten."); + } + + // Named imports, one per annotation written, rather than the package on + // demand -- and the fully qualified name instead for any whose simple + // name the file has already given to something else. A wildcard import + // loses to an explicit `import com.example.Build;` and to a type in the + // file's own package, so the generated `@Build` referred to theirs, the + // verification build failed, and an otherwise valid migration rolled + // back. A named import beats a same-package type; only a type declared + // in this very file cannot be imported at all, so that one is qualified. + StringBuilder importLines = new StringBuilder(); + StringBuilder written = new StringBuilder(); + for (String line : annotations.split("\n", -1)) { + String name = annotationNameOf(line); + if (name == null) { + written.append(line).append('\n'); + continue; + } + String body = line; + if (simpleNameIsTaken(text, blanked, name, kotlin)) { + body = "@" + ANNOTATION_PACKAGE + "." + line.substring(1); + } else if (importLines.indexOf(importOf(name, kotlin)) < 0) { + importLines.append(importOf(name, kotlin)).append('\n'); + } + // An enum-valued hint renders as `IosThemeMode.MODERN`, which is a + // second type to account for -- without its own import the generated + // annotation does not compile, so every enum-valued migration was + // rolled back by its own verification build. + written.append(withEnumsResolved(body, text, blanked, kotlin, importLines)) + .append('\n'); + } + // split(-1) keeps the trailing empty piece, which put a blank line back. + annotations = written.substring(0, Math.max(0, written.length() - 1)); + String importLine = importLines.length() == 0 ? null + : importLines.substring(0, importLines.length() - 1); + + int declaration = classDeclarationIndex(text, kotlin, simpleName); + if (declaration < 0) { + throw new IOException("Could not find the class declaration in " + source.getName()); + } + String head = text.substring(0, declaration); + String tail = text.substring(declaration); + + String blankedHead = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, kotlin); + int lastImport = lastImportIndex(blankedHead); + if (lastImport >= 0) { + // After the whole declaration. `import java.\n util.List;` is legal + // and the first newline after the keyword is inside it, so cutting + // there spliced the new import into the middle of the old one and the + // verification build rolled a correct migration back. + int at = endOfImportDeclaration(blankedHead, lastImport); + if (importLine != null) { + head = head.substring(0, at) + importLine + "\n" + head.substring(at); + } + } else if (importLine != null) { + // No existing import. Anchor after the package declaration, and when + // the class is in the default package anchor above any annotation it + // already carries: indexOf returns -1 there, and the old arithmetic + // then put the import at the first newline in the file, which is + // inside the copyright comment. + // + // The package is found in CODE. A header sentence mentioning the word + // -- "// The package layout is documented here" -- was selected by a + // raw search, and the import went in before the real declaration or + // inside the comment itself, so the verification build failed and + // rolled back a migration that was otherwise correct. + int pkg = livePackageIndex(blankedHead); + int anchor = pkg >= 0 ? endOfPackageDeclaration(blankedHead, pkg) + : startOfFirstDeclaration(head, kotlin); + head = head.substring(0, anchor) + (pkg >= 0 ? "\n" : "") + + importLine + "\n" + (pkg >= 0 ? "" : "\n") + head.substring(anchor); + } + write(source, head + annotations + tail); + } + + /// `line` with every enum type it names either imported or written out in + /// full, by the same rule the annotation names follow. + private static String withEnumsResolved(String line, String text, String blanked, + boolean kotlin, StringBuilder importLines) { + java.util.Set enums = enumTypeNames(); + StringBuilder out = new StringBuilder(); + int i = 0; + while (i < line.length()) { + char c = line.charAt(i); + if (!Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(line.charAt(i - 1)))) { + out.append(c); + i++; + continue; + } + int end = i; + while (end < line.length() && Character.isJavaIdentifierPart(line.charAt(end))) { + end++; + } + String word = line.substring(i, end); + if (!enums.contains(word) || end >= line.length() || line.charAt(end) != '.') { + out.append(word); + i = end; + continue; + } + if (simpleNameIsTaken(text, blanked, word, kotlin)) { + out.append(ANNOTATION_PACKAGE).append('.').append(word); + } else { + if (importLines.indexOf(importOf(word, kotlin)) < 0) { + importLines.append(importOf(word, kotlin)).append('\n'); + } + out.append(word); + } + i = end; + } + return out.toString(); + } + + /// Every enum type the catalog can render a value as. + private static java.util.Set enumTypeNames() { + java.util.Set out = new java.util.LinkedHashSet(); + for (com.codename1.build.shared.BuildHints.Hint h + : com.codename1.build.shared.BuildHints.entries()) { + if (h.enumName() != null && h.enumName().length() > 0) { + out.add(h.enumName()); + } + } + return out; + } + + /** The package the generated annotations live in. */ + private static final String ANNOTATION_PACKAGE = "com.codename1.annotations.buildhints"; + + /** The import statement for one of them, in the right language. */ + private static String importOf(String simple, boolean kotlin) { + return "import " + ANNOTATION_PACKAGE + "." + simple + (kotlin ? "" : ";"); + } + + /// The annotation a generated line writes, or null when the line is not one. + /// + /// The text being read here is the text this goal just rendered, one + /// annotation to a line, so this recognises that shape rather than parsing + /// the language. + private static String annotationNameOf(String line) { + if (!line.startsWith("@")) { + return null; + } + int end = 1; + while (end < line.length() && Character.isJavaIdentifierPart(line.charAt(end))) { + end++; + } + return end > 1 ? line.substring(1, end) : null; + } + + /// Whether `simple` already names something else in this file: a type it + /// declares, or a type it imports from elsewhere. + /// + /// A same-package type is NOT taken, because the named import this goal + /// writes beats it. A type declared in this very file is, because importing + /// a name the compilation unit declares is an error rather than a shadowing. + private static boolean simpleNameIsTaken(String text, String blanked, String simple, + boolean kotlin) { + if (com.codename1.maven.processors.BuildHintAnnotationProcessor + .declaresType(text, simple, kotlin)) { + return true; + } + if (kotlin && declaresTypeAlias(blanked, simple)) { + return true; + } + for (int at = importKeywordAt(blanked, 0); at >= 0; + at = importKeywordAt(blanked, at + "import".length())) { + if (simple.equals(importedSimpleName(blanked, at, kotlin))) { + return true; + } + } + return false; + } + + /// Whether blanked `code` declares `typealias simple = ...`. + /// + /// A typealias is a declaration this file makes, so it takes the name as + /// surely as a class does -- and the type lookup only knows about class, + /// object, interface, enum and record. Writing a named import beside one + /// gives the same local name twice, which does not compile. + private static boolean declaresTypeAlias(String code, String simple) { + int at = 0; + while (true) { + at = code.indexOf("typealias", at); + if (at < 0) { + return false; + } + int after = at + "typealias".length(); + boolean whole = (at == 0 || !Character.isJavaIdentifierPart(code.charAt(at - 1))) + && after < code.length() + && !Character.isJavaIdentifierPart(code.charAt(after)); + if (whole) { + int n = after; + while (n < code.length() && Character.isWhitespace(code.charAt(n))) { + n++; + } + int escaped = com.codename1.maven.processors.BuildHintAnnotationProcessor + .escapedIdentifierEnd(code, n); + String name; + if (escaped > n) { + name = code.substring(n + 1, escaped - 1); + } else { + int stop = n; + while (stop < code.length() + && Character.isJavaIdentifierPart(code.charAt(stop))) { + stop++; + } + name = code.substring(n, stop); + } + if (simple.equals(name)) { + return true; + } + } + at = after; + } + } + + /// The name the import at `at` makes available, or null when it makes none + /// this goal has to work around. + /// + /// The `as` alias is read as a TOKEN. Searching for the literal `" as "` + /// missed `import com.example.Other as\nIos`, which is legal, so the goal + /// wrote its own `import ...buildhints.Ios` beside it -- two imports giving + /// the same local name, which does not compile, so verification rolled back + /// an otherwise valid migration. An on-demand import is not a name at all: + /// the named import this goal writes beats it. + private static String importedSimpleName(String blanked, int at, boolean kotlin) { + int nameAt = at + "import".length(); + int probeStatic = nameAt; + while (probeStatic < blanked.length() + && Character.isWhitespace(blanked.charAt(probeStatic))) { + probeStatic++; + } + if (!kotlin && blanked.startsWith("static", probeStatic) + && probeStatic + 6 < blanked.length() + && !Character.isJavaIdentifierPart(blanked.charAt(probeStatic + 6))) { + nameAt = probeStatic + 6; + } + String name = com.codename1.maven.processors.BuildHintAnnotationProcessor + .qualifiedNameAt(blanked, nameAt); + int end = com.codename1.maven.processors.BuildHintAnnotationProcessor + .qualifiedNameEnd(blanked, nameAt); + int dot = name.lastIndexOf('.'); + String last = dot < 0 ? name : name.substring(dot + 1); + if ("*".equals(last) || last.length() == 0) { + return null; + } + if (!kotlin) { + return last; + } + int probe = end; + while (probe < blanked.length() && Character.isWhitespace(blanked.charAt(probe))) { + probe++; + } + if (!blanked.startsWith("as", probe) || probe + 2 >= blanked.length() + || Character.isJavaIdentifierPart(blanked.charAt(probe + 2))) { + return last; + } + int alias = probe + 2; + while (alias < blanked.length() && Character.isWhitespace(blanked.charAt(alias))) { + alias++; + } + int escaped = com.codename1.maven.processors.BuildHintAnnotationProcessor + .escapedIdentifierEnd(blanked, alias); + if (escaped > alias) { + return blanked.substring(alias + 1, escaped - 1); + } + int stop = alias; + while (stop < blanked.length() && Character.isJavaIdentifierPart(blanked.charAt(stop))) { + stop++; + } + return stop > alias ? blanked.substring(alias, stop) : last; + } + + /** + * Index of the start of the line declaring the top-level type. + * + *

Matched by pattern rather than against a list of prefixes: a declaration + * can carry any combination of modifiers -- {@code public final class}, + * {@code internal data class} -- and a missing combination would abort the + * migration on a perfectly ordinary file. Anchored to column zero so a + * nested type or a mention inside an indented doc comment cannot match, and + * the type named by {@code codename1.mainName} is preferred over whatever + * happens to appear first.

+ */ + /// Whether blanked `code` contains a live import of the build hint package. + /// The end of the declaration that has been read up to `i`: its terminating + /// semicolon if it has one, then the rest of that line. + /// + /// Any whitespace before the semicolon, newlines included -- a blanked block + /// comment keeps its newlines, so `import foo.Bar /* note\n */ ;` left the + /// semicolon unconsumed and ended the declaration at that newline, INSIDE + /// the comment. The generated import was written there and stayed commented + /// out, so the annotations failed verification and a valid migration was + /// rolled back. Only taken when a semicolon is what follows, so a Kotlin + /// declaration that has none still ends on its own line. + private static int endOfDeclarationLine(String code, int i) { + int probe = i; + while (probe < code.length() && Character.isWhitespace(code.charAt(probe))) { + probe++; + } + if (probe < code.length() && code.charAt(probe) == ';') { + i = probe + 1; + } + int eol = code.indexOf('\n', i); + return eol < 0 ? code.length() : eol + 1; + } + + static boolean importsBuildHints(String code) { + for (int at = importKeywordAt(code, 0); at >= 0; + at = importKeywordAt(code, at + "import".length())) { + String name = com.codename1.maven.processors.BuildHintAnnotationProcessor + .qualifiedNameAt(code, at + "import".length()); + // The PACKAGE, not any name that starts with its letters. An + // unrelated com.codename1.annotations.buildhintsExtra.Widget read as + // "already imported" and aborted a migration with nothing to + // conflict with. + if (name.equals("com.codename1.annotations.buildhints") + || name.startsWith("com.codename1.annotations.buildhints.")) { + return true; + } + } + return false; + } + + /// The offset of the last live `import` keyword in blanked `code`, or -1. + static int lastImportIndex(String code) { + int last = -1; + for (int at = importKeywordAt(code, 0); at >= 0; + at = importKeywordAt(code, at + "import".length())) { + last = at; + } + return last; + } + + private static int importKeywordAt(String code, int from) { + int i = from; + while (i < code.length()) { + // A Kotlin escaped identifier is code, not a keyword: `fun + // `import`() {}` declares a function called import. + int escaped = com.codename1.maven.processors.BuildHintAnnotationProcessor + .escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (!Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int end = i; + while (end < code.length() && Character.isJavaIdentifierPart(code.charAt(end))) { + end++; + } + if ("import".equals(code.substring(i, end))) { + return i; + } + i = end; + } + return -1; + } + + /// The index just past the import declaration beginning at `importAt`. + static int endOfImportDeclaration(String code, int importAt) { + int i = importAt + "import".length(); + // Java's optional `static` first. Passing it to the name reader made + // `static` itself the imported name, and the declaration then ended at + // the newline inside the real name -- so `import static java.util.\n + // Collections.emptyList;` had the generated import spliced into it. + int probeStatic = i; + while (probeStatic < code.length() && Character.isWhitespace(code.charAt(probeStatic))) { + probeStatic++; + } + if (code.startsWith("static", probeStatic) + && probeStatic + 6 < code.length() + && !Character.isJavaIdentifierPart(code.charAt(probeStatic + 6))) { + i = probeStatic + 6; + } + // The name, then an optional Kotlin `as` alias, then an optional + // semicolon, then the rest of that line. + for (int pass = 0; pass < 2; pass++) { + // Component by component: `import java.\n util.List;` is legal, and a + // contiguous run stops at the newline in the middle of the name. + i = com.codename1.maven.processors.BuildHintAnnotationProcessor + .qualifiedNameEnd(code, i); + int probe = i; + while (probe < code.length() && Character.isWhitespace(code.charAt(probe))) { + probe++; + } + if (!code.startsWith("as", probe) || probe + 2 >= code.length() + || Character.isJavaIdentifierPart(code.charAt(probe + 2))) { + break; + } + i = probe + 2; + } + return endOfDeclarationLine(code, i); + } + + /// The offset of the `package` keyword in already-blanked code, or -1. + static int livePackageIndex(String code) { + int i = 0; + while (i < code.length()) { + // A Kotlin escaped identifier is code, not a keyword: `fun + // `import`() {}` declares a function called import. + int escaped = com.codename1.maven.processors.BuildHintAnnotationProcessor + .escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (!Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < code.length() + && Character.isJavaIdentifierPart(code.charAt(wordEnd))) { + wordEnd++; + } + if ("package".equals(code.substring(i, wordEnd))) { + return i; + } + i = wordEnd; + } + return -1; + } + + /// The index just past the whole package declaration beginning at `pkgAt`. + /// + /// Past the NAME and its optional semicolon, not merely to the next newline: + /// `package\ncom.example;` is valid Java, and cutting at the first newline + /// would have inserted the import into the middle of the statement. + static int endOfPackageDeclaration(String code, int pkgAt) { + // Component by component. `package com.\nexample;` is legal, and a + // contiguous scan stops at the newline -- so the import was inserted + // before `example;` and the verification build rolled back a correct + // migration. Same reader the import anchor uses, so the two cannot + // disagree about where a name ends. + int i = com.codename1.maven.processors.BuildHintAnnotationProcessor + .qualifiedNameEnd(code, pkgAt + "package".length()); + return endOfDeclarationLine(code, i); + } + + /// The offset in `original` where an import may be inserted: before the + /// FIRST top-level declaration, whatever it is. + /// + /// Only for a file with no package declaration and no existing import -- + /// otherwise the anchor is the end of one of those. This replaced a backward + /// walk from the main class over its annotations and modifiers, which + /// answered the wrong question: an import goes above EVERY top-level + /// declaration, so a `fun helper() {}` written before the main class left + /// the import below it and the verification build rejected the file. There + /// is nothing to back over once the anchor is the first declaration in the + /// file, which is also why the annotation and modifier cases it used to + /// handle now need no handling. + /// + /// Kotlin's FILE annotations are the exception, and the only one: the + /// grammar puts them above the package header and the imports both, so the + /// leading `@file:` run is stepped over rather than displaced. + static int startOfFirstDeclaration(String original) { + return startOfFirstDeclaration(original, false); + } + + static int startOfFirstDeclaration(String original, boolean kotlin) { + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(original, kotlin); + int i = 0; + while (true) { + while (i < code.length() && Character.isWhitespace(code.charAt(i))) { + i++; + } + if (i >= code.length()) { + return code.length(); + } + if (!kotlin || !fileAnnotationAt(code, i)) { + return i; + } + int after = endOfAnnotation(code, i); + if (after <= i) { + return i; + } + i = after; + } + } + + /// Whether `@file:` starts at `at`. Kotlin allows space around the colon. + private static boolean fileAnnotationAt(String code, int at) { + if (at >= code.length() || code.charAt(at) != '@') { + return false; + } + int i = at + 1; + while (i < code.length() && Character.isWhitespace(code.charAt(i))) { + i++; + } + if (!code.startsWith("file", i)) { + return false; + } + i += 4; + while (i < code.length() && Character.isWhitespace(code.charAt(i))) { + i++; + } + return i < code.length() && code.charAt(i) == ':'; + } + + /// The offset just past the annotation starting at `at`, or `at` when it + /// cannot be read. Blanked code, so a parenthesis inside a literal is gone. + private static int endOfAnnotation(String code, int at) { + int i = at + 1; + while (i < code.length() && (Character.isWhitespace(code.charAt(i)) + || code.charAt(i) == ':' || code.charAt(i) == '.' + || Character.isJavaIdentifierPart(code.charAt(i)))) { + i++; + } + int probe = i; + while (probe < code.length() && Character.isWhitespace(code.charAt(probe))) { + probe++; + } + if (probe >= code.length()) { + return i; + } + char c = code.charAt(probe); + // Arguments, or a BRACKETED list: Kotlin lets one use-site target carry + // several annotations -- `@file:[JvmName("X") Suppress("unchecked")]` -- + // and stopping at the `[` read the bracket as the first declaration, so + // the import went between `@file:` and its own list. + if (c == '(') { + return balancedEnd(code, probe, '(', ')', at); + } + if (c == '[') { + return balancedEnd(code, probe, '[', ']', at); + } + return i; + } + + /// The offset just past the run opened at `from`, or `fallback` when it never + /// closes. Blanked code, so a delimiter inside a literal is already gone. + private static int balancedEnd(String code, int from, char open, char close, int fallback) { + int depth = 0; + for (int j = from; j < code.length(); j++) { + if (code.charAt(j) == open) { + depth++; + } else if (code.charAt(j) == close) { + depth--; + if (depth == 0) { + return j + 1; + } + } + } + return fallback; + } + + /// One thing this deliberately does NOT do: translate Java's unicode + /// escapes. `public cl\\u0061ss Main` is a legal spelling of the keyword + /// (written with two backslashes here because javac would translate a real + /// one even inside this comment), and + /// the processor-side reader decodes it -- so the source lookup accepts a + /// file this locator then cannot find a declaration in, and the goal refuses + /// with "Could not find the class declaration". + /// + /// That is the outcome we want from it. Every index here is written back + /// into the file as it is on disk, so decoding would need an offset map + /// threaded through the import scan, the package scan, the annotation walk + /// and the insertion itself -- and the failure being avoided is a refusal + /// that names what it could not do and changes nothing, on a spelling no + /// project writes. A migration that guessed an offset wrong would corrupt + /// the source instead. Refusing is the safe half of the trade. + static int classDeclarationIndex(String text, boolean kotlin, String simpleName) { + // Top level means brace depth zero, not column zero. Anchoring the + // pattern to the start of a line refused ` public class MyApp`, which + // compiles perfectly well -- so the goal rolled back with "Could not find + // the class declaration" on a project whose source it had just accepted + // through the token-aware lookup. + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(text, kotlin); + int first = -1; + int depth = 0; + int i = 0; + while (i < code.length()) { + int escaped = com.codename1.maven.processors.BuildHintAnnotationProcessor + .escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (c == '{') { + depth++; + i++; + continue; + } + if (c == '}') { + depth--; + i++; + continue; + } + if (depth != 0 || !Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < code.length() + && Character.isJavaIdentifierPart(code.charAt(wordEnd))) { + wordEnd++; + } + String word = code.substring(i, wordEnd); + if (isTypeKind(word, kotlin)) { + int n = wordEnd; + while (n < code.length() && Character.isWhitespace(code.charAt(n))) { + n++; + } + // Kotlin may ESCAPE the declared name in backticks, and + // codename1.mainName holds the name between them. Reading only + // identifier characters recorded nothing for `class `when``, so + // the goal reported "Could not find the class declaration" and + // rolled back a valid migration of a file it had just accepted. + int end = n; + String declared; + if (kotlin && n < code.length() && code.charAt(n) == '`') { + int close = code.indexOf('`', n + 1); + declared = close < 0 ? "" : code.substring(n + 1, close); + } else { + while (end < code.length() + && Character.isJavaIdentifierPart(code.charAt(end))) { + end++; + } + declared = code.substring(n, end); + } + if (declared.length() > 0) { + // The declaration's own modifiers come before the keyword, and + // the annotations have to go before those. + int start = startOfModifiers(code, i); + if (simpleName != null && simpleName.length() > 0 + && (declared.equals(simpleName) + || declared.equals(asWrittenInSource(simpleName)))) { + return start; + } + if (first < 0) { + first = start; + } + } + } + i = wordEnd; + } + return first; + } + + private static boolean isTypeKind(String word, boolean kotlin) { + if (kotlin) { + return "class".equals(word) || "object".equals(word) || "interface".equals(word); + } + return "class".equals(word) || "interface".equals(word) || "enum".equals(word) + || "record".equals(word); + } + + /// Back up over the modifiers preceding the keyword at `at`, so the + /// annotations land above `public final class` rather than inside it. + /// + /// Across any whitespace, newlines included. `public\nclass Main` is legal, + /// and stopping at the line break left `public` in the head -- so the + /// generated import was written after it, which is not valid Java, and the + /// verification build rolled back a migration that was otherwise correct. + /// Comments are already spaces here, since this runs on blanked code. + private static int startOfModifiers(String code, int at) { + int start = at; + while (true) { + int i = start - 1; + while (i >= 0 && Character.isWhitespace(code.charAt(i))) { + i--; + } + if (i < 0) { + return start; + } + int wordEnd = i + 1; + while (i >= 0 && (Character.isJavaIdentifierPart(code.charAt(i)) + || code.charAt(i) == '-')) { + i--; + } + String word = code.substring(i + 1, wordEnd); + if (word.length() == 0 || !isModifier(word)) { + return start; + } + start = i + 1; + } + } + + private static boolean isModifier(String word) { + String[] modifiers = {"public", "protected", "private", "abstract", "final", "static", + "strictfp", "sealed", "non-sealed", "internal", "open", "data", + "value", "annotation", "inner", "expect", "actual"}; + for (String m : modifiers) { + if (m.equals(word)) { + return true; + } + } + return false; + } + + /** + * Deletes the migrated lines, leaving every other line -- comments, + * ordering, unrelated settings -- byte for byte as it was. + */ + /** + * Deletes the migrated declarations, leaving every other line -- comments, + * ordering, unrelated settings -- byte for byte as it was. + * + *

Keys are recognised the way {@code Properties.load} defines them, not + * just {@code key=value}: {@code key:value} and {@code key value} are equally + * valid, and a line ending in an odd number of backslashes continues onto the + * next. A declaration this pass fails to recognise is left behind while the + * annotation is added, and the very next build fails with the duplicate-hint + * error this goal exists to avoid.

+ * + *

Written back as ISO-8859-1 because that is what {@code Properties.load} + * reads a {@code .properties} stream as. Rewriting the file as UTF-8 would + * turn any non-ASCII byte elsewhere in it -- an accented + * {@code codename1.displayName}, say -- into mojibake, even though it has + * nothing to do with the hint being migrated.

+ */ + static void removeMigratedLines(File settingsFile, List keys) throws IOException { + // Each entry keeps its own terminator. readLine() discards it, and + // appending '\n' to every retained line rewrote a CRLF checkout end to + // end -- a whole-file diff from a goal that promises to delete some + // lines and touch nothing else, and one this repository has been bitten + // by before. + List lines = physicalLines(readAll(settingsFile)); + + Map wanted = new LinkedHashMap(); + for (String k : keys) { + wanted.put(k, Boolean.TRUE); + } + + StringBuilder out = new StringBuilder(); + for (int i = 0; i < lines.size(); i++) { + // Gather the whole logical line: continuations belong to the same + // declaration and have to go with it. + int last = i; + StringBuilder logical = new StringBuilder(withoutTerminator(lines.get(i))); + // A COMMENT is a natural line: continuation does not apply to it, so + // `# note \` ends at the newline and the declaration below it is an + // ordinary property. Joining the two made the pair read as a + // comment, so the migrated declaration was retained and the + // verification build failed on the duplicate. + boolean comment = isCommentLine(logical.toString()); + while (!comment && continues(withoutTerminator(lines.get(last))) + && last + 1 < lines.size()) { + // The continuation backslash is a MARKER, not part of the value: + // Properties.load drops it, so leaving it in made + // `codename1.arg.ios.teamId\` + ` =ABCDE` read as an escaped `=` + // and the key never matched the one being migrated. The + // declaration stayed behind, and the verification build then + // failed on the duplicate the goal had just created. + logical.setLength(logical.length() - 1); + last++; + logical.append(withoutTerminator(lines.get(last)).replaceFirst("^\\s+", "")); + } + // A marker with nothing after it is still a marker: a file whose + // last byte is that backslash reads as an empty value to + // Properties.load, while leaving it in produced a key ending in `\` + // that matched nothing -- so the declaration stayed and the + // verification build failed on the duplicate. + if (!comment && continues(logical.toString())) { + logical.setLength(logical.length() - 1); + } + String key = propertyKeyOf(logical.toString()); + if (key != null && wanted.containsKey(key)) { + i = last; + continue; + } + for (int j = i; j <= last; j++) { + out.append(lines.get(j)); + } + i = last; + } + writeProperties(settingsFile, out.toString()); + } + + /** The whole file, as the encoding {@code Properties.load} would use. */ + private static String readAll(File f) throws IOException { + Reader r = new InputStreamReader(new FileInputStream(f), PROPERTIES_ENCODING); + try { + StringBuilder sb = new StringBuilder(); + char[] buf = new char[8192]; + for (int n = r.read(buf); n > 0; n = r.read(buf)) { + sb.append(buf, 0, n); + } + return sb.toString(); + } finally { + r.close(); + } + } + + /** + * The physical lines of {@code text}, each WITH the terminator it ended on. + * + *

All three of CRLF, LF and CR end a line for {@code Properties.load}, and + * a file need not end with one at all -- so the terminators travel with their + * lines rather than being normalised away and guessed at on the way out.

+ */ + private static List physicalLines(String text) { + List out = new ArrayList(); + int start = 0; + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (c != '\n' && c != '\r') { + continue; + } + int end = i + 1; + if (c == '\r' && end < text.length() && text.charAt(end) == '\n') { + end++; + } + out.add(text.substring(start, end)); + start = end; + i = end - 1; + } + if (start < text.length()) { + out.add(text.substring(start)); + } + return out; + } + + /** That line without its terminator, which is what the parsing reads. */ + private static String withoutTerminator(String line) { + int end = line.length(); + if (end > 0 && line.charAt(end - 1) == '\n') { + end--; + } + if (end > 0 && line.charAt(end - 1) == '\r') { + end--; + } + return line.substring(0, end); + } + + /** Whether the line is a comment, which continuation does not apply to. */ + private static boolean isCommentLine(String line) { + int i = 0; + while (i < line.length() && isPropertySpace(line.charAt(i))) { + i++; + } + return i < line.length() && (line.charAt(i) == '#' || line.charAt(i) == '!'); + } + + /** Whether a physical line ends in an odd number of backslashes. */ + private static boolean continues(String line) { + int backslashes = 0; + for (int i = line.length() - 1; i >= 0 && line.charAt(i) == '\\'; i--) { + backslashes++; + } + return backslashes % 2 != 0; + } + + /** + * The key a logical properties line declares, or null when the line is blank + * or a comment. + * + *

Follows {@code java.util.Properties}: the key runs to the first + * unescaped {@code =}, {@code :} or whitespace, and {@code \}{@code uXXXX} + * decodes to the character it names. The escape matters because the key this + * returns is compared against one {@code Properties.load} produced: a file + * writing {@code codename1.arg.\}{@code u0069os.teamId} declares + * {@code ios.teamId}, and reading it as {@code u0069os.teamId} leaves the + * original line in place, so the migration rolls back over a duplicate + * declaration it created itself.

+ */ + static String propertyKeyOf(String logicalLine) { + int i = 0; + while (i < logicalLine.length() && isPropertySpace(logicalLine.charAt(i))) { + i++; + } + if (i >= logicalLine.length()) { + return null; + } + char first = logicalLine.charAt(i); + if (first == '#' || first == '!') { + return null; + } + StringBuilder key = new StringBuilder(); + for (; i < logicalLine.length(); i++) { + char c = logicalLine.charAt(i); + if (c == '\\' && i + 1 < logicalLine.length()) { + char escaped = logicalLine.charAt(++i); + if (escaped == 'u' && i + 4 < logicalLine.length()) { + String hex = logicalLine.substring(i + 1, i + 5); + int value = hexValue(hex); + if (value >= 0) { + key.append((char) value); + i += 4; + continue; + } + } + key.append(escaped); + continue; + } + if (c == '=' || c == ':' || isPropertySpace(c)) { + break; + } + key.append(c); + } + return key.length() == 0 ? null : key.toString(); + } + + private static boolean isPropertySpace(char c) { + return c == ' ' || c == '\t' || c == '\f'; + } + + /** Four hex digits as a char value, or -1 when they are not four hex digits. */ + private static int hexValue(String hex) { + int value = 0; + for (int i = 0; i < hex.length(); i++) { + int digit = Character.digit(hex.charAt(i), 16); + if (digit < 0) { + return -1; + } + value = value * 16 + digit; + } + return value; + } + + /** The encoding {@code Properties.load(InputStream)} reads. */ + private static final String PROPERTIES_ENCODING = "ISO-8859-1"; + + private static void writeProperties(File f, String content) throws IOException { + Writer w = new OutputStreamWriter(new FileOutputStream(f), PROPERTIES_ENCODING); + try { + w.write(content); + } finally { + w.close(); + } + } + + /** + * Reads a properties file as ISO-8859-1, matching {@link #writeProperties}. + * + *

The rollback snapshot has to round-trip byte for byte. Taking it through + * the UTF-8 {@link #read} and restoring it with the ISO-8859-1 writer would + * mangle any raw high byte in an unrelated property -- an accented + * {@code codename1.displayName}, say -- while the goal reports that both + * files were put back as they were.

+ */ + private static String readProperties(File f) throws IOException { + return read(f, PROPERTIES_ENCODING); + } + + /** + * Reads a source file byte-transparently. + * + *

ISO-8859-1 maps every byte 0-255 to the same char, so decoding with it, + * splicing in text that is pure ASCII, and encoding back reproduces the + * original bytes exactly -- whatever the project's real source encoding is. + * Hard-coding UTF-8 here reinterpreted the whole file, so a raw byte in a + * comment or a string literal came back changed even when the migration + * succeeded, and reading {@code project.build.sourceEncoding} would only + * narrow that to projects that declare it correctly.

+ * + *

The markers this class searches for -- {@code package}, {@code import}, + * the class declaration -- are ASCII, and every ASCII-compatible encoding + * decodes them identically under this scheme.

+ */ + private static String read(File f) throws IOException { + return read(f, SOURCE_BYTE_TRANSPARENT_ENCODING); + } + + /** See {@link #read(File)}: byte-transparent, not a claim about the file. */ + private static final String SOURCE_BYTE_TRANSPARENT_ENCODING = "ISO-8859-1"; + + private static String read(File f, String encoding) throws IOException { + StringBuilder sb = new StringBuilder(); + BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(f), encoding)); + try { + int c; + while ((c = r.read()) >= 0) { + sb.append((char) c); + } + } finally { + r.close(); + } + return sb.toString(); + } + + /** Restores a source file after a failed migration. */ + private static void writeSource(File f, String content) throws IOException { + write(f, content); + } + + private static void write(File f, String content) throws IOException { + Writer w = new OutputStreamWriter(new FileOutputStream(f), SOURCE_BYTE_TRANSPARENT_ENCODING); + try { + w.write(content); + } finally { + w.close(); + } + } +} diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/OpenSettingsMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/OpenSettingsMojo.java index 3e8e426c683..f4f39319f84 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/OpenSettingsMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/OpenSettingsMojo.java @@ -40,6 +40,9 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; + +import org.apache.maven.execution.MavenSession; +import org.apache.maven.project.MavenProject; import java.util.UUID; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -231,13 +234,25 @@ File extractSettingsIcon(File jar, File runtimeDir) { void writeBinding(File inputFile, File projectDir) throws MojoExecutionException { File root = multimoduleRoot(projectDir); - File buildHints = new File(root, "docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc"); + // No buildHintsDoc: the Settings tool used to scrape the developer guide's + // AsciiDoc table at runtime and guess each hint's type from its description + // prose. It now reads com.codename1.build.shared.BuildHints, the same table + // the build hint annotations are generated from. String content = "# Codename One Settings project binding\n" + "projectDir=" + projectDir.getAbsolutePath() + "\n" + "settings=" + new File(projectDir, "codenameone_settings.properties").getAbsolutePath() + "\n" + "pom=" + new File(projectDir, "pom.xml").getAbsolutePath() + "\n" + "multimoduleRoot=" + root.getAbsolutePath() + "\n" - + (buildHints.isFile() ? "buildHintsDoc=" + buildHints.getAbsolutePath() + "\n" : ""); + // What Maven RESOLVED, so the tool does not have to infer it + // from POM text. It has no model: it cannot evaluate a profile + // activation, follow an inherited or expand a + // property, and every one of those has been a way for it to miss + // the main class and then offer an annotation-owned hint for + // editing. Its own reading stays as the fallback for a Settings + // launched without these -- an older plugin, or the standalone + // app. + + bindingList("sourceRoots", compileSourceRoots(moduleAt(projectDir))) + + bindingValue("sourceEncoding", sourceEncodingOf(moduleAt(projectDir))); try { FileUtils.write(inputFile, content, StandardCharsets.UTF_8); } catch (IOException ex) { @@ -245,6 +260,125 @@ void writeBinding(File inputFile, File projectDir) throws MojoExecutionException } } + /// The reactor module whose directory is `projectDir`, or the project being + /// built when the reactor has no such module. + /// + /// `cn1:settings` is normally run from the root of a multi-module project + /// while the module being EDITED is common, so the project in scope is not + /// the one whose sources matter. + private MavenProject moduleAt(File projectDir) { + if (projectDir == null) { + return project; + } + MavenSession session = getSession(); + List projects = session == null ? null : session.getProjects(); + if (projects != null) { + for (MavenProject candidate : projects) { + File basedir = candidate.getBasedir(); + if (basedir != null + && basedir.getAbsolutePath().equals(projectDir.getAbsolutePath())) { + return candidate; + } + } + } + return project; + } + + /// The source encoding Maven resolved for `module`, or null. + private static String sourceEncodingOf(MavenProject module) { + if (module == null) { + return null; + } + String encoding = null; + if (module.getProperties() != null) { + encoding = module.getProperties().getProperty("project.build.sourceEncoding"); + if (encoding == null) { + encoding = module.getProperties().getProperty("maven.compiler.encoding"); + } + } + if (encoding == null || encoding.trim().isEmpty()) { + // Configured on the plugin rather than as a property. Maven does not + // copy a plugin parameter into the project's properties, so a POM + // that sets inside maven-compiler-plugin -- in a profile, + // say -- published nothing here and left the tool guessing. + encoding = compilerPluginEncoding(module); + } + return encoding == null || encoding.trim().isEmpty() ? null : encoding.trim(); + } + + /// The `` maven-compiler-plugin is configured with, from the + /// EFFECTIVE model -- so a profile that Maven activated is already folded in. + private static String compilerPluginEncoding(MavenProject module) { + List plugins; + try { + plugins = module.getBuildPlugins(); + } catch (RuntimeException ex) { + return null; + } + if (plugins == null) { + return null; + } + for (org.apache.maven.model.Plugin plugin : plugins) { + if (!"maven-compiler-plugin".equals(plugin.getArtifactId())) { + continue; + } + String fromPlugin = encodingIn(plugin.getConfiguration()); + if (fromPlugin != null) { + return fromPlugin; + } + if (plugin.getExecutions() == null) { + continue; + } + for (org.apache.maven.model.PluginExecution execution : plugin.getExecutions()) { + // The main compilation's, not testCompile's. + if (execution.getGoals() != null && execution.getGoals().contains("compile")) { + String fromExecution = encodingIn(execution.getConfiguration()); + if (fromExecution != null) { + return fromExecution; + } + } + } + } + return null; + } + + private static String encodingIn(Object configuration) { + if (!(configuration instanceof org.codehaus.plexus.util.xml.Xpp3Dom)) { + return null; + } + org.codehaus.plexus.util.xml.Xpp3Dom encoding = + ((org.codehaus.plexus.util.xml.Xpp3Dom) configuration).getChild("encoding"); + if (encoding == null || encoding.getValue() == null) { + return null; + } + String value = encoding.getValue().trim(); + // An unexpanded ${property} is not an encoding. + return value.isEmpty() || value.indexOf('$') >= 0 ? null : value; + } + + private static String bindingValue(String key, String value) { + return value == null ? "" : key + "=" + value + "\n"; + } + + private static String bindingList(String key, List values) { + if (values == null || values.isEmpty()) { + return ""; + } + StringBuilder joined = new StringBuilder(); + for (String value : values) { + if (value == null || value.trim().isEmpty()) { + continue; + } + if (joined.length() > 0) { + // A path separator, since these are paths and a comma is legal + // in a directory name. + joined.append(File.pathSeparatorChar); + } + joined.append(value.trim()); + } + return joined.length() == 0 ? "" : key + "=" + joined + "\n"; + } + File multimoduleRoot(File projectDir) { File parent = projectDir == null ? null : projectDir.getParentFile(); if (parent != null && "common".equals(projectDir.getName())) { diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/ProcessAnnotationsMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/ProcessAnnotationsMojo.java index c7829d15e5a..b06d16d00db 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/ProcessAnnotationsMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/ProcessAnnotationsMojo.java @@ -35,13 +35,16 @@ import org.apache.maven.plugins.annotations.Parameter; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.ServiceLoader; import java.util.Set; @@ -103,7 +106,11 @@ protected void executeImpl() throws MojoExecutionException, MojoFailureException } ProcessorContext ctx = new ProcessorContext(outputDirectory, stubSourceDirectory, - index, getLog()); + index, getLog(), getCN1ProjectDir(), rawProjectSettings(), mainClassBinaryName(), + // The roots Maven is actually compiling, so a processor asking + // whether a class still has a source is not guessing at the + // layout. + compileSourceRoots(project)); // start() for (Iterator it = processors.iterator(); it.hasNext(); ) { @@ -219,6 +226,21 @@ protected void executeImpl() throws MojoExecutionException, MojoFailureException getLog().info("cn1: emitted " + resources.size() + " generated resource(s) under " + outputDirectory); } + + // The build hint manifest records the main class's own bytes so the + // simulator, which has no bytecode reader, can tell a current manifest + // from one an earlier build left behind. A processor may REPLACE that + // class through emitClass -- BindingAnnotationProcessor does, for a + // two-way @Bindable setter -- and those are flushed above, after every + // finish(). So the stamp is corrected here, which is the first moment + // the class on disk is final. A no-op when there is no manifest. + try { + com.codename1.maven.processors.BuildHintAnnotationProcessor + .restampClassDigest(outputDirectory); + } catch (IOException ioe) { + throw new MojoExecutionException( + "Could not stamp the build hint manifest under " + outputDirectory, ioe); + } } private static boolean intersects(Set a, Set b) { @@ -238,4 +260,55 @@ private List loadProcessors() { for (AnnotationProcessor p : sl) out.add(p); return Collections.unmodifiableList(out); } + + /// Loads `codenameone_settings.properties` exactly as it sits on disk. + /// + /// Deliberately not the inherited `properties` field: that one has the + /// `-D` command line overlaid on top of it, and a hint passed with `-D` is + /// the documented way to override one for a single build. A processor that + /// compared annotations against the overlaid view would report a conflict + /// for the one case that is supposed to win. + private Properties rawProjectSettings() { + File f = getProjectPropertiesFile(); + if (f == null || !f.exists()) { + return null; + } + Properties p = new Properties(); + InputStream in = null; + try { + in = new FileInputStream(f); + p.load(in); + } catch (IOException ex) { + getLog().warn("cn1: could not read " + f + ": " + ex.getMessage()); + return null; + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ignored) { + // nothing useful to do on close failure of a read-only stream + } + } + } + return p; + } + + /// `codename1.packageName` + `codename1.mainName`, or null when the project + /// declares no main class. + private String mainClassBinaryName() { + Properties p = rawProjectSettings(); + if (p == null) { + return null; + } + String main = p.getProperty("codename1.mainName"); + String pkg = p.getProperty("codename1.packageName"); + if (main == null || main.trim().length() == 0) { + return null; + } + main = main.trim(); + if (pkg == null || pkg.trim().length() == 0) { + return main; + } + return pkg.trim() + "." + main; + } } diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/AnnotatedClass.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/AnnotatedClass.java index acb914cb5cd..920be84baa6 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/AnnotatedClass.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/AnnotatedClass.java @@ -42,6 +42,7 @@ public final class AnnotatedClass { private final String internalName; + private String sourceFile; private final String superInternalName; private final List interfaceInternalNames; private final int access; @@ -106,6 +107,17 @@ private static Set collectAllDescriptors( } /// JVM internal name (`com/example/ProfileForm`). + /// The source file name the compiler recorded, or null when the class was + /// compiled without debug information. + /// + /// The name only, never a path. It is the one reliable link back from a + /// class to its source: Kotlin lets a file's name and directory differ from + /// the class it declares, so deriving the file from the class name is a + /// guess and this is not. + public String getSourceFile() { return sourceFile; } + + void setSourceFile(String sourceFile) { this.sourceFile = sourceFile; } + public String getInternalName() { return internalName; } /// Dotted binary name (`com.example.ProfileForm`). diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ClassScanner.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ClassScanner.java index 427b71fc4a2..a823b7d99e2 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ClassScanner.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ClassScanner.java @@ -43,8 +43,15 @@ /// Walks a directory of compiled `.class` files and produces the /// `AnnotatedClass` index passed to processors. /// -/// Uses ASM's `ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | -/// ClassReader.SKIP_FRAMES` flags — we only care about declarations +/// Uses ASM's `ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES` flags — we only +/// care about declarations. +/// +/// NOT `SKIP_DEBUG`, which also suppresses `visitSource` and so the SourceFile +/// attribute. That attribute is the only reliable link from a compiled class +/// back to the file that declared it — Kotlin does not require the two to share +/// a name — and skipping it made every caller of `getSourceFile()` see null and +/// silently take its "cannot tell" branch. With SKIP_CODE already set there are +/// no method bodies to walk, so what this costs is parsing one string per class /// (annotations, signatures), never method bodies. This keeps scanning fast /// even on large projects. /// @@ -118,7 +125,7 @@ public static AnnotatedClass readClass(InputStream in, File source) throws Proce try { ClassReader reader = new ClassReader(in); Collector c = new Collector(source); - reader.accept(c, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + reader.accept(c, ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); return c.build(); } catch (IOException e) { throw new ProcessingException("Could not read class from " + source + ": " + e.getMessage(), e); @@ -147,11 +154,23 @@ private static final class Collector extends ClassVisitor { } AnnotatedClass build() { - return new AnnotatedClass( + AnnotatedClass out = new AnnotatedClass( internalName, superInternalName, interfaces, access, classAnnotations, methods, fields, source); + out.setSourceFile(sourceFile); + return out; } + /// The SourceFile attribute, which is the only reliable link from a + /// compiled class back to the file that declared it -- Kotlin does not + /// require the two to share a name. + @Override + public void visitSource(String sourceFileName, String debug) { + this.sourceFile = sourceFileName; + } + + private String sourceFile; + @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfacesArr) { diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ProcessorContext.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ProcessorContext.java index 7eb35bec52a..e67bb168a65 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ProcessorContext.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/annotations/ProcessorContext.java @@ -28,6 +28,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import org.apache.maven.plugin.logging.Log; @@ -45,6 +46,9 @@ /// - A **stub source directory** in `target/generated-sources/cn1-annotations` /// used by the GENERATE_SOURCES Mojo; the PROCESS_CLASSES path doesn't write /// to it but the directory may exist either way. +/// - The **project settings** exactly as `codenameone_settings.properties` +/// holds them, plus the main class those settings name. A processor that +/// validates against project configuration needs both. public final class ProcessorContext { private final File outputClassDir; @@ -55,17 +59,73 @@ public final class ProcessorContext { private final Map emittedClasses = new LinkedHashMap(); private final Map emittedStubSources = new LinkedHashMap(); private final Map emittedResources = new LinkedHashMap(); + private final File projectDir; + private final Properties projectSettings; + private final String mainClassBinaryName; + private final List compileSourceRoots; public ProcessorContext(File outputClassDir, File stubSourceDir, Map classIndex, Log log) { + this(outputClassDir, stubSourceDir, classIndex, log, null, null, null); + } + + /// Full form, adding the project configuration. + /// + /// `projectSettings` must be the **raw** contents of + /// `codenameone_settings.properties`, without any `-D` overlay: a hint given + /// on the command line is the documented way to override one for a single + /// build, so it must never be mistaken for something the project declares. + public ProcessorContext(File outputClassDir, File stubSourceDir, + Map classIndex, Log log, + File projectDir, Properties projectSettings, + String mainClassBinaryName) { + this(outputClassDir, stubSourceDir, classIndex, log, projectDir, projectSettings, + mainClassBinaryName, null); + } + + /// Adds the module's configured compile source roots. + /// + /// Passed in rather than guessed at from the project directory: a module may + /// add `generated-sources`, or a Kotlin root, or replace the conventional one + /// altogether, and a processor that assumes `src/main/java` would decide a + /// perfectly live class has no source. + public ProcessorContext(File outputClassDir, File stubSourceDir, + Map classIndex, Log log, + File projectDir, Properties projectSettings, + String mainClassBinaryName, List compileSourceRoots) { this.outputClassDir = outputClassDir; this.stubSourceDir = stubSourceDir; this.classIndex = classIndex == null ? Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap(classIndex)); this.log = log; + this.projectDir = projectDir; + this.projectSettings = projectSettings; + this.mainClassBinaryName = mainClassBinaryName; + this.compileSourceRoots = compileSourceRoots == null + ? Collections.emptyList() + : Collections.unmodifiableList(new ArrayList(compileSourceRoots)); } + /// The module's configured compile source roots, empty when unknown. + /// + /// Empty means "not told", never "there are none": a caller deciding whether + /// a class still has a source has to treat the two differently, or an + /// unfamiliar layout looks exactly like a deleted file. + public List getCompileSourceRoots() { return compileSourceRoots; } + + /// The Codename One project directory -- the one holding + /// `codenameone_settings.properties` -- or null when it could not be found. + public File getProjectDir() { return projectDir; } + + /// The raw `codenameone_settings.properties`, or null when absent. Never + /// carries a `-D` overlay; see the constructor. + public Properties getProjectSettings() { return projectSettings; } + + /// Fully qualified name of the class named by `codename1.mainName`, or null + /// when the project does not declare one (a cn1lib, for instance). + public String getMainClassBinaryName() { return mainClassBinaryName; } + /// `target/classes` for the project, or the equivalent output directory. public File getOutputClassDir() { return outputClassDir; } diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/processors/BuildHintAnnotationProcessor.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/processors/BuildHintAnnotationProcessor.java new file mode 100644 index 00000000000..22f15e95ee4 --- /dev/null +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/processors/BuildHintAnnotationProcessor.java @@ -0,0 +1,1844 @@ +/* + * Copyright (c) 2012, 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.codename1.maven.processors; + +import com.codename1.build.shared.BuildHintAnnotationBinding; +import com.codename1.build.shared.BuildHints; +import com.codename1.maven.annotations.AbstractAnnotationProcessor; +import com.codename1.maven.annotations.AnnotatedClass; +import com.codename1.maven.annotations.AnnotationValues; +import com.codename1.maven.annotations.ProcessingException; +import com.codename1.maven.annotations.ProcessorContext; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeMap; + +/// Turns the `com.codename1.annotations.buildhints` annotations into the +/// `codename1.arg.*` key/value pairs the builders already consume. +/// +/// A build hint used to be a properties line that nothing checked, so a +/// misspelled name reached the build request, was never read, and was silently +/// dropped -- a green build with the setting simply not applied. Written as an +/// annotation the compiler catches the same mistake, and this processor is what +/// turns the checked form back into the wire form. +/// +/// The result is written to `META-INF/codenameone/build-hints.properties` in +/// `target/classes`, which puts it both on the simulator's classpath and inside +/// the jar uploaded to the build server. +public class BuildHintAnnotationProcessor extends AbstractAnnotationProcessor { + + /// Where the emitted hints land. Read by `CN1BuildMojo` before it writes the + /// build request, and by `Simulator` on startup. + public static final String MANIFEST_RESOURCE = "META-INF/codenameone/build-hints.properties"; + + /// Records which annotation attribute supplied each hint, so a later stage + /// -- the conflict message, the simulator's hint editor -- can name it. + private static final String ORIGIN_PREFIX = "cn1.buildHints.origin."; + + /// Other names for the same setting, for a consumer that cannot reach the + /// catalog to resolve an alias itself. + private static final String ALIAS_PREFIX = "cn1.buildHints.alias."; + + /// Stamps the emitted file with the main class it came from, so a stale or + /// foreign copy on the classpath can be recognised rather than merged. + private static final String MAIN_CLASS_KEY = "cn1.buildHints.mainClass"; + + /// Digest of the annotations this file was generated from. + /// + /// The main-class stamp only says *which* class produced it, which is the + /// same class an out-of-date copy names. Nothing removes `target/classes` + /// between builds, so a project that ran this processor once and then stopped + /// -- the goal unbound, skipped, or bound to a phase that no longer runs -- + /// keeps a manifest that looks entirely valid while the annotations beside it + /// have moved on. Recording what it was built from lets the consumer compare + /// it against the class file actually on the classpath and refuse instead of + /// shipping last week's configuration. + public static final String SOURCE_DIGEST_KEY = "cn1.buildHints.sourceDigest"; + + /// The compiled main class's own bytes, for a consumer that cannot read + /// bytecode. + /// + /// The simulator lives in the JavaSE port and has no bytecode reader, so it + /// cannot recompute [#SOURCE_DIGEST_KEY] and was left comparing file + /// timestamps. Those are not always available to compare: a jar records + /// entry times to two-second granularity, and a build configured for + /// reproducible output stamps every entry identically -- which makes the + /// comparison inert rather than merely coarse, so a manifest left behind by + /// an earlier build reads as current and the simulator runs the previous + /// values of hints it can actually see. Hashing the class file needs no + /// bytecode reader at all. + public static final String CLASS_DIGEST_KEY = "cn1.buildHints.classDigest"; + + /// hint name to value, sorted so the emitted bytes are stable. + private final Map hints = new TreeMap(); + /// hint name to "@Ios(pods)". + private final Map origins = new TreeMap(); + /// Classes carrying a build hint annotation, in discovery order. + private final List annotated = new ArrayList(); + + @Override + public Set getAnnotationDescriptors() { + return new LinkedHashSet(BuildHintAnnotationBinding.descriptors()); + } + + @Override + public void start(ProcessorContext ctx) throws ProcessingException { + hints.clear(); + origins.clear(); + annotated.clear(); + } + + @Override + public void processClass(AnnotatedClass cls, ProcessorContext ctx) throws ProcessingException { + Set descriptors = getAnnotationDescriptors(); + + // @Target(TYPE) already rejects a method or field placement at compile + // time, but @Target is a front-end check and this reads bytecode: a + // class produced another way could still carry one, and silently + // ignoring it would be the exact failure this feature removes. + for (String d : cls.getAllAnnotationDescriptors()) { + if (descriptors.contains(d) && !cls.getClassAnnotations().containsKey(d)) { + ctx.error(cls, "@" + simpleName(d) + " is a build hint annotation and belongs on " + + "the class itself, not on one of its members."); + } + } + + boolean carriesAny = false; + for (Map.Entry e : cls.getClassAnnotations().entrySet()) { + if (descriptors.contains(e.getKey())) { + carriesAny = true; + } + } + if (!carriesAny) { + return; + } + // An output directory keeps class files whose source is gone. Rename the + // main class, update codename1.mainName and skip the clean, and the old + // annotated .class is still sitting there -- so every incremental build + // failed with a placement error naming a class the developer had already + // deleted, and the orphan's hints were merged in besides. + // + // Only a class that is NOT the main one is dropped this way. The main + // class is processed whatever its source layout, because failing to find + // its source would otherwise mean silently applying none of its hints, + // which is worse than any placement message. + if (!isMainClass(cls, ctx) && !hasBackingSource(cls, ctx)) { + ctx.getLog().debug("cn1: ignoring " + cls.getBinaryName() + + " -- annotated, but no source for it; stale output from an earlier build"); + return; + } + annotated.add(cls); + + for (Map.Entry e : cls.getClassAnnotations().entrySet()) { + String descriptor = e.getKey(); + if (!descriptors.contains(descriptor)) { + continue; + } + AnnotationValues values = e.getValue(); + // Only what the developer actually wrote: javac omits a member left + // at its default from the class file, and that absence is how an + // unset attribute is distinguished from one set to the default + // value. Reading through a getXxxOrDefault here would write a hint + // for every attribute of every annotation used. + for (Map.Entry member : values.all().entrySet()) { + String hint = BuildHintAnnotationBinding.hintFor(descriptor, member.getKey()); + if (hint == null) { + ctx.error(cls, "@" + simpleName(descriptor) + "(" + member.getKey() + + ") is not a known build hint. The catalog and the annotation " + + "have drifted; regenerate with " + + "scripts/gen-build-hint-annotations.sh."); + continue; + } + String value = wireValue(cls, descriptor, member.getKey(), member.getValue(), + hint, ctx); + if (value == null) { + continue; + } + String origin = "@" + simpleName(descriptor) + "(" + member.getKey() + ")"; + String previous = hints.put(hint, value); + if (previous != null && !previous.equals(value)) { + ctx.error(cls, "Build hint " + hint + " is set twice with different values: " + + origins.get(hint) + " and " + origin + "."); + } + origins.put(hint, origin); + } + } + } + + @Override + public void finish(ProcessorContext ctx) throws ProcessingException { + if (annotated.isEmpty()) { + // The last annotation was removed. The Mojo only writes emitted + // resources, it never deletes ones a processor stopped emitting, so + // without this yesterday's hints would stay in target/classes and + // ship inside the jar. + deleteGenerated(ctx); + return; + } + checkPlacement(ctx); + checkConflicts(ctx); + if (ctx.hasErrors()) { + return; + } + ctx.emitResource(MANIFEST_RESOURCE, serialize(ctx)); + ctx.getLog().info("cn1: " + hints.size() + " build hint(s) from annotations on " + + annotated.get(0).getBinaryName()); + } + + private static boolean isMainClass(AnnotatedClass cls, ProcessorContext ctx) { + String main = ctx.getMainClassBinaryName(); + return main != null && main.equals(cls.getBinaryName()); + } + + /// Whether a source file for `cls` still exists under the module. + /// + /// Answered "yes" whenever the question cannot actually be put, because the + /// only thing this decides is whether to IGNORE an annotated class, and + /// ignoring a live one applies none of its hints and reports nothing. Only a + /// class this can positively show has no source is treated as an orphan. + /// + /// Searched by the file name the compiler recorded, anywhere under the + /// module's configured source roots, rather than by the package path. Both + /// halves matter: a module may add `generated-sources` or replace + /// `src/main/java` outright, and Kotlin lets a file's name and directory + /// differ from the class it declares, so a package-path lookup would call a + /// perfectly live class orphaned. + private static boolean hasBackingSource(AnnotatedClass cls, ProcessorContext ctx) { + return hasBackingSource(cls, ctx.getCompileSourceRoots()); + } + + /// As above, for a caller that has the roots but no ProcessorContext. + public static boolean hasBackingSource(AnnotatedClass cls, List compileSourceRoots) { + List roots = compileSourceRoots; + if (roots == null || roots.isEmpty()) { + return true; + } + String sourceFile = cls.getSourceFile(); + if (sourceFile == null || sourceFile.length() == 0) { + // Compiled without debug information; nothing to look for. + return true; + } + String pkg = packageOf(cls.getBinaryName()); + String simpleName = simpleNameOf(cls.getBinaryName()); + String[] nestedName = nestedNameOf(cls.getBinaryName()); + // The name with its dollars intact. `$` is a legal character in a Java + // type name, so a top-level `class Wrong$Type` has binary name + // Wrong$Type and is not nested at all -- reading every `$` as nesting + // looked for a `Wrong` that does not exist, dropped the live class as an + // orphan, and lost the placement error it should have raised. + int lastDot = cls.getBinaryName().lastIndexOf('.'); + String wholeName = lastDot < 0 ? cls.getBinaryName() + : cls.getBinaryName().substring(lastDot + 1); + boolean sawARoot = false; + for (String root : roots) { + File dir = new File(root); + if (!dir.isDirectory()) { + continue; + } + sawARoot = true; + if (declaresPackage(dir, sourceFile, pkg, simpleName, nestedName, wholeName, 0)) { + return true; + } + } + return !sawARoot; + } + + private static String packageOf(String binaryName) { + int dot = binaryName.lastIndexOf('.'); + return dot < 0 ? "" : binaryName.substring(0, dot); + } + + /// The OUTERMOST simple name, so a nested type is looked for by the type its + /// file actually declares. + /// + /// A nested class's binary name is Main$Wrong, and no source declares a type + /// spelled that way -- searching for it found nothing, the class was read as + /// an orphan and dropped, and the placement check that would have said + /// "annotations belong on the main class" never ran. The build then succeeded + /// with the requested hints silently absent, which is the failure this whole + /// feature exists to remove. + private static String simpleNameOf(String binaryName) { + int dot = binaryName.lastIndexOf('.'); + String simple = dot < 0 ? binaryName : binaryName.substring(dot + 1); + int nested = simple.indexOf('$'); + return nested < 0 ? simple : simple.substring(0, nested); + } + + /// How deep the source tree is walked before the answer is given up on. + /// + /// Generous rather than tight: a package with this many components is not + /// something anyone writes, and the cost of guessing wrong is a live class + /// dropped without a word. + private static final int MAX_SOURCE_TREE_DEPTH = 64; + + /// Whether a file called `name` declaring package `pkg` exists under `dir`. + /// + /// The package matters as well as the name: moving a class to another package + /// without a clean leaves an orphan whose SourceFile is, say, App.java, and + /// the NEW App.java would otherwise answer for it -- so the stale class stays + /// and fails the placement check on every incremental build, which is the bug + /// this whole guard exists to prevent. + /// + /// The package is read from the file rather than inferred from its directory, + /// because Kotlin does not require the two to agree. Depth-limited: this runs + /// per annotated class and a source tree is not a search index. + private static boolean declaresPackage(File dir, String name, String pkg, String simple, + String[] nested, String whole, int depth) { + if (depth > MAX_SOURCE_TREE_DEPTH) { + // Out of budget is "cannot tell", not "no such source". Answering no + // here dropped a live annotated class -- silently, and with its + // placement error lost -- for the sake of a search bound, which is + // the wrong way round: everywhere else in this walk an unanswerable + // question keeps the class, because the only thing it decides is + // whether to IGNORE an annotation. + return true; + } + File[] children = dir.listFiles(); + if (children == null) { + return false; + } + for (File f : children) { + if (f.isFile()) { + if (f.getName().equals(name) && matches(f, pkg, simple, nested, whole)) { + return true; + } + } else if (f.isDirectory() + && declaresPackage(f, name, pkg, simple, nested, whole, depth + 1)) { + return true; + } + } + return false; + } + + /// Whether `f` declares type `simple` in package `pkg`. + /// + /// The declaration is checked, not just the file's name and package. Kotlin + /// lets a class be renamed without renaming its file, and one file can hold + /// several types, so the surviving source would otherwise answer for the + /// class that used to be in it -- keeping a stale annotation owner and + /// failing the placement check on every incremental build, which is the very + /// thing this guard was added to stop. + private static boolean matches(File f, String pkg, String simple, String[] nested, + String whole) { + String text = readHead(f); + if (text == null) { + // Unreadable: answer yes, as everywhere else here, because the only + // thing this decides is whether to IGNORE an annotated class. + return true; + } + // The file names its own language, and a triple-quoted literal is read + // differently in each. + boolean kotlin = f.getName().endsWith(".kt"); + // Java translates unicode escapes before tokenizing, so this has to as + // well or `package com.ex\u0061mple;` reads as com.ex. Only the answers + // below depend on the text, never an offset into the file. + if (!kotlin) { + text = decodeUnicodeEscapes(text); + } + String declaredPkg = declaredPackageIn(text, kotlin); + if (!pkg.equals(declaredPkg)) { + // A name outside ASCII cannot be judged without the compiler's + // source encoding, which this scan cannot see -- so a mismatch + // involving one is "cannot tell", not "somewhere else". Concluding + // otherwise dropped a live annotated class and lost its placement + // error, which is the failure this whole guard exists to prevent. + return !isAscii(pkg) || !isAscii(declaredPkg); + } + // The name as spelled, before it is read as a nesting path: `$` is legal + // in a Java type name, so a top-level `class Wrong$Type` really is + // called that. + if (whole != null && !whole.equals(simple) && declaresType(text, whole, kotlin)) { + return true; + } + if (!declaresType(text, simple, kotlin)) { + // Same reasoning as the package: an unreadable name is unjudgeable. + return !isAscii(simple) || !isAscii(text); + } + // The whole nesting PATH has to be there, in order. Checking only the + // innermost name let an unrelated Main.B.Wrong vouch for a deleted + // Main.A.Wrong, so the orphan stayed and failed the placement check on + // every incremental build. Checking only the outer class was the same bug + // one level out. + return nested == null || declaresNestedPath(text, nested, kotlin); + } + + /// Whether every character of `s` is ASCII, which is where this scan can + /// read a source without knowing its encoding. + private static boolean isAscii(String s) { + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) > 0x7F) { + return false; + } + } + return true; + } + + /// Whether `text` declares the chain `path` -- {"Main", "A", "Wrong"} -- each + /// inside the body of the one before it. + /// + /// Braces are counted on the blanked text, where every comment and string + /// literal is already spaces, so a brace inside either cannot throw the + /// nesting off. + public static boolean declaresNestedPath(String text, String[] path) { + return declaresNestedPath(text, path, false); + } + + public static boolean declaresNestedPath(String text, String[] path, boolean kotlin) { + String code = blankNonCode(text, kotlin); + int from = 0; + int end = code.length(); + for (int p = 0; p < path.length; p++) { + String segment = path[p]; + boolean last = p == path.length - 1; + int at = declarationOf(code, segment, from, end); + // p > 0: the outermost segment is the type the file declares and is + // always required. Only what Kotlin may have synthesised BETWEEN it + // and the class gets the benefit of the doubt. + if (at < 0 && kotlin && !last && p > 0) { + // Kotlin builds a local class's binary name out of the enclosing + // FUNCTION names -- a Wrong declared in Main.start() is + // Main$start$Wrong, with nothing to mark `start` as synthetic the + // way javac's $1 does. So an intermediate segment that is not a + // type may be a function, and the class is inside its body. + at = functionDeclarationOf(code, segment, from, end); + if (at < 0 && "Companion".equals(segment)) { + // Kotlin's UNNAMED companion object is called Companion in the + // binary name and is declared as `companion object` with no + // name at all, so nothing in the source is spelled Companion. + // Accepting the whole path here on that basis stopped the walk + // before the class itself, and a deleted + // Main$Companion$Wrong then kept its orphan and failed every + // incremental build. Recognised as a scope so the remaining + // segments are still checked. + at = companionObjectAt(code, from, end); + } + if (at < 0) { + // Some other Kotlin construct names an intermediate segment -- + // an init block, a property accessor. Inconclusive, and + // deliberately so: concluding orphan drops a live annotated + // class and loses its hints with no message, while keeping a + // stale one costs a placement error that can be seen and acted + // on. This does NOT extend to the last segment, which is the + // class itself: a nested type that is genuinely gone must be + // reported, or a deleted Main$Wrong keeps its orphan and fails + // every incremental build. + return true; + } + } + if (at < 0) { + return false; + } + int open = code.indexOf('{', at); + if (open < 0 || open >= end) { + // A body-less declaration -- Kotlin's `class Foo` -- can only be + // the last segment, and if it is not, nothing is nested in it. + return last; + } + from = open + 1; + end = matchingBrace(code, open); + } + return true; + } + + /// The offset of a `class`/`interface`/`enum`/`object`/`record` declaration of + /// `simple` declared DIRECTLY between `from` and `end`, or -1. + /// + /// Directly: at brace depth zero within that range. A match at any depth + /// would let Main.B.Wrong answer for Main.Wrong, which is the same + /// wrong-identity bug one level along -- and Main.Wrong not existing is + /// exactly when its .class is an orphan. + private static int declarationOf(String code, String simple, int from, int end) { + return declarationOf(code, simple, from, end, true); + } + + /// As above; `directOnly` restricts the match to brace depth zero within the + /// range, which is what nesting identity needs and what a plain "does this + /// file declare X" question does not. + private static int declarationOf(String code, String simple, int from, int end, + boolean directOnly) { + int depth = 0; + int i = from; + while (i < end && i < code.length()) { + int escaped = escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (c == '{') { + depth++; + i++; + continue; + } + if (c == '}') { + depth--; + i++; + continue; + } + if ((directOnly && depth != 0) || !Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < code.length() && Character.isJavaIdentifierPart(code.charAt(wordEnd))) { + wordEnd++; + } + String word = code.substring(i, wordEnd); + if (isTypeKeyword(word)) { + int n = wordEnd; + while (n < end && Character.isWhitespace(code.charAt(n))) { + n++; + } + if (simple.equals(simpleNameAt(code, n, end))) { + return i; + } + } + i = wordEnd; + } + return -1; + } + + /// Java's unicode escapes, applied. + /// + /// javac processes `\\uXXXX` in the LEXICAL TRANSLATION step, before it + /// tokenizes anything -- so `package com.ex\\u0061mple;` really declares + /// com.example, and an escape works inside an identifier, a comment or + /// anywhere else. Reading the text literally stopped the package component + /// at the backslash and recorded com.ex, so a live annotated class looked + /// like it belonged elsewhere and was dropped as an orphan with its + /// placement error unreported. + /// + /// A backslash only starts an escape when an EVEN number of backslashes + /// precedes it, which is what keeps `"\\\\u0041"` the four characters it + /// looks like. Kotlin has no such step, so this is applied to Java only. + /// + /// Offsets move, so this is for the readers that answer questions about the + /// source -- never for the migration, which writes back at indices into the + /// text as it is on disk. + public static String decodeUnicodeEscapes(String text) { + if (text == null || text.indexOf('\\') < 0) { + return text; + } + StringBuilder out = new StringBuilder(text.length()); + int i = 0; + while (i < text.length()) { + char c = text.charAt(i); + if (c != '\\') { + out.append(c); + i++; + continue; + } + int j = i; + while (j < text.length() && text.charAt(j) == '\\') { + j++; + } + int run = j - i; + for (int pair = 0; pair < run / 2; pair++) { + out.append('\\').append('\\'); + } + if (run % 2 == 0) { + i = j; + continue; + } + // One backslash is left over, and only it can open an escape. + int u = j; + while (u < text.length() && text.charAt(u) == 'u') { + u++; + } + int value = u > j ? hexQuad(text, u) : -1; + if (value < 0) { + out.append('\\'); + i = j; + continue; + } + out.append((char) value); + i = u + 4; + } + return out.toString(); + } + + /// The four hex digits at `from`, or -1 when they are not four hex digits. + private static int hexQuad(String text, int from) { + if (from + 4 > text.length()) { + return -1; + } + int value = 0; + for (int i = from; i < from + 4; i++) { + int digit = Character.digit(text.charAt(i), 16); + if (digit < 0) { + return -1; + } + value = value * 16 + digit; + } + return value; + } + + /// The index just past a Kotlin escaped identifier at `i`, or -1 when there + /// is not one there. + /// + /// [#blankNonCode] leaves these as the code they are, because a declared + /// name has to stay readable -- so every scanner looking for a KEYWORD has + /// to step over them itself. `fun `import`() {}` declares a function called + /// import, not an import directive, and reading it as one put the generated + /// import after a top-level declaration where Kotlin does not allow it. + /// Stepping over the run also keeps the brace count honest, since `{` is a + /// legal character inside one. + public static int escapedIdentifierEnd(String code, int i) { + if (i < 0 || i >= code.length() || code.charAt(i) != '`') { + return -1; + } + int close = code.indexOf('`', i + 1); + return close < 0 ? -1 : close + 1; + } + + /// The declared simple name at `n`, or null when the source runs out. + /// + /// Kotlin lets a declaration ESCAPE its name in backticks -- `class `when`` + /// compiles to a class whose binary name is plainly `when`. Reading it with + /// the identifier rule stopped at the backtick and recorded an empty name, + /// so the class looked undeclared: the orphan filter then classified a live + /// annotated type as stale and dropped it before placement validation, and + /// the misplaced hints went unreported on a green build. + /// + /// A backtick cannot appear in Java source at all outside a comment or a + /// literal, both of which are already blanked, so this needs no language + /// flag. + private static String simpleNameAt(String code, int n, int end) { + if (n < end && n < code.length() && code.charAt(n) == '`') { + int close = code.indexOf('`', n + 1); + if (close < 0 || close >= end) { + return null; + } + return code.substring(n + 1, close); + } + int stop = n; + while (stop < end && Character.isJavaIdentifierPart(code.charAt(stop))) { + stop++; + } + return code.substring(n, stop); + } + + private static boolean isTypeKeyword(String word) { + return "class".equals(word) || "interface".equals(word) || "enum".equals(word) + || "object".equals(word) || "record".equals(word); + } + + /// The offset of an unnamed `companion object` declared directly between + /// `from` and `end`, or -1. + /// + /// A NAMED companion -- `companion object Named` -- needs nothing special: + /// its name is what appears in the binary name and the ordinary declaration + /// lookup finds it. + private static int companionObjectAt(String code, int from, int end) { + int depth = 0; + int i = from; + while (i < end && i < code.length()) { + int escaped = escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (c == '{') { + depth++; + i++; + continue; + } + if (c == '}') { + depth--; + i++; + continue; + } + if (depth != 0 || !Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < code.length() + && Character.isJavaIdentifierPart(code.charAt(wordEnd))) { + wordEnd++; + } + if ("companion".equals(code.substring(i, wordEnd))) { + int n = wordEnd; + while (n < end && Character.isWhitespace(code.charAt(n))) { + n++; + } + int stop = n; + while (stop < end && Character.isJavaIdentifierPart(code.charAt(stop))) { + stop++; + } + if ("object".equals(code.substring(n, stop))) { + int after = stop; + while (after < end && Character.isWhitespace(code.charAt(after))) { + after++; + } + // Unnamed only: a name here means the binary path carries that + // name instead, and the ordinary lookup has already handled it. + if (after < end && code.charAt(after) == '{') { + return i; + } + } + } + i = wordEnd; + } + return -1; + } + + /// The offset of a `fun` named `simple` declared directly between `from` and + /// `end`, or -1. + /// + /// Only Kotlin names a local class after its enclosing function, so this is + /// how an intermediate segment is told from a nested type that is gone. + private static int functionDeclarationOf(String code, String simple, int from, int end) { + int depth = 0; + int i = from; + while (i < end && i < code.length()) { + int escaped = escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (c == '{') { + depth++; + i++; + continue; + } + if (c == '}') { + depth--; + i++; + continue; + } + if (depth != 0 || !Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < code.length() + && Character.isJavaIdentifierPart(code.charAt(wordEnd))) { + wordEnd++; + } + if ("fun".equals(code.substring(i, wordEnd))) { + int n = wordEnd; + while (n < end && Character.isWhitespace(code.charAt(n))) { + n++; + } + // Backticks here too: Kotlin test code habitually names a + // function `does the thing`, and a local class inside it takes + // that name as a segment of its binary name. + if (simple.equals(simpleNameAt(code, n, end))) { + return i; + } + } + i = wordEnd; + } + return -1; + } + + /// The index just past the brace closing the one at `open`. + private static int matchingBrace(String code, int open) { + int depth = 0; + for (int i = open; i < code.length(); i++) { + char c = code.charAt(i); + if (c == '{') { + depth++; + } else if (c == '}') { + depth--; + if (depth == 0) { + return i; + } + } + } + return code.length(); + } + + /// The innermost named segment of a nested binary name, or null. + /// + /// Null for an unnamed segment -- Main$1 is an anonymous class, which no + /// source declares and which cannot carry an annotation in the first place, + /// so there is nothing to look for and nothing to conclude from not finding + /// it. + static String[] nestedNameOf(String binaryName) { + int dot = binaryName.lastIndexOf('.'); + String simple = dot < 0 ? binaryName : binaryName.substring(dot + 1); + if (simple.indexOf('$') < 0) { + return null; + } + String[] path = simple.split("\\$"); + for (String segment : path) { + // A segment BEGINNING with a digit is javac's, not the developer's: + // $1 for an anonymous class and $1Wrong for a named local one. No + // source declares either spelling, so looking for it finds nothing -- + // and concluding "orphan" from that dropped a live annotated local + // class before the placement check could reject it, which let the + // build succeed with the requested hints silently discarded. + // + // Checking for wholly-numeric missed $1Wrong exactly. + if (segment.length() == 0 || Character.isDigit(segment.charAt(0))) { + return null; + } + } + return path; + } + + /// The dotted name starting at or after `from`, skipping whitespace around + /// each dot. Blanked code, so comments are whitespace already. + public static String qualifiedNameAt(String code, int from) { + StringBuilder name = new StringBuilder(); + readQualifiedName(code, from, name); + return name.toString(); + } + + /// The index just past the dotted name starting at or after `from`, or + /// `from` when there is none. The same walk as {@link #qualifiedNameAt}, so + /// the two cannot disagree about where a name ends. + public static int qualifiedNameEnd(String code, int from) { + return readQualifiedName(code, from, null); + } + + private static int readQualifiedName(String code, int from, StringBuilder name) { + int i = from; + int end = from; + while (i < code.length()) { + while (i < code.length() && Character.isWhitespace(code.charAt(i))) { + i++; + } + int stop = i; + if (stop < code.length() && code.charAt(stop) == '*') { + if (name != null) { + name.append('*'); + } + return stop + 1; + } + // A COMPONENT may be escaped too: `package com.`when`` is legal + // Kotlin and the compiled class belongs to com.when. Stopping at the + // backtick recorded `com.`, so a live annotated class looked like it + // belonged to another package, was dropped as an orphan, and its + // misplaced hints went unreported on a green build. A backtick is + // not Java source outside a comment or literal, both already blanked, + // so this needs no language flag. + if (stop < code.length() && code.charAt(stop) == '`') { + int close = code.indexOf('`', stop + 1); + if (close < 0) { + return end; + } + if (name != null) { + name.append(code, stop + 1, close); + } + stop = close + 1; + end = stop; + int nextDot = stop; + while (nextDot < code.length() && Character.isWhitespace(code.charAt(nextDot))) { + nextDot++; + } + if (nextDot >= code.length() || code.charAt(nextDot) != '.') { + return end; + } + if (name != null) { + name.append('.'); + } + i = nextDot + 1; + continue; + } + while (stop < code.length() && Character.isJavaIdentifierPart(code.charAt(stop))) { + stop++; + } + if (stop == i) { + return end; + } + if (name != null) { + name.append(code, i, stop); + } + end = stop; + int dot = stop; + while (dot < code.length() && Character.isWhitespace(code.charAt(dot))) { + dot++; + } + if (dot >= code.length() || code.charAt(dot) != '.') { + return end; + } + if (name != null) { + name.append('.'); + } + i = dot + 1; + } + return end; + } + + /// Whether `text` declares a type called `simple`. + /// + /// Comments and string literals are blanked first: a commented-out + /// `// class Wrong` left behind by the very edit that deleted the type would + /// otherwise vouch for its own orphan. + public static boolean declaresType(String text, String simple) { + return declaresType(text, simple, false); + } + + /// As above, reading the source by `kotlin`'s rules. + public static boolean declaresType(String text, String simple, boolean kotlin) { + String code = blankNonCode(text, kotlin); + return declarationOf(code, simple, 0, code.length(), false) >= 0; + } + + /// `text` with every comment and string literal replaced by spaces, so a + /// declaration can be looked for without a quoted or commented mention of one + /// answering for it. Lengths and line breaks are preserved. + public static String blankNonCode(String text) { + return blankNonCode(text, false); + } + + /// As above, reading triple-quoted literals by the rules of `kotlin`'s + /// language. + /// + /// The two differ and reading one as the other over-consumes: a Kotlin raw + /// string ends at the LAST three quotes of a run, while a Java text block + /// processes escapes so `\"""` is not a delimiter. Getting it wrong blanks + /// the declaration that follows, so a live class reads as an orphan and its + /// misplaced annotation is never reported. + public static String blankNonCode(String text, boolean kotlin) { + char[] out = text.toCharArray(); + int i = 0; + while (i < out.length) { + char c = out[i]; + if (c == '/' && i + 1 < out.length && out[i + 1] == '/') { + while (i < out.length && out[i] != '\n') { + out[i++] = ' '; + } + } else if (c == '/' && i + 1 < out.length && out[i + 1] == '*') { + // Kotlin block comments NEST; Java's do not. Stopping at the + // first */ in Kotlin ends the comment early, and the text after + // it -- `package old.name */` in a commented-out block -- is then + // read as live code, so a class looks like it belongs elsewhere + // and a live annotated one is dropped as an orphan. + int depth = 0; + while (i < out.length) { + if (out[i] == '/' && i + 1 < out.length && out[i + 1] == '*') { + depth++; + out[i++] = ' '; + out[i++] = ' '; + continue; + } + if (out[i] == '*' && i + 1 < out.length && out[i + 1] == '/') { + depth--; + out[i++] = ' '; + out[i++] = ' '; + if (depth == 0 || !kotlin) { + break; + } + continue; + } + if (out[i] != '\n') { + out[i] = ' '; + } + i++; + } + } else if (kotlin && c == '`') { + // A Kotlin escaped identifier. It is CODE, so it is left alone + // rather than blanked -- the declared name has to stay readable + // -- but it is stepped over whole, because the quote in + // `class `say"hi`` would otherwise open a literal that swallows + // the rest of the file. + int j = i + 1; + while (j < out.length && out[j] != '`' && out[j] != '\n') { + j++; + } + i = j < out.length && out[j] == '`' ? j + 1 : i + 1; + } else if (c == '\'') { + // A char literal. '{' is legal and would otherwise be counted as + // syntax, so the nesting scan loses its place and reads a live + // class as an orphan. + out[i++] = ' '; + while (i < out.length) { + if (out[i] == '\\' && i + 1 < out.length) { + out[i++] = ' '; + out[i++] = ' '; + continue; + } + boolean closing = out[i] == '\''; + if (out[i] != '\n') { + out[i] = ' '; + } + i++; + if (closing) { + break; + } + } + } else if (c == '"' && i + 2 < out.length && out[i + 1] == '"' && out[i + 2] == '"') { + int close = kotlin ? endOfKotlinRawString(out, i) : endOfJavaTextBlock(out, i); + while (i < close && i < out.length) { + if (out[i] != '\n') { + out[i] = ' '; + } + i++; + } + } else if (c == '"') { + out[i++] = ' '; + while (i < out.length) { + if (out[i] == '\\' && i + 1 < out.length) { + out[i++] = ' '; + out[i++] = ' '; + continue; + } + // A Kotlin template expression opens a fresh nesting level, + // and the first quote inside it starts a NEW literal rather + // than closing this one -- so `"${"@Ios(teamId = x)"}"` ended + // the string early and exposed its contents as code, which + // read as a declaration nobody wrote. + int template = kotlin ? endOfKotlinTemplate(out, i) : -1; + if (template > i) { + while (i < template) { + if (out[i] != '\n') { + out[i] = ' '; + } + i++; + } + continue; + } + boolean closing = out[i] == '"'; + if (out[i] != '\n') { + out[i] = ' '; + } + i++; + if (closing) { + break; + } + } + } else { + i++; + } + } + return new String(out); + } + + /// Index just past a Java text block opening at `i`. Escapes apply, so a + /// backslash consumes the next character and cannot start the delimiter. + private static int endOfJavaTextBlock(char[] c, int i) { + int j = i + 3; + while (j < c.length) { + if (c[j] == '\\') { + j += 2; + continue; + } + if (c[j] == '"' && j + 2 < c.length && c[j + 1] == '"' && c[j + 2] == '"') { + return j + 3; + } + j++; + } + return c.length; + } + + /// Index just past a Kotlin raw string opening at `i`. No escapes, and a run + /// of quotes closes at its LAST three, so the extra ones belong to the value. + /// The offset just past a `${ ... }` template expression at `i`, or -1 when + /// one does not start there. + /// + /// Braces are matched, and a nested literal inside the expression is stepped + /// over so that a `}` inside it does not close the expression early. + private static int endOfKotlinTemplate(char[] c, int i) { + if (i + 1 >= c.length || c[i] != '$' || c[i + 1] != '{') { + return -1; + } + int depth = 0; + int j = i + 1; + while (j < c.length) { + char ch = c[j]; + if (ch == '"') { + int run = j; + while (run < c.length && c[run] == '"') { + run++; + } + j = run - j >= 3 ? endOfKotlinRawString(c, j) : endOfKotlinString(c, j); + continue; + } + // The expression is ordinary code, so it holds ordinary comments and + // char literals -- and a quote inside one of those is not a nested + // string. Reading `${ /* " */ 1 }` as if it were swallowed the rest + // of the file, so a live declaration after it was blanked and its + // class dropped as an orphan. + int nonCode = endOfKotlinNonCode(c, j); + if (nonCode > j) { + j = nonCode; + continue; + } + // An escaped identifier is code, and everything inside it is part of + // the name -- a quote there does not open a string and a brace does + // not close the expression. `${ `"` }` left the template looking + // unterminated, so the rest of the file was blanked and a live + // declaration after it dropped as an orphan. + if (c[j] == '`') { + int close = j + 1; + while (close < c.length && c[close] != '`') { + close++; + } + if (close >= c.length) { + return -1; + } + j = close + 1; + continue; + } + if (ch == '{') { + depth++; + } else if (ch == '}') { + depth--; + if (depth == 0) { + return j + 1; + } + } + j++; + } + return -1; + } + + /// The offset just past a comment or char literal at `i`, or `i` when there + /// is neither. + private static int endOfKotlinNonCode(char[] c, int i) { + if (i + 1 < c.length && c[i] == '/' && c[i + 1] == '/') { + int j = i; + while (j < c.length && c[j] != '\n') { + j++; + } + return j; + } + if (i + 1 < c.length && c[i] == '/' && c[i + 1] == '*') { + // Kotlin block comments NEST. + int depth = 0; + int j = i; + while (j < c.length) { + if (c[j] == '/' && j + 1 < c.length && c[j + 1] == '*') { + depth++; + j += 2; + continue; + } + if (c[j] == '*' && j + 1 < c.length && c[j + 1] == '/') { + depth--; + j += 2; + if (depth == 0) { + return j; + } + continue; + } + j++; + } + return c.length; + } + if (c[i] == '\'') { + int j = i + 1; + while (j < c.length) { + if (c[j] == '\\') { + j += 2; + continue; + } + if (c[j] == '\'') { + return j + 1; + } + j++; + } + return c.length; + } + return i; + } + + /// The offset just past an ordinary Kotlin string starting at `i`. + private static int endOfKotlinString(char[] c, int i) { + int j = i + 1; + while (j < c.length) { + if (c[j] == '\\') { + j += 2; + continue; + } + int template = endOfKotlinTemplate(c, j); + if (template > j) { + j = template; + continue; + } + if (c[j] == '"') { + return j + 1; + } + j++; + } + return c.length; + } + + private static int endOfKotlinRawString(char[] c, int i) { + int j = i + 3; + while (j < c.length) { + // A template expression here too: a `"""` inside one is a nested + // literal, not this string's terminator. + int template = endOfKotlinTemplate(c, j); + if (template > j) { + j = template; + continue; + } + if (c[j] != '"') { + j++; + continue; + } + int run = j; + while (run < c.length && c[run] == '"') { + run++; + } + if (run - j >= 3) { + return run; + } + j = run; + } + return c.length; + } + + /// The whole of `f`, or null when it cannot be read or is implausibly large. + /// + /// Not a prefix. A line bound looked harmless and was not: a type declared + /// below it -- after a long generated header, or a big import block -- was + /// not found, so a live class read as an orphan and its misplaced annotation + /// was skipped instead of reported. A nesting scan also cannot start in the + /// middle of a file and still count braces. + /// + /// The size cap is a guard against something that is not source at all, not + /// a budget: 4MB is far past any hand-written Java or Kotlin file, and + /// exceeding it returns null, which the caller reads as "cannot tell" and so + /// keeps the class. + /// The charset to read `f` as: UTF-8 when it decodes as UTF-8, ISO-8859-1 + /// otherwise. + /// + /// The compiler's source encoding is a project setting this scan cannot see. + /// Guessing it from the bytes is not exact, but decoding everything as UTF-8 + /// produced replacement characters for a source that was never UTF-8, and a + /// name that cannot be read never matches. + private static java.nio.charset.Charset decoderFor(File f) { + try { + byte[] bytes = new byte[(int) Math.min(f.length(), 64L * 1024)]; + InputStream in = new FileInputStream(f); + try { + int read = 0; + while (read < bytes.length) { + int n = in.read(bytes, read, bytes.length - read); + if (n < 0) { + break; + } + read += n; + } + java.nio.charset.CharsetDecoder decoder = + java.nio.charset.Charset.forName("UTF-8").newDecoder(); + decoder.onMalformedInput(java.nio.charset.CodingErrorAction.REPORT); + decoder.onUnmappableCharacter(java.nio.charset.CodingErrorAction.REPORT); + decoder.decode(java.nio.ByteBuffer.wrap(bytes, 0, read)); + return java.nio.charset.Charset.forName("UTF-8"); + } finally { + in.close(); + } + } catch (java.nio.charset.CharacterCodingException notUtf8) { + return java.nio.charset.Charset.forName("ISO-8859-1"); + } catch (IOException ex) { + return java.nio.charset.Charset.forName("UTF-8"); + } + } + + static String readHead(File f) { + if (f.length() > 4L * 1024 * 1024) { + return null; + } + BufferedReader r = null; + try { + // UTF-8 where the file is UTF-8, which is the overwhelming case and + // what a name from the class file can be compared against directly. + // Where it is not, ISO-8859-1: it never fails to decode, so a source + // in a single-byte encoding is read correctly rather than turned + // into replacement characters. What neither reading can settle -- a + // non-ASCII name in some third encoding -- is left inconclusive by + // the caller rather than called an orphan. + r = new BufferedReader(new InputStreamReader(new FileInputStream(f), decoderFor(f))); + StringBuilder sb = new StringBuilder(); + String line; + while ((line = r.readLine()) != null) { + sb.append(line).append('\n'); + } + return sb.toString(); + } catch (IOException ex) { + return null; + } finally { + if (r != null) { + try { + r.close(); + } catch (IOException ignored) { + // read-only stream + } + } + } + } + + /// The package `text` declares, or "" for the default package. + public static String declaredPackageIn(String text) { + return declaredPackageIn(text, false); + } + + /// As above, reading the source by `kotlin`'s rules. + public static String declaredPackageIn(String text, boolean kotlin) { + // Tokens, not lines. `package\ncom.example;` is valid Java, and reading + // one physical line saw an empty remainder and reported the default + // package -- so a live class looked like it belonged somewhere else, read + // as an orphan, and its misplaced annotation went unreported. + String code = blankNonCode(text, kotlin); + int i = 0; + while (i < code.length()) { + // An escaped identifier is left as the code it is, so the scan has + // to step over it: `fun `package helper`() {}` declares a function, + // and reading into it reported `helper` as the declared package -- + // which made a live annotated class in that file look like it + // belonged elsewhere and dropped it as an orphan. + int escaped = escapedIdentifierEnd(code, i); + if (escaped > i) { + i = escaped; + continue; + } + char c = code.charAt(i); + if (!Character.isJavaIdentifierStart(c) + || (i > 0 && Character.isJavaIdentifierPart(code.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < code.length() + && Character.isJavaIdentifierPart(code.charAt(wordEnd))) { + wordEnd++; + } + if (!"package".equals(code.substring(i, wordEnd))) { + i = wordEnd; + continue; + } + // Component by component. `package com /* generated */ . example;` is + // legal, and reading the name as one contiguous run stopped at the + // separator and recorded `com` -- so a live class looked like it + // belonged elsewhere, read as an orphan, and its misplaced annotation + // went unreported. Comments are already spaces here. + return qualifiedNameAt(code, wordEnd); + } + return ""; + } + + /// Build hints configure the application, so they belong on the class the /// Build hints configure the application, so they belong on the class the + /// project already names as its entry point. + /// + /// Accepting them anywhere would mean two classes could set the same hint + /// and the winner would depend on the order `File.listFiles` happened to + /// return -- and it would scatter the effective build configuration across + /// the source tree, which is the problem the properties file already had. + private void checkPlacement(ProcessorContext ctx) { + String main = ctx.getMainClassBinaryName(); + if (main == null) { + ctx.error(annotated.get(0), + "Build hint annotations are only supported in a Codename One application, " + + "and this module declares no codename1.mainName."); + return; + } + for (AnnotatedClass cls : annotated) { + if (!main.equals(cls.getBinaryName())) { + ctx.error(cls, "Build hint annotations belong on the application's main class, " + + main + ", but this one carries them. Move them there, or set the hint " + + "in codenameone_settings.properties."); + } + } + } + + /// A hint has one source of truth. Setting it in both places means the two + /// can disagree, and nothing would say which won. + private void checkConflicts(ProcessorContext ctx) { + Properties settings = ctx.getProjectSettings(); + if (settings == null) { + return; + } + Map lines = propertyLines(ctx); + for (Map.Entry e : hints.entrySet()) { + Set names = spellingsOf(e.getKey()); + for (String name : names) { + String key = BuildHints.ARG_PREFIX + name; + if (settings.getProperty(key) == null) { + continue; + } + StringBuilder sb = new StringBuilder(); + sb.append(key).append(" is declared twice.\n"); + sb.append(" annotation : ").append(origins.get(e.getKey())) + .append(" on ").append(annotated.get(0).getBinaryName()).append('\n'); + sb.append(" properties : "); + File f = settingsFile(ctx); + sb.append(f == null ? "codenameone_settings.properties" : f.getPath()); + Integer line = lines.get(key); + if (line != null) { + sb.append(':').append(line); + } + sb.append('\n'); + sb.append(" ").append(key).append('=') + .append(settings.getProperty(key)).append('\n'); + sb.append(" A build hint has one source of truth. Delete the properties line " + + "and keep the annotation, or delete the annotation attribute and keep " + + "the line. (-D").append(key).append("=... overrides either and is not " + + "a conflict.)"); + ctx.error(annotated.get(0), sb.toString()); + } + } + } + + private File settingsFile(ProcessorContext ctx) { + File dir = ctx.getProjectDir(); + if (dir == null) { + return null; + } + File f = new File(dir, "codenameone_settings.properties"); + return f.exists() ? f : null; + } + + /// Best-effort key to line number, so the conflict message can point at the + /// offending line. Properties escaping means an exotic key may not match; + /// the message then names the file only rather than guessing. + private Map propertyLines(ProcessorContext ctx) { + Map out = new LinkedHashMap(); + File f = settingsFile(ctx); + if (f == null) { + return out; + } + BufferedReader r = null; + try { + r = new BufferedReader(new InputStreamReader(new FileInputStream(f), "ISO-8859-1")); + String line; + int n = 0; + while ((line = r.readLine()) != null) { + n++; + String t = line.trim(); + if (t.length() == 0 || t.charAt(0) == '#' || t.charAt(0) == '!') { + continue; + } + int eq = t.indexOf('='); + int colon = t.indexOf(':'); + int split = eq < 0 ? colon : (colon < 0 ? eq : Math.min(eq, colon)); + if (split <= 0) { + continue; + } + String key = t.substring(0, split).trim(); + if (!out.containsKey(key)) { + out.put(key, Integer.valueOf(n)); + } + } + } catch (IOException ex) { + ctx.getLog().debug("cn1: could not read " + f + " for line numbers: " + ex.getMessage()); + } finally { + if (r != null) { + try { + r.close(); + } catch (IOException ignored) { + // read-only stream; nothing useful to do + } + } + } + return out; + } + + /// Converts one annotation member value to the string the build receives. + /// + /// Returns null when the value could not be converted, having reported it. + private String wireValue(AnnotatedClass cls, String descriptor, String member, Object raw, + String hint, ProcessorContext ctx) { + if (raw instanceof Boolean || raw instanceof Number || raw instanceof Character) { + return String.valueOf(raw); + } + if (raw instanceof String) { + return (String) raw; + } + // ASM reports an enum constant as { descriptor, CONSTANT_NAME }. The + // constant name is not the value the builder compares against, and a + // builder silently falls back to its default on a value it does not + // recognise, so guessing here would fail invisibly. + if (raw instanceof String[]) { + String[] pair = (String[]) raw; + if (pair.length == 2) { + String wire = BuildHintAnnotationBinding.wireValue(pair[0], pair[1]); + if (wire == null) { + ctx.error(cls, "@" + simpleName(descriptor) + "(" + member + ") uses the " + + "constant " + pair[1] + ", which the build hint catalog does not " + + "map to a value. Regenerate with " + + "scripts/gen-build-hint-annotations.sh."); + return null; + } + return wire; + } + } + if (raw instanceof List) { + String separator = BuildHints.separatorFor(hint); + if (separator.length() == 0) { + ctx.error(cls, "@" + simpleName(descriptor) + "(" + member + ") is a list but the " + + "catalog gives " + hint + " no separator, so its values would run " + + "together."); + return null; + } + // By POSITION, not by what has been written. An element may legally be + // empty -- a newline-delimited android.xgradle whose value starts with + // a newline migrates to {"", "..."} -- and testing sb.length() then + // skipped the separator after it, silently dropping the leading + // newline from the hint the builder receives. + StringBuilder sb = new StringBuilder(); + List items = (List) raw; + for (int i = 0; i < items.size(); i++) { + if (i > 0) { + sb.append(separator); + } + String itemValue = wireValue(cls, descriptor, member, items.get(i), hint, ctx); + if (itemValue == null) { + return null; + } + sb.append(itemValue); + } + return sb.toString(); + } + ctx.error(cls, "@" + simpleName(descriptor) + "(" + member + ") has a value this " + + "processor cannot convert: " + raw); + return null; + } + + /// Serializes deterministically. + /// + /// Not `Properties.store`: it writes a timestamp comment, so the bytes would + /// differ on every build. That churns the resource in every incremental + /// build and defeats the staged-jar staleness comparison in `CN1BuildMojo`. + /// Every name that denotes the same setting as `hint`, itself included. + /// + /// An alias and its target are one setting -- the builder reads + /// `android.captureRecord` and then lets `and.captureRecord` override it -- + /// so declaring either in the properties file collides with the annotation. + static Set spellingsOf(String hint) { + Set names = new LinkedHashSet(); + names.add(hint); + for (BuildHints.Hint h : BuildHints.entries()) { + if (hint.equals(h.aliasOf()) || hint.equals(BuildHints.canonicalName(h.name()))) { + names.add(h.name()); + } + } + return names; + } + + /// A stable fingerprint of every build hint annotation on `cls`. /// A stable fingerprint of every build hint annotation on `cls`. + /// + /// Taken over the raw annotation members rather than over the hints they + /// convert into, so it changes for anything the developer can change: a + /// different value, an added or removed attribute, a whole annotation + /// gained or lost. Two builds of the same source produce the same string; + /// there is no timestamp or path in it. + public static String sourceDigest(AnnotatedClass cls) throws ProcessingException { + StringBuilder sb = new StringBuilder(); + Set known = new HashSet(BuildHintAnnotationBinding.descriptors()); + // Sorted, because the class file's annotation order is the source's and a + // reordering is not a change. + for (String descriptor : new TreeMap( + cls.getClassAnnotations()).keySet()) { + if (!known.contains(descriptor)) { + continue; + } + emit(sb, descriptor); + AnnotationValues values = cls.getClassAnnotation(descriptor); + emit(sb, String.valueOf(values.all().size())); + for (Map.Entry e + : new TreeMap(values.all()).entrySet()) { + emit(sb, e.getKey()); + renderForDigest(e.getValue(), sb); + } + } + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); + byte[] digest = md.digest(sb.toString().getBytes("UTF-8")); + StringBuilder hex = new StringBuilder(); + for (byte b : digest) { + hex.append(Character.forDigit((b >> 4) & 0xf, 16)); + hex.append(Character.forDigit(b & 0xf, 16)); + } + return hex.toString(); + } catch (java.security.NoSuchAlgorithmException | UnsupportedEncodingException ex) { + throw new ProcessingException("Could not fingerprint the build hint annotations", ex); + } + } + + /// Appends `s` length-prefixed, so nothing it contains can be read as + /// structure. + /// + /// A value IS a place an attacker -- or an unlucky developer -- writes + /// arbitrary text: with plain delimiters, + /// `@Ios(bundleVersion = "1;teamId=java.lang.String:X")` rendered exactly + /// like `@Ios(bundleVersion = "1", teamId = "X")`, so a stale manifest was + /// accepted for a different configuration and the build silently kept the old + /// values. + private static void emit(StringBuilder sb, String s) { + sb.append(s.length()).append(':').append(s).append(';'); + } + + /// The type is part of the rendering, so an int 1 and the string "1" -- which + /// print alike but are different annotations -- do not fingerprint alike. + /// + /// Every variable-length piece goes through `emit`, so no value can forge the + /// structure around it. + private static void renderForDigest(Object value, StringBuilder sb) { + if (value == null) { + emit(sb, "null"); + } else if (value instanceof String[]) { + // How ASM delivers an enum member: {descriptor, CONSTANT_NAME}. + String[] e = (String[]) value; + emit(sb, "enum"); + emit(sb, e.length > 0 ? e[0] : ""); + emit(sb, e.length > 1 ? e[1] : ""); + } else if (value instanceof List) { + List list = (List) value; + emit(sb, "list"); + emit(sb, String.valueOf(list.size())); + for (Object item : list) { + renderForDigest(item, sb); + } + } else if (value instanceof AnnotationValues) { + AnnotationValues nested = (AnnotationValues) value; + emit(sb, "annotation"); + emit(sb, nested.getDescriptor()); + emit(sb, String.valueOf(nested.all().size())); + for (Map.Entry e + : new TreeMap(nested.all()).entrySet()) { + emit(sb, e.getKey()); + renderForDigest(e.getValue(), sb); + } + } else { + emit(sb, value.getClass().getName()); + emit(sb, String.valueOf(value)); + } + } + + /// Rewrites [#CLASS_DIGEST_KEY] in an emitted manifest to describe the class + /// that is actually on disk. + /// + /// A processor may REPLACE a class through `emitClass`, and the mojo flushes + /// those only after every processor's `finish()` -- so a manifest written + /// during ours records the class as the compiler left it, not as the build + /// ships it. `BindingAnnotationProcessor` does exactly that for a main class + /// with a two-way `@Bindable` setter, and processor order is whatever the + /// service loader returns, so reading the queued bytes instead would only + /// move the race. Called by the mojo once the classes are written, which is + /// the first moment the answer is stable. + /// + /// Silent when there is no manifest, no main class recorded, or no class + /// file: this only makes an existing stamp accurate. + public static void restampClassDigest(File outputDirectory) throws IOException { + File manifest = new File(outputDirectory, MANIFEST_RESOURCE); + if (!manifest.isFile()) { + return; + } + Properties p = new Properties(); + InputStream in = new FileInputStream(manifest); + try { + p.load(in); + } finally { + in.close(); + } + String main = p.getProperty(MAIN_CLASS_KEY); + String recorded = p.getProperty(CLASS_DIGEST_KEY); + if (main == null || recorded == null) { + return; + } + String actual = digestOfClassFile(outputDirectory, main); + if (actual == null || actual.equals(recorded)) { + return; + } + byte[] raw = readAllBytes(manifest); + String text = new String(raw, "ISO-8859-1"); + String replaced = text.replace(CLASS_DIGEST_KEY + "=" + recorded, + CLASS_DIGEST_KEY + "=" + actual); + if (replaced.equals(text)) { + return; + } + FileOutputStream out = new FileOutputStream(manifest); + try { + out.write(replaced.getBytes("ISO-8859-1")); + } finally { + out.close(); + } + } + + private static byte[] readAllBytes(File f) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + InputStream in = new FileInputStream(f); + try { + byte[] buf = new byte[8192]; + for (int n = in.read(buf); n > 0; n = in.read(buf)) { + bos.write(buf, 0, n); + } + } finally { + in.close(); + } + return bos.toByteArray(); + } + + /// SHA-256 of the compiled main class, hex, or null when it cannot be read. + /// + /// Nothing rewrites the class after `process-classes` in a Codename One + /// project, so this identifies the build that produced the manifest beside + /// it. A project that does add such a step would see the manifest reported + /// as stale, which is why the consumer treats a missing value as "cannot + /// tell" rather than as proof of anything. + private static String compiledClassDigest(ProcessorContext ctx, String main) { + return ctx.getOutputClassDir() == null ? null + : digestOfClassFile(ctx.getOutputClassDir(), main); + } + + private static String digestOfClassFile(File dir, String main) { + if (main == null || dir == null) { + return null; + } + File f = new File(dir, main.replace('.', File.separatorChar) + ".class"); + if (!f.isFile()) { + return null; + } + try { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); + InputStream in = new FileInputStream(f); + try { + byte[] buf = new byte[8192]; + for (int n = in.read(buf); n > 0; n = in.read(buf)) { + md.update(buf, 0, n); + } + } finally { + in.close(); + } + StringBuilder hex = new StringBuilder(); + for (byte b : md.digest()) { + hex.append(Character.forDigit((b >> 4) & 0xF, 16)); + hex.append(Character.forDigit(b & 0xF, 16)); + } + return hex.toString(); + } catch (IOException | java.security.NoSuchAlgorithmException ex) { + return null; + } + } + + private byte[] serialize(ProcessorContext ctx) throws ProcessingException { + StringBuilder sb = new StringBuilder(); + sb.append("# Generated from build hint annotations by the Codename One Maven plugin.\n"); + sb.append("# Edit the annotations on the main class, not this file.\n"); + String main = ctx.getMainClassBinaryName(); + if (main != null) { + sb.append(MAIN_CLASS_KEY).append('=').append(escape(main)).append('\n'); + } + sb.append(SOURCE_DIGEST_KEY).append('=') + .append(sourceDigest(annotated.get(0))).append('\n'); + String compiled = compiledClassDigest(ctx, main); + if (compiled != null) { + sb.append(CLASS_DIGEST_KEY).append('=').append(compiled).append('\n'); + } + for (Map.Entry e : hints.entrySet()) { + sb.append(escape(BuildHints.ARG_PREFIX + e.getKey())).append('=') + .append(escape(e.getValue())).append('\n'); + } + for (Map.Entry e : origins.entrySet()) { + sb.append(escape(ORIGIN_PREFIX + e.getKey())).append('=') + .append(escape(e.getValue())).append('\n'); + } + // The other spellings of each hint, for a consumer that has to collapse + // them and cannot reach the catalog -- the simulator, which lives in the + // JavaSE port. Written only where there is more than one, so the common + // hint costs nothing. + for (String hint : hints.keySet()) { + Set spellings = spellingsOf(hint); + spellings.remove(hint); + if (spellings.isEmpty()) { + continue; + } + StringBuilder joined = new StringBuilder(); + for (String name : spellings) { + if (joined.length() > 0) { + joined.append(','); + } + joined.append(name); + } + sb.append(escape(ALIAS_PREFIX + hint)).append('=') + .append(escape(joined.toString())).append('\n'); + } + try { + return sb.toString().getBytes("ISO-8859-1"); + } catch (UnsupportedEncodingException ex) { + throw new ProcessingException("ISO-8859-1 is unavailable", ex); + } + } + + /// Applies the escaping `java.util.Properties` expects, so a value holding a + /// newline -- `gradleDependencies` legitimately does -- survives the round + /// trip. + static String escape(String s) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '\\': sb.append("\\\\"); break; + case '\n': sb.append("\\n"); break; + case '\r': sb.append("\\r"); break; + case '\t': sb.append("\\t"); break; + case '=': sb.append("\\="); break; + case ':': sb.append("\\:"); break; + case '#': sb.append("\\#"); break; + case '!': sb.append("\\!"); break; + case ' ': sb.append(i == 0 ? "\\ " : " "); break; + default: + if (c < 0x20 || c > 0x7e) { + sb.append(String.format("\\u%04x", Integer.valueOf(c))); + } else { + sb.append(c); + } + } + } + return sb.toString(); + } + + private void deleteGenerated(ProcessorContext ctx) { + File f = new File(ctx.getOutputClassDir(), MANIFEST_RESOURCE); + if (f.exists() && !f.delete()) { + ctx.getLog().warn("cn1: could not remove stale " + f + "; it would be packaged " + + "with hints the project no longer declares"); + } + } + + private static String simpleName(String descriptor) { + String s = descriptor; + if (s.startsWith("L") && s.endsWith(";")) { + s = s.substring(1, s.length() - 1); + } + int slash = s.lastIndexOf('/'); + return slash >= 0 ? s.substring(slash + 1) : s; + } +} diff --git a/maven/codenameone-maven-plugin/src/main/resources/META-INF/services/com.codename1.maven.annotations.AnnotationProcessor b/maven/codenameone-maven-plugin/src/main/resources/META-INF/services/com.codename1.maven.annotations.AnnotationProcessor index 52e2d775b5b..965c0ff6c46 100644 --- a/maven/codenameone-maven-plugin/src/main/resources/META-INF/services/com.codename1.maven.annotations.AnnotationProcessor +++ b/maven/codenameone-maven-plugin/src/main/resources/META-INF/services/com.codename1.maven.annotations.AnnotationProcessor @@ -7,3 +7,4 @@ com.codename1.maven.processors.ProtoMessageAnnotationProcessor com.codename1.maven.processors.GrpcClientAnnotationProcessor com.codename1.maven.processors.GraphQLClientAnnotationProcessor com.codename1.maven.processors.AppIntentAnnotationProcessor +com.codename1.maven.processors.BuildHintAnnotationProcessor diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/AnnotationBuildHintMergeTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/AnnotationBuildHintMergeTest.java new file mode 100644 index 00000000000..27850b51de9 --- /dev/null +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/AnnotationBuildHintMergeTest.java @@ -0,0 +1,408 @@ +/* + * 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.codename1.maven; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Properties; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Where the hints that came from annotations meet the build request. + * + *

The merge has to distinguish three states that look alike from here: the + * processor ran and produced hints, it ran and produced none, and it never ran + * at all. Only the third is a broken build, and getting that wrong either ships + * an app with its build configuration silently missing or refuses one that is + * perfectly configured.

+ */ +public class AnnotationBuildHintMergeTest { + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + private static final String RESOURCE = "META-INF/codenameone/build-hints.properties"; + + @Test + public void hintsFromTheManifestReachTheBuildRequest() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "codename1.arg.ios.pods=Alamofire\n"); + Properties target = new Properties(); + + merge(target, classes, "MyApp", "com.example"); + + assertEquals("Alamofire", target.getProperty("codename1.arg.ios.pods")); + } + + /** + * A manifest with no hints in it is what {@code @Ios()} produces once the + * last attribute is deleted -- still legal, still processed. Judging by the + * hint count alone read that as "the processor never ran" and refused every + * build until the annotation itself was removed. + */ + @Test + public void anEmptyManifestIsProofTheProcessorRan() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n"); + // The annotated class has to be there too -- that is the whole situation: + // an annotation the compiler recorded and a manifest that carries no hint + // for it. Without the class the refusal path has nothing to trip on and + // the test would pass against the bug it exists for. + writeAnnotatedClass(classes); + Properties target = new Properties(); + + merge(target, classes, "MyApp", "com.example"); + + assertTrue("no hint should have been applied", target.isEmpty()); + } + + /** + * The refusal still has to fire for the case it exists for: annotations in + * the compiled classes with no manifest anywhere means the goal is unbound, + * and every annotated hint is missing from the build. + */ + @Test + public void annotatedClassesWithNoManifestAreRefused() throws Exception { + File classes = tmp.newFolder(); + writeAnnotatedClass(classes); + try { + merge(new Properties(), classes, "MyApp", "com.example"); + fail("expected the build to be refused"); + } catch (InvocationTargetException ex) { + assertTrue(String.valueOf(ex.getCause().getMessage()), + ex.getCause().getMessage().contains("process-annotations")); + } + } + + /** No annotations and no manifest is an ordinary properties-file project. */ + @Test + public void aProjectWithNoAnnotationsIsLeftAlone() throws Exception { + Properties target = new Properties(); + merge(target, tmp.newFolder(), "MyApp", "com.example"); + assertTrue(target.isEmpty()); + } + + /** A manifest stamped for another project is somebody else's configuration. */ + @Test + public void aManifestStampedForAnotherMainClassIsIgnored() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.other.TheirApp\n" + + "codename1.arg.ios.pods=Alamofire\n"); + Properties target = new Properties(); + + merge(target, classes, "MyApp", "com.example"); + + assertNull(target.getProperty("codename1.arg.ios.pods")); + } + + /** + * The processor ran once and then stopped -- goal unbound, skipped, or moved + * to a phase that no longer runs -- and the annotation changed afterwards. + * Nothing clears {@code target/classes}, so the old manifest is still there, + * still naming the right main class. Trusting it ships the previous values + * and hides the fact that the goal is not running at all. + */ + @Test + public void aManifestThatDoesNotMatchTheCompiledAnnotationsIsRefused() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "cn1.buildHints.sourceDigest=" + digestOf("@Ios(teamId = \"OLD\")") + "\n" + + "codename1.arg.ios.teamId=OLD\n"); + writeAnnotatedClass(classes); // compiled with teamId = ABCDE12345 + + Properties target = new Properties(); + try { + merge(target, classes, "MyApp", "com.example"); + fail("expected the stale manifest to be refused"); + } catch (InvocationTargetException ex) { + assertTrue(String.valueOf(ex.getCause().getMessage()), + ex.getCause().getMessage().contains("left over from an earlier build")); + } + assertNull("the stale value must not have been applied", + target.getProperty("codename1.arg.ios.teamId")); + } + + /** The fingerprint of the annotations the build actually compiled matches. */ + @Test + public void aManifestGeneratedFromTheCompiledAnnotationsIsAccepted() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "cn1.buildHints.sourceDigest=" + + digestOf("@Ios(teamId = \"ABCDE12345\")") + "\n" + + "codename1.arg.ios.teamId=ABCDE12345\n"); + writeAnnotatedClass(classes); + + Properties target = new Properties(); + merge(target, classes, "MyApp", "com.example"); + + assertEquals("ABCDE12345", target.getProperty("codename1.arg.ios.teamId")); + } + + /** + * A manifest with no fingerprint in it cannot be judged, so it is taken at + * face value rather than refused on a guess. + */ + @Test + public void aManifestWithNoFingerprintIsStillTrusted() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "codename1.arg.ios.teamId=OLD\n"); + writeAnnotatedClass(classes); + + Properties target = new Properties(); + merge(target, classes, "MyApp", "com.example"); + + assertEquals("OLD", target.getProperty("codename1.arg.ios.teamId")); + } + + /** + * The fingerprint covers the annotations and nothing else, so editing the + * properties file cannot invalidate it. With processing skipped, a line added + * for a hint an annotation already sets left a manifest that still matched -- + * and the overlay quietly replaced the value the developer had just written, + * until the next clean build regenerated the manifest and failed instead. + */ + @Test + public void aPropertiesLineForAnAnnotatedHintIsRefusedNotOverwritten() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "cn1.buildHints.sourceDigest=" + + digestOf("@Ios(teamId = \"ABCDE12345\")") + "\n" + + "cn1.buildHints.origin.ios.teamId=@Ios(teamId)\n" + + "codename1.arg.ios.teamId=ABCDE12345\n"); + writeAnnotatedClass(classes); + + Properties target = new Properties(); + target.setProperty("codename1.arg.ios.teamId", "FROMFILE"); + try { + merge(target, classes, "MyApp", "com.example"); + fail("expected the duplicate declaration to be refused"); + } catch (InvocationTargetException ex) { + String message = String.valueOf(ex.getCause().getMessage()); + assertTrue(message, message.contains("declared twice")); + assertTrue(message, message.contains("@Ios(teamId)")); + } + assertEquals("the file's value must not have been replaced", + "FROMFILE", target.getProperty("codename1.arg.ios.teamId")); + } + + /** A hint only the file sets is not a conflict -- that is the escape hatch. */ + @Test + public void aPropertiesLineForAnUnannotatedHintIsLeftAlone() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "cn1.buildHints.sourceDigest=" + + digestOf("@Ios(teamId = \"ABCDE12345\")") + "\n" + + "codename1.arg.ios.teamId=ABCDE12345\n"); + writeAnnotatedClass(classes); + + Properties target = new Properties(); + target.setProperty("codename1.arg.ios.pods", "Alamofire"); + + merge(target, classes, "MyApp", "com.example"); + + assertEquals("Alamofire", target.getProperty("codename1.arg.ios.pods")); + assertEquals("ABCDE12345", target.getProperty("codename1.arg.ios.teamId")); + } + + // ------------------------------------------------------------------ + // helpers + // ------------------------------------------------------------------ + + /** + * Accepting a manifest does not mean the processor ran THIS build. Its + * fingerprint covers the main class, so an annotation added to a live class + * beside it leaves the manifest looking entirely current -- and with the + * goal unbound or skipped the build succeeded having neither applied that + * class's hints nor said the annotation was in the wrong place. + */ + @Test + public void aMisplacedAnnotationIsRefusedEvenWhenTheManifestIsCurrent() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "cn1.buildHints.sourceDigest=" + + digestOf("@Ios(teamId = \"ABCDE12345\")") + "\n" + + "codename1.arg.ios.teamId=ABCDE12345\n"); + writeAnnotatedClass(classes); + File src = writeAnnotatedHelperSource(); + compileInto(classes, "com.example.Helper", helperSource()); + + Properties target = new Properties(); + try { + merge(target, classes, "MyApp", "com.example", src); + fail("expected the misplaced annotation to be refused"); + } catch (InvocationTargetException ex) { + assertTrue(String.valueOf(ex.getCause().getMessage()), + ex.getCause().getMessage().contains("com.example.Helper")); + } + } + + /** The main class carrying them is the whole point, so it is not a misplacement. */ + @Test + public void theMainClassCarryingAnnotationsIsNotAMisplacement() throws Exception { + File classes = manifest("cn1.buildHints.mainClass=com.example.MyApp\n" + + "cn1.buildHints.sourceDigest=" + + digestOf("@Ios(teamId = \"ABCDE12345\")") + "\n" + + "codename1.arg.ios.teamId=ABCDE12345\n"); + writeAnnotatedClass(classes); + + Properties target = new Properties(); + merge(target, classes, "MyApp", "com.example", writeAnnotatedHelperSource()); + + assertEquals("ABCDE12345", target.getProperty("codename1.arg.ios.teamId")); + } + + private static String helperSource() { + return "package com.example;\n" + + "import com.codename1.annotations.buildhints.Ios;\n" + + "@Ios(pods = \"Alamofire\")\n" + + "public class Helper {\n}\n"; + } + + /** A source root holding Helper.java, so the class counts as live. */ + private File writeAnnotatedHelperSource() throws Exception { + File src = tmp.newFolder(); + File f = new File(src, "com/example/Helper.java"); + f.getParentFile().mkdirs(); + try (Writer w = new OutputStreamWriter(new FileOutputStream(f), "UTF-8")) { + w.write(helperSource()); + } + return src; + } + + private void compileInto(File classes, String binaryName, String source) throws Exception { + com.codename1.maven.annotations.JavaSourceCompiler.compile( + com.codename1.maven.annotations.JavaSourceCompiler.singleSource( + binaryName, source), + classes, + Arrays.asList(new File(Class.forName("com.codename1.annotations.buildhints.Ios") + .getProtectionDomain().getCodeSource().getLocation().toURI()))); + } + + private File manifest(String body) throws Exception { + File classes = tmp.newFolder(); + File out = new File(classes, RESOURCE); + out.getParentFile().mkdirs(); + try (Writer w = new OutputStreamWriter(new FileOutputStream(out), "ISO-8859-1")) { + w.write(body); + } + return classes; + } + + /** Compiles a main class carrying one build hint annotation. */ + private void writeAnnotatedClass(File classes) throws Exception { + com.codename1.maven.annotations.JavaSourceCompiler.compile( + com.codename1.maven.annotations.JavaSourceCompiler.singleSource( + "com.example.MyApp", + "package com.example;\n" + + "import com.codename1.annotations.buildhints.Ios;\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "public class MyApp {\n}\n"), + classes, + Arrays.asList(new File(Class.forName("com.codename1.annotations.buildhints.Ios") + .getProtectionDomain().getCodeSource().getLocation().toURI()))); + } + + /** + * Drives the shipped merge rather than a restatement of it, so a change to + * the rule is a change to what this asserts. + */ + private void merge(Properties target, File classesDir, String mainName, String pkg) + throws Exception { + merge(target, classesDir, mainName, pkg, null); + } + + private void merge(Properties target, File classesDir, String mainName, String pkg, + File sourceRoot) throws Exception { + CN1BuildMojo mojo = new CN1BuildMojo(); + if (sourceRoot != null) { + org.apache.maven.project.MavenProject p = new org.apache.maven.project.MavenProject(); + p.addCompileSourceRoot(sourceRoot.getAbsolutePath()); + Field proj = findField(mojo.getClass(), "project"); + proj.setAccessible(true); + proj.set(mojo, p); + } + + Properties settings = new Properties(); + settings.setProperty("codename1.mainName", mainName); + settings.setProperty("codename1.packageName", pkg); + Field props = findField(mojo.getClass(), "properties"); + props.setAccessible(true); + props.set(mojo, settings); + + List cp = Collections.singletonList(classesDir.getAbsolutePath()); + Method m = findMethod(mojo.getClass(), "mergeAnnotationBuildHints", + Properties.class, List.class); + m.setAccessible(true); + m.invoke(mojo, target, cp); + } + + private static Field findField(Class type, String name) throws NoSuchFieldException { + for (Class c = type; c != null; c = c.getSuperclass()) { + try { + return c.getDeclaredField(name); + } catch (NoSuchFieldException keepLooking) { + // up the chain + } + } + throw new NoSuchFieldException(name); + } + + private static Method findMethod(Class type, String name, Class... args) + throws NoSuchMethodException { + for (Class c = type; c != null; c = c.getSuperclass()) { + try { + return c.getDeclaredMethod(name, args); + } catch (NoSuchMethodException keepLooking) { + // up the chain + } + } + throw new NoSuchMethodException(name); + } + + /** The fingerprint the processor would record for a main class annotated so. */ + private String digestOf(String annotations) throws Exception { + File dir = tmp.newFolder(); + com.codename1.maven.annotations.JavaSourceCompiler.compile( + com.codename1.maven.annotations.JavaSourceCompiler.singleSource( + "com.example.MyApp", + "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + annotations + "\n" + + "public class MyApp {\n}\n"), + dir, + Arrays.asList(new File(Class.forName("com.codename1.annotations.buildhints.Ios") + .getProtectionDomain().getCodeSource().getLocation().toURI()))); + return com.codename1.maven.processors.BuildHintAnnotationProcessor.sourceDigest( + com.codename1.maven.annotations.ClassScanner.readClass( + new File(dir, "com/example/MyApp.class"))); + } +} diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/CompileSourceRootsTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/CompileSourceRootsTest.java new file mode 100644 index 00000000000..751b6ae6306 --- /dev/null +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/CompileSourceRootsTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012, 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.codename1.maven; + +import org.apache.maven.model.Build; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginExecution; +import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.Xpp3DomBuilder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.StringReader; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Where a source could be compiled from. + * + *

This list is used to decide that a source is ABSENT -- an annotated class + * with no source behind it is dropped as an orphan, taking its placement error + * with it -- so a list that is merely incomplete must not be read as that, and + * one that is too wide is just as wrong in the other direction.

+ */ +public class CompileSourceRootsTest { + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + /** The Kotlin plugin compiles its own sourceDirs without adding them back. */ + @Test + public void theKotlinPluginsConfiguredDirectoriesCount() throws Exception { + File basedir = tmp.newFolder(); + new File(basedir, "src/main/kotlin").mkdirs(); + MavenProject project = projectAt(basedir); + project.addCompileSourceRoot(new File(basedir, "src/main/java").getAbsolutePath()); + + Plugin kotlin = new Plugin(); + kotlin.setArtifactId("kotlin-maven-plugin"); + kotlin.setConfiguration(config("src/shared/kotlin")); + kotlin.addExecution(execution("compile", "src/extra/kotlin")); + kotlin.addExecution( + execution("test-compile", "src/test/kotlin")); + project.getBuild().addPlugin(kotlin); + + List roots = AbstractCN1Mojo.compileSourceRoots(project); + + // What Maven listed, the conventional Kotlin root, and the dirs the + // plugin compiles. + assertTrue(roots.toString(), contains(roots, basedir, "src/main/java")); + assertTrue(roots.toString(), contains(roots, basedir, "src/main/kotlin")); + assertTrue(roots.toString(), contains(roots, basedir, "src/shared/kotlin")); + assertTrue(roots.toString(), contains(roots, basedir, "src/extra/kotlin")); + + // NOT the test execution's: a same-named test fixture would then make a + // deleted production class look like it still has a source. + assertFalse(roots.toString(), contains(roots, basedir, "src/test/kotlin")); + } + + /** A conventional root that does not exist is not invented. */ + @Test + public void anAbsentKotlinRootIsNotAdded() throws Exception { + File basedir = tmp.newFolder(); + MavenProject project = projectAt(basedir); + assertFalse(contains(AbstractCN1Mojo.compileSourceRoots(project), basedir, + "src/main/kotlin")); + } + + /** No project is "not told", which the callers read as inconclusive. */ + @Test + public void noProjectIsNoAnswer() { + org.junit.Assert.assertNull(AbstractCN1Mojo.compileSourceRoots(null)); + } + + private MavenProject projectAt(File basedir) { + MavenProject project = new MavenProject(); + project.setBuild(new Build()); + project.setFile(new File(basedir, "pom.xml")); + return project; + } + + private static PluginExecution execution(String goal, String configuration) throws Exception { + PluginExecution execution = new PluginExecution(); + execution.setGoals(Arrays.asList(goal)); + execution.setConfiguration(config(configuration)); + return execution; + } + + private static Xpp3Dom config(String inner) throws Exception { + return Xpp3DomBuilder.build(new StringReader("" + inner + + "")); + } + + private static boolean contains(List roots, File basedir, String relative) { + return roots != null + && roots.contains(new File(basedir, relative).getAbsolutePath()); + } +} diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/MigrateBuildHintsPropertyParsingTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/MigrateBuildHintsPropertyParsingTest.java new file mode 100644 index 00000000000..29c9eba1150 --- /dev/null +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/MigrateBuildHintsPropertyParsingTest.java @@ -0,0 +1,862 @@ +/* + * Copyright (c) 2012, 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.codename1.maven; + +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNull; + +/// Covers the properties parsing in `MigrateBuildHintsMojo`. +/// +/// The migration deletes a hint's declaration and replaces it with an +/// annotation. A declaration the deletion pass fails to recognise is left +/// behind while the annotation is added, and the very next build fails with the +/// duplicate-hint error the goal exists to prevent -- so the parser has to +/// accept every form `java.util.Properties` does, not just `key=value`. +public class MigrateBuildHintsPropertyParsingTest { + + @Test + public void equalsSeparatorIsRecognized() { + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf("codename1.arg.ios.teamId=ABCDE")); + } + + @Test + public void colonSeparatorIsRecognized() { + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf("codename1.arg.ios.teamId:ABCDE")); + } + + /// The form that used to survive the deletion pass and break the next build. + @Test + public void whitespaceSeparatorIsRecognized() { + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf("codename1.arg.ios.teamId ABCDE")); + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf("codename1.arg.ios.teamId\tABCDE")); + } + + @Test + public void leadingWhitespaceIsIgnored() { + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf(" codename1.arg.ios.teamId = ABCDE")); + } + + @Test + public void spacingAroundTheSeparatorIsIgnored() { + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf("codename1.arg.ios.teamId = ABCDE")); + } + + /// A key may escape the characters that would otherwise end it. + @Test + public void escapedSeparatorsStayPartOfTheKey() { + assertEquals("a=b", MigrateBuildHintsMojo.propertyKeyOf("a\\=b=value")); + assertEquals("a b", MigrateBuildHintsMojo.propertyKeyOf("a\\ b=value")); + assertEquals("a:b", MigrateBuildHintsMojo.propertyKeyOf("a\\:b=value")); + } + + @Test + public void commentsAndBlanksDeclareNothing() { + assertNull(MigrateBuildHintsMojo.propertyKeyOf("# codename1.arg.ios.teamId=ABCDE")); + assertNull(MigrateBuildHintsMojo.propertyKeyOf("! codename1.arg.ios.teamId=ABCDE")); + assertNull(MigrateBuildHintsMojo.propertyKeyOf("")); + assertNull(MigrateBuildHintsMojo.propertyKeyOf(" ")); + } + + /// Kotlin interpolates `$` inside a string; Java does not. A hint value + /// carrying one -- a Gradle snippet such as `${'$'}{version}` -- would either + /// fail to compile as an unresolved reference or resolve to something else. + @Test + public void dollarSignsAreEscapedOnlyForKotlin() { + assertEquals("\"implementation 'x:y:\\$version'\"", + MigrateBuildHintsMojo.quoteFor("implementation 'x:y:$version'", true)); + assertEquals("\"implementation 'x:y:$version'\"", + MigrateBuildHintsMojo.quoteFor("implementation 'x:y:$version'", false)); + } + + /// The class declaration is the only safe anchor in a default-package source: + /// there is no `package` line, and the old arithmetic put the import at the + /// first newline in the file, which is inside the copyright comment. + @Test + public void aDefaultPackageSourceStillGetsAUsableAnchor() { + String src = "/*\n * Copyright\n */\npublic class MyApp {\n}\n"; + assertEquals(src.indexOf("public class MyApp"), + MigrateBuildHintsMojo.classDeclarationIndex(src, false, "MyApp")); + } + + @Test + public void aValueOnlyLineHasNoSeparator() { + assertEquals("bare", MigrateBuildHintsMojo.propertyKeyOf("bare")); + } + + /// `Properties.load` turns a `\\u20ac` in the settings file into a real euro + /// sign, and the migrated source is written back through ISO-8859-1 to keep + /// the untouched part of the file byte-identical. Emitting the character raw + /// would write `?` for anything ISO-8859-1 cannot map, and a high byte for + /// anything it can -- which corrupts a UTF-8 source. The verification build + /// would not notice: it checks that the hint came back, not its value. + @Test + public void aNonAsciiCharacterIsWrittenAsAnAsciiEscape() { + assertEquals("\"a\\u20acb\"", MigrateBuildHintsMojo.quoteFor("a\u20acb", false)); + assertEquals("\"a\\u20acb\"", MigrateBuildHintsMojo.quoteFor("a\u20acb", true)); + // Latin-1 is mappable and still escaped: the source may well be UTF-8. + assertEquals("\"caf\\u00e9\"", MigrateBuildHintsMojo.quoteFor("caf\u00e9", false)); + } + + /// A backslash before an escaped character has to stay a backslash. In Java a + /// unicode escape is recognised before parsing and only after an even number + /// of backslashes, so the doubled pair plus our own opener is what makes this + /// come out right rather than a coincidence. + @Test + public void aBackslashBeforeAnEscapedCharacterSurvives() { + assertEquals("\"\\\\\\u00e9\"", MigrateBuildHintsMojo.quoteFor("\\\u00e9", false)); + } + + /// Control characters without a short escape would otherwise go in raw. + @Test + public void aControlCharacterIsEscaped() { + assertEquals("\"\\u0001\"", MigrateBuildHintsMojo.quoteFor("\u0001", false)); + } + + /// `Properties.load` decodes a Unicode escape in a KEY too, so the key this parser + /// returns has to be the decoded one. Reading the escape literally left the + /// original line in place, and the migration then rolled back over a + /// duplicate declaration it had created itself. + @Test + public void aUnicodeEscapeInAKeyIsDecoded() { + assertEquals("codename1.arg.ios.teamId", + MigrateBuildHintsMojo.propertyKeyOf("codename1.arg.\\u0069os.teamId=ABCDE")); + } + + /// Not every backslash-u is an escape. Four hex digits or it is a literal u. + @Test + public void aMalformedUnicodeEscapeIsNotDecoded() { + assertEquals("a.uZZZZb", MigrateBuildHintsMojo.propertyKeyOf("a.\\uZZZZb=1")); + } + + /// A documented spelling that is not its own constant migrates to the one it + /// means, rather than being refused as outside the domain -- which is what an + /// existing project setting a legacy spelling would have hit. + @Test + public void anAcceptedSpellingMigratesToTheConstantItMeans() { + MigrateBuildHintsMojo mojo = new MigrateBuildHintsMojo(); + com.codename1.build.shared.BuildHints.Hint ios = + com.codename1.build.shared.BuildHints.byName("ios.themeMode"); + assertEquals("IosThemeMode.IOS7", mojo.toSourceLiteral(ios, "flat", false)); + assertEquals("IosThemeMode.MODERN", mojo.toSourceLiteral(ios, "liquid", false)); + assertEquals("IosThemeMode.MODERN", mojo.toSourceLiteral(ios, "modern", false)); + assertNull(mojo.toSourceLiteral(ios, "nonsense", false)); + } + + /// A value that is not already canonical is refused, not normalised. + /// AndroidGradleBuilder compares android.hideStatusBar with .equals("true"), + /// so `TRUE` is false today and migrating it to `true` would flip the app's + /// behaviour while reporting a successful migration. + @Test + public void aNonCanonicalScalarIsRefused() { + MigrateBuildHintsMojo mojo = new MigrateBuildHintsMojo(); + com.codename1.build.shared.BuildHints.Hint bool = + com.codename1.build.shared.BuildHints.byName("android.hideStatusBar"); + assertEquals("true", mojo.toSourceLiteral(bool, "true", false)); + assertNull(mojo.toSourceLiteral(bool, "TRUE", false)); + assertNull(mojo.toSourceLiteral(bool, "True", false)); + assertNull(mojo.toSourceLiteral(bool, "true ", false)); + + com.codename1.build.shared.BuildHints.Hint ios = + com.codename1.build.shared.BuildHints.byName("ios.themeMode"); + assertEquals("IosThemeMode.MODERN", mojo.toSourceLiteral(ios, "modern", false)); + assertNull(mojo.toSourceLiteral(ios, "MODERN", false)); + } + + /// An int that does not round-trip would be rewritten too. + @Test + public void anIntThatDoesNotRoundTripIsRefused() { + MigrateBuildHintsMojo mojo = new MigrateBuildHintsMojo(); + com.codename1.build.shared.BuildHints.Hint i = + com.codename1.build.shared.BuildHints.byName("android.min_sdk_version"); + assertEquals("24", mojo.toSourceLiteral(i, "24", false)); + assertNull(mojo.toSourceLiteral(i, "024", false)); + assertNull(mojo.toSourceLiteral(i, "+24", false)); + } + + /// Top level is brace depth zero, not column zero. Anchoring to the start of + /// a line refused ` public class MyApp`, which compiles fine -- so the goal + /// rolled back on a project whose source it had just accepted. + @Test + public void anIndentedDeclarationIsStillTopLevel() { + String src = "package com.example;\n\n public final class MyApp {\n}\n"; + int at = MigrateBuildHintsMojo.classDeclarationIndex(src, false, "MyApp"); + assertEquals(src.indexOf(" public final class") + 2, at); + } + + /// The insertion point precedes the modifiers, so the annotations do not land + /// between `public` and `class`. + @Test + public void theInsertionPointPrecedesTheModifiers() { + String src = "package com.example;\npublic abstract class MyApp {\n}\n"; + assertEquals(src.indexOf("public abstract class"), + MigrateBuildHintsMojo.classDeclarationIndex(src, false, "MyApp")); + } + + /// A nested type of the same name is not the top-level declaration. + @Test + public void aNestedTypeIsNotTheInsertionPoint() { + String src = "package com.example;\nclass Outer {\n class MyApp {}\n}\n" + + "class MyApp {}\n"; + assertEquals(src.lastIndexOf("class MyApp {}"), + MigrateBuildHintsMojo.classDeclarationIndex(src, false, "MyApp")); + } + + /// An import goes above EVERY top-level declaration, so the anchor for a + /// file with no package and no import is the first declaration in it -- + /// whatever kind it is. Anchoring on the MAIN class instead put the import + /// below a `fun helper()` written before it, which neither language allows, + /// and verification rolled back a valid migration. + @Test + public void theAnchorIsTheFirstDeclarationNotTheMainClass() { + String kt = "fun helper() {}\n\nclass MyApp\n"; + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration(kt, true)); + + String java = "class Helper {}\n\n@Deprecated\nclass MyApp {}\n"; + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration(java)); + } + + /// A default-package class that already carries an annotation: the import + /// must go ABOVE it. Anchoring on the declaration put the import between the + /// annotation and the class, which is not valid in either language. + @Test + public void theImportGoesAboveAnExistingAnnotation() { + String head = "/* c */\n@SuppressWarnings(\"unchecked\")\n"; + assertEquals(head.indexOf("@SuppressWarnings"), + MigrateBuildHintsMojo.startOfFirstDeclaration(head)); + } + + /// A parenthesis inside an annotation argument must not stop the walk. + @Test + public void anArgumentContainingAParenthesisDoesNotStopTheWalk() { + String head = "@Deprecated\n@SuppressWarnings(\"a(b\")\n"; + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration(head)); + } + + /// With no declaration there is nothing to go above. + @Test + public void withNoDeclarationTheAnchorIsTheEnd() { + String head = "/* copyright */\n\n"; + assertEquals(head.length(), MigrateBuildHintsMojo.startOfFirstDeclaration(head)); + } + + /// Modifiers and annotations may interleave: `public @Deprecated final + /// class Main` is legal, and the whole run is below the import. + @Test + public void theAnchorClearsModifiersInterleavedWithAnnotations() { + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration("public @Deprecated ")); + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration("public ")); + } + + /// A Kotlin annotation may have an ESCAPED name, which is code the scan has + /// to read rather than stop on. + @Test + public void anEscapedAnnotationNameIsPartOfTheLeadingRun() { + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration("@`when`\n", true)); + assertEquals(0, + MigrateBuildHintsMojo.startOfFirstDeclaration("@`when`(\"x\")\n@Deprecated\n", true)); + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration("@com.`when`.Ann\n", true)); + } + + /// Kotlin's FILE annotations sit above the package header and the imports + /// both, so the import goes BELOW them -- the one thing the anchor steps + /// over rather than displaces. + @Test + public void aKotlinFileAnnotationStaysAboveTheImport() { + String kt = "@file:Suppress(\"unchecked\")\n@file:JvmName(\"X\")\n\nclass MyApp\n"; + assertEquals(kt.indexOf("class MyApp"), + MigrateBuildHintsMojo.startOfFirstDeclaration(kt, true)); + + // One target may carry a BRACKETED list of annotations. + String grouped = "@file:[JvmName(\"X\") Suppress(\"unchecked\")]\n\nclass MyApp\n"; + assertEquals(grouped.indexOf("class MyApp"), + MigrateBuildHintsMojo.startOfFirstDeclaration(grouped, true)); + + // ...and a bracketed list with no target is not a FILE annotation, so + // the import goes above it like any other. + String untargeted = "@[JvmName(\"X\") Suppress(\"unchecked\")]\nclass MyApp\n"; + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration(untargeted, true)); + + // An ordinary annotation is not a file annotation. + String ordinary = "@Suppress(\"unchecked\")\nclass MyApp\n"; + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration(ordinary, true)); + + // Java has no such form, so `@file` there is an ordinary annotation. + assertEquals(0, MigrateBuildHintsMojo.startOfFirstDeclaration(kt, false)); + } + + /// The migration's source lookup must require a TOP-LEVEL declaration. A + /// leftover Main.kt holding `class Outer { class Main }` otherwise stopped + /// the search, the annotations went onto Outer, and the verification build + /// rejected the placement and rolled the migration back. + @Test + public void onlyATopLevelDeclarationIdentifiesTheMainClass() { + String nested = "package com.example\nclass Outer { class MyApp }\n"; + assertFalse(com.codename1.maven.processors.BuildHintAnnotationProcessor + .declaresNestedPath(nested, new String[] {"MyApp"}, true)); + String topLevel = "package com.example\nclass Outer { }\nclass MyApp\n"; + assertTrue(com.codename1.maven.processors.BuildHintAnnotationProcessor + .declaresNestedPath(topLevel, new String[] {"MyApp"}, true)); + } + + /// The word "package" in a header sentence is not the package declaration. A + /// raw search selected it and the import went in before the real statement, + /// or inside the comment, so the verification build failed and rolled back an + /// otherwise correct migration. + @Test + public void theWordPackageInACommentIsNotTheDeclaration() { + String head = "// The package layout is documented here\npackage com.example;\n\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + assertEquals(head.indexOf("package com.example"), + MigrateBuildHintsMojo.livePackageIndex(code)); + } + + /// The anchor is past the whole declaration, not at the first newline: + /// `package\ncom.example;` is valid Java and cutting there would put the + /// import inside the statement. + @Test + public void theAnchorClearsAMultiLinePackageDeclaration() { + String head = "package\ncom.example;\nclass X {}\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int pkg = MigrateBuildHintsMojo.livePackageIndex(code); + assertEquals(head.indexOf("class X"), + MigrateBuildHintsMojo.endOfPackageDeclaration(code, pkg)); + } + + /// Kotlin has no semicolon; the declaration ends with the name. + @Test + public void aKotlinPackageDeclarationEndsAtItsName() { + String head = "package com.example\nclass X\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, true); + int pkg = MigrateBuildHintsMojo.livePackageIndex(code); + assertEquals(head.indexOf("class X"), + MigrateBuildHintsMojo.endOfPackageDeclaration(code, pkg)); + } + + /// `public\nclass Main` is legal. Stopping at the line break left `public` in + /// the head, so the generated import was written after it -- not valid Java, + /// and the verification build rolled the migration back. + @Test + public void modifiersOnEarlierLinesArePartOfTheDeclaration() { + String src = "public\nfinal\nclass MyApp {\n}\n"; + assertEquals(0, MigrateBuildHintsMojo.classDeclarationIndex(src, false, "MyApp")); + + String annotated = "@Deprecated\npublic\nclass MyApp {\n}\n"; + assertEquals(annotated.indexOf("public"), + MigrateBuildHintsMojo.classDeclarationIndex(annotated, false, "MyApp")); + } + + /// ...and the walk still stops at a word that is not a modifier. + @Test + public void aNonModifierWordStopsTheWalk() { + String src = "interface Other {}\npublic class MyApp {}\n"; + assertEquals(src.indexOf("public class"), + MigrateBuildHintsMojo.classDeclarationIndex(src, false, "MyApp")); + } + + /// The words in a comment are not an import. A javadoc line mentioning the + /// package aborted the migration on a source that compiles perfectly well. + @Test + public void mentioningThePackageIsNotImportingIt() { + String mention = com.codename1.maven.processors.BuildHintAnnotationProcessor.blankNonCode( + "// see com.codename1.annotations.buildhints for the annotations\n" + + "public class MyApp {}\n", false); + assertFalse(MigrateBuildHintsMojo.importsBuildHints(mention)); + + String real = com.codename1.maven.processors.BuildHintAnnotationProcessor.blankNonCode( + "import com.codename1.annotations.buildhints.Ios;\npublic class MyApp {}\n", + false); + assertTrue(MigrateBuildHintsMojo.importsBuildHints(real)); + } + + /// An import may legally span lines, so the insertion point is the end of the + /// DECLARATION. Cutting at the first newline after the keyword spliced the + /// new import into the middle of the old one. + @Test + public void theInsertionPointClearsAMultiLineImport() { + String head = "import java.\n util.List;\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int last = MigrateBuildHintsMojo.lastImportIndex(code); + assertEquals(head.length(), MigrateBuildHintsMojo.endOfImportDeclaration(code, last)); + } + + /// A Kotlin main class may escape its name in backticks, and + /// `codename1.mainName` holds the name between them. Reading only identifier + /// characters recorded nothing, so the goal reported "Could not find the + /// class declaration" and rolled back a valid migration of a file the + /// lookup had just accepted as the right one. + @Test + public void theDeclarationLocatorReadsAnEscapedKotlinName() { + String src = "package com.example\n\nclass `when` {\n}\n"; + assertEquals(src.indexOf("class `when`"), + MigrateBuildHintsMojo.classDeclarationIndex(src, true, "when")); + // An escaped declaration also counts as the first one, which is what a + // name that matches nothing falls back to. Recording no name at all left + // even that fallback unset. + assertEquals(src.indexOf("class `when`"), + MigrateBuildHintsMojo.classDeclarationIndex(src, true, "Other")); + } + + /// `blankNonCode` leaves an escaped identifier as the code it is, so a + /// scanner looking for a KEYWORD has to step over it. `fun `import`() {}` + /// declares a function called import, and reading it as an import directive + /// put the generated import after a top-level declaration -- where Kotlin + /// does not allow one, so verification failed and rolled back a valid + /// migration. + @Test + public void anEscapedIdentifierIsNotAKeyword() { + String kt = "package com.example\n\nfun `import`() {}\n\nclass MyApp\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(kt, true); + assertEquals(-1, MigrateBuildHintsMojo.lastImportIndex(code)); + assertFalse(MigrateBuildHintsMojo.importsBuildHints(code)); + assertEquals(0, MigrateBuildHintsMojo.livePackageIndex(code)); + + // ...and the package keyword the same way. A file with no package + // declaration at all has none, whatever a function is called. + String noPackage = "fun `package`() {}\n\nclass MyApp\n"; + assertEquals(-1, MigrateBuildHintsMojo.livePackageIndex( + com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(noPackage, true))); + } + + /// The build hints PACKAGE, not any name that starts with its letters. An + /// unrelated `com.codename1.annotations.buildhintsExtra.Widget` read as + /// "already imported" and aborted a migration with nothing to conflict with. + @Test + public void anImportOfALongerPackageIsNotOurs() { + String other = com.codename1.maven.processors.BuildHintAnnotationProcessor.blankNonCode( + "import com.codename1.annotations.buildhintsExtra.Widget;\n" + + "public class MyApp {}\n", false); + assertFalse(MigrateBuildHintsMojo.importsBuildHints(other)); + + String ours = com.codename1.maven.processors.BuildHintAnnotationProcessor.blankNonCode( + "import com.codename1.annotations.buildhints.*;\npublic class MyApp {}\n", + false); + assertTrue(MigrateBuildHintsMojo.importsBuildHints(ours)); + } + + /// A blanked block comment keeps its newlines, so + /// `import foo.Bar /* note\n */ ;` left the semicolon unconsumed and ended + /// the declaration at that newline -- INSIDE the comment, where the + /// generated import was then written and stayed commented out. + @Test + public void theInsertionPointClearsAMultiLineTrailingComment() { + String head = "import foo.Bar /* note\n */ ;\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int last = MigrateBuildHintsMojo.lastImportIndex(code); + assertEquals(head.length(), MigrateBuildHintsMojo.endOfImportDeclaration(code, last)); + } + + /// The package declaration has the same terminator and the same hazard. + @Test + public void theAnchorClearsAMultiLineTrailingComment() { + String head = "package com.example /* note\n */ ;\nclass X {}\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int pkg = MigrateBuildHintsMojo.livePackageIndex(code); + assertEquals(head.indexOf("class X"), + MigrateBuildHintsMojo.endOfPackageDeclaration(code, pkg)); + } + + /// `static` is a modifier, not the imported name. Reading it as the name + /// ended the declaration at the newline inside the REAL name, so the + /// generated import was spliced into the middle of the static import and the + /// verification build rolled back a valid migration. + @Test + public void theInsertionPointClearsAMultiLineStaticImport() { + String head = "import static java.util.\n Collections.emptyList;\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int last = MigrateBuildHintsMojo.lastImportIndex(code); + assertEquals(head.length(), MigrateBuildHintsMojo.endOfImportDeclaration(code, last)); + } + + /// A name that merely STARTS with `static` is a name. + @Test + public void anImportOfATypeNamedStaticallyIsNotAStaticImport() { + String head = "import staticky.Thing;\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int last = MigrateBuildHintsMojo.lastImportIndex(code); + assertEquals(head.length(), MigrateBuildHintsMojo.endOfImportDeclaration(code, last)); + } + + /// A Kotlin alias belongs to the declaration too. + @Test + public void theInsertionPointClearsAKotlinAlias() { + String head = "import com.example.Ios as TheirIos\nclass X\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, true); + int last = MigrateBuildHintsMojo.lastImportIndex(code); + assertEquals(head.indexOf("class X"), + MigrateBuildHintsMojo.endOfImportDeclaration(code, last)); + } + + /// The LAST import is the anchor, not the first. + @Test + public void theAnchorIsTheLastImport() { + String head = "import a.B;\nimport c.D;\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + assertEquals(head.indexOf("import c.D"), MigrateBuildHintsMojo.lastImportIndex(code)); + } + + /// `package com.\nexample;` is legal, and a contiguous scan stops at the + /// newline -- so the import was inserted before `example;`, producing invalid + /// source, and the verification build rolled back a correct migration. + @Test + public void theAnchorClearsAPackageNameThatSpansLines() { + String head = "package com.\nexample;\nclass X {}\n"; + String code = com.codename1.maven.processors.BuildHintAnnotationProcessor + .blankNonCode(head, false); + int pkg = MigrateBuildHintsMojo.livePackageIndex(code); + assertEquals(head.indexOf("class X"), + MigrateBuildHintsMojo.endOfPackageDeclaration(code, pkg)); + } + + /// The goal promises to delete the migrated declarations and leave every + /// other line byte for byte as it was. Reading with readLine() discarded + /// each terminator, and appending a newline to every retained line rewrote a + /// CRLF checkout end to end -- a whole-file diff from a goal that should + /// have touched three lines. + @Test + public void removingLinesKeepsTheFilesOwnLineEndings() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + String before = "# a comment\r\n" + + "codename1.displayName=Demo\r\n" + + "codename1.arg.ios.pods=Alamofire\r\n" + + "codename1.arg.android.min_sdk_version=24\r\n"; + write(f, before); + + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.pods")); + + assertEquals("# a comment\r\n" + + "codename1.displayName=Demo\r\n" + + "codename1.arg.android.min_sdk_version=24\r\n", + read(f)); + } + + /// A file that does not end in a newline must not acquire one, and a mixed + /// file keeps each line as it found it. + @Test + public void removingLinesInventsNoTerminator() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + write(f, "codename1.arg.ios.pods=Alamofire\n" + + "codename1.displayName=Demo\r\n" + + "codename1.arg.ios.teamId=ABCDE12345"); + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.pods")); + assertEquals("codename1.displayName=Demo\r\n" + + "codename1.arg.ios.teamId=ABCDE12345", read(f)); + } + + /// A continuation belongs to its declaration, terminators included. + @Test + public void removingAContinuedDeclarationTakesEveryLineOfIt() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + write(f, "codename1.arg.ios.pods=Alamofire,\\\r\n" + + " SwiftyJSON\r\n" + + "codename1.displayName=Demo\r\n"); + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.pods")); + assertEquals("codename1.displayName=Demo\r\n", read(f)); + } + + private static void write(File f, String text) throws Exception { + java.io.Writer w = new java.io.OutputStreamWriter( + new java.io.FileOutputStream(f), "ISO-8859-1"); + try { + w.write(text); + } finally { + w.close(); + } + } + + private static String read(File f) throws Exception { + byte[] all = java.nio.file.Files.readAllBytes(f.toPath()); + return new String(all, "ISO-8859-1"); + } + + /// The source is read byte for byte, while `codename1.packageName` and + /// `codename1.mainName` come from a properties file and are real Unicode. + /// For an ASCII name the two spellings are identical; for + /// `package com.\u5e94\u7528` in a UTF-8 file they are not, and comparing + /// only the Unicode one made the goal refuse a valid migration saying it + /// could not find the main source. + @Test + public void aNonAsciiNameIsMatchedAsTheSourceSpellsIt() throws Exception { + String pkg = "com.\u5e94\u7528"; + String asWritten = MigrateBuildHintsMojo.asWrittenInSource(pkg); + // The bytes of the UTF-8 file, read one per character. + assertEquals(new String(pkg.getBytes("UTF-8"), "ISO-8859-1"), asWritten); + assertTrue("a non-ASCII name must read differently", !asWritten.equals(pkg)); + + // An ASCII name is untouched, so nothing about the common case changes. + assertEquals("com.example", MigrateBuildHintsMojo.asWrittenInSource("com.example")); + + // And the declaration locator accepts either spelling of the class name. + String source = "package " + asWritten + ";\n\nclass " + + MigrateBuildHintsMojo.asWrittenInSource("\u5e94\u7528") + " {\n}\n"; + assertEquals(source.indexOf("class "), + MigrateBuildHintsMojo.classDeclarationIndex(source, false, "\u5e94\u7528")); + } + + /// The continuation backslash is a MARKER, not part of the value. + /// `Properties.load` drops it, so leaving it in made `key\` + ` =value` read + /// as an escaped `=`; the key never matched the one being migrated, the + /// declaration stayed behind, and the verification build failed on the + /// duplicate the goal had just created. + @Test + public void aSeparatorOnAContinuationLineStillNamesItsKey() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + write(f, "codename1.arg.ios.teamId\\\n" + + " =ABCDE12345\n" + + "codename1.displayName=Demo\n"); + + // Exactly what Properties.load calls the key, so the plan and the + // removal cannot disagree about it. + java.util.Properties loaded = new java.util.Properties(); + java.io.InputStream in = new java.io.FileInputStream(f); + try { + loaded.load(in); + } finally { + in.close(); + } + assertEquals("ABCDE12345", loaded.getProperty("codename1.arg.ios.teamId")); + + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.teamId")); + assertEquals("codename1.displayName=Demo\n", read(f)); + } + + /// A continuation marker with nothing after it is still a marker: a file + /// whose last byte is that backslash reads as an empty value to + /// `Properties.load`, while leaving it in produced a key ending in `\` that + /// matched nothing -- so the declaration stayed and the verification build + /// failed on the duplicate. + @Test + public void aContinuationMarkerAtTheEndOfTheFileIsStillAMarker() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + write(f, "codename1.displayName=Demo\n" + + "codename1.arg.ios.teamId\\"); + + java.util.Properties loaded = new java.util.Properties(); + java.io.InputStream in = new java.io.FileInputStream(f); + try { + loaded.load(in); + } finally { + in.close(); + } + assertEquals("", loaded.getProperty("codename1.arg.ios.teamId")); + + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.teamId")); + assertEquals("codename1.displayName=Demo\n", read(f)); + } + + /// A comment is a natural line: continuation does not apply to it, so + /// `# note \` ends at the newline and the declaration below it is an + /// ordinary property. Joining the two made the pair read as a comment, so + /// the migrated declaration was retained and the verification build failed + /// on the duplicate. + @Test + public void aCommentEndingInABackslashDoesNotSwallowTheNextLine() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + write(f, "# note \\\n" + + "codename1.arg.ios.pods=Alamofire\n" + + "codename1.displayName=Demo\n"); + + java.util.Properties loaded = new java.util.Properties(); + java.io.InputStream in = new java.io.FileInputStream(f); + try { + loaded.load(in); + } finally { + in.close(); + } + assertEquals("Alamofire", loaded.getProperty("codename1.arg.ios.pods")); + + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.pods")); + assertEquals("# note \\\ncodename1.displayName=Demo\n", read(f)); + } + + /// A `!` comment is a comment too, and a real continuation still continues. + @Test + public void onlyCommentsAreExemptFromContinuation() throws Exception { + File f = File.createTempFile("cn1-settings", ".properties"); + f.deleteOnExit(); + write(f, "! note \\\n" + + "codename1.arg.ios.pods=Alamofire,\\\n" + + " SwiftyJSON\n" + + "codename1.displayName=Demo\n"); + + MigrateBuildHintsMojo.removeMigratedLines(f, + java.util.Arrays.asList("codename1.arg.ios.pods")); + assertEquals("! note \\\ncodename1.displayName=Demo\n", read(f)); + } + + /// A wildcard import loses to an explicit `import com.example.Build;` and to + /// a type in the file's own package, so the generated `@Build` referred to + /// theirs and the verification build failed. Named imports are written + /// instead, and the fully qualified name for any simple name the file has + /// already given away. + @Test + public void theGeneratedAnnotationsNameOurAnnotations() throws Exception { + String migrated = migrate("package com.example;\n" + + "import com.example.other.Build;\n" + + "public class MyApp {\n}\n", + "@Build(nativeTheme = NativeThemeMode.MODERN)\n@Ios(teamId = \"X\")\n"); + + // The taken name is qualified and not imported... + assertTrue(migrated, + migrated.contains("@com.codename1.annotations.buildhints.Build(nativeTheme")); + assertFalse(migrated, + migrated.contains("import com.codename1.annotations.buildhints.Build;")); + // ...the free one is imported and written plainly... + assertTrue(migrated, migrated.contains("import com.codename1.annotations.buildhints.Ios;")); + assertTrue(migrated, migrated.contains("@Ios(teamId")); + // ...and the package is never imported on demand. + assertFalse(migrated, migrated.contains("buildhints.*")); + } + + /// A type in the file's own package is beaten by the named import, so it is + /// not a collision; a type in THIS file cannot be imported at all. + @Test + public void onlyThisFilesOwnDeclarationForcesTheQualifiedName() throws Exception { + String plain = migrate("package com.example;\npublic class MyApp {\n}\n", + "@Ios(teamId = \"X\")\n"); + assertTrue(plain, plain.contains("import com.codename1.annotations.buildhints.Ios;")); + assertTrue(plain, plain.contains("@Ios(teamId")); + + String declaresIt = migrate("package com.example;\n" + + "@interface Ios { String teamId(); }\n" + + "public class MyApp {\n}\n", + "@Ios(teamId = \"X\")\n"); + assertTrue(declaresIt, + declaresIt.contains("@com.codename1.annotations.buildhints.Ios(teamId")); + assertFalse(declaresIt, + declaresIt.contains("import com.codename1.annotations.buildhints.Ios;")); + } + + /// A Kotlin alias is a TOKEN, and `import com.example.Other as\nIos` is + /// legal. Searching for the literal `" as "` missed it, so the goal wrote + /// its own `import ...buildhints.Ios` beside it -- two imports giving the + /// same local name, which does not compile. + @Test + public void anAliasSpanningLinesStillTakesTheName() throws Exception { + String migrated = migrateKotlin("package com.example\n" + + "import com.example.other.Other as\n Ios\n" + + "class MyApp\n", + "@Ios(teamId = \"X\")\n"); + assertTrue(migrated, + migrated.contains("@com.codename1.annotations.buildhints.Ios(teamId")); + assertFalse(migrated, migrated.contains("import com.codename1.annotations.buildhints.Ios")); + + // An alias that takes some OTHER name leaves ours alone. + String free = migrateKotlin("package com.example\n" + + "import com.example.other.Other as\n Something\n" + + "class MyApp\n", + "@Ios(teamId = \"X\")\n"); + assertTrue(free, free.contains("import com.codename1.annotations.buildhints.Ios")); + assertTrue(free, free.contains("@Ios(teamId")); + } + + /// An enum-valued hint renders as `IosThemeMode.MODERN`, which is a second + /// type to account for: without its own import the generated annotation does + /// not compile, so every enum-valued migration was rolled back by its own + /// verification build. + @Test + public void anEnumValueBringsItsOwnType() throws Exception { + String migrated = migrate("package com.example;\npublic class MyApp {\n}\n", + "@Ios(themeMode = IosThemeMode.MODERN)\n"); + assertTrue(migrated, + migrated.contains("import com.codename1.annotations.buildhints.IosThemeMode;")); + assertTrue(migrated, migrated.contains("@Ios(themeMode = IosThemeMode.MODERN)")); + + // A file that has given that name away gets the qualified form instead. + String taken = migrate("package com.example;\n" + + "import com.example.other.IosThemeMode;\n" + + "public class MyApp {\n}\n", + "@Ios(themeMode = IosThemeMode.MODERN)\n"); + assertTrue(taken, taken.contains( + "themeMode = com.codename1.annotations.buildhints.IosThemeMode.MODERN")); + assertFalse(taken, + taken.contains("import com.codename1.annotations.buildhints.IosThemeMode;")); + } + + /// A `typealias` is a declaration this file makes, so it takes the name as + /// surely as a class does. Writing a named import beside one gives the same + /// local name twice, which does not compile. + @Test + public void aTypeAliasTakesTheNameTheImportWouldWant() throws Exception { + String migrated = migrateKotlin("package com.example\n" + + "typealias Ios = com.example.other.Ios\n" + + "class MyApp\n", + "@Ios(teamId = \"X\")\n"); + assertTrue(migrated, + migrated.contains("@com.codename1.annotations.buildhints.Ios(teamId")); + assertFalse(migrated, + migrated.contains("import com.codename1.annotations.buildhints.Ios")); + } + + private String migrateKotlin(String source, String annotations) throws Exception { + File f = File.createTempFile("MyApp", ".kt"); + f.deleteOnExit(); + write(f, source); + new MigrateBuildHintsMojo().insertAnnotations(f, annotations, "MyApp"); + return read(f); + } + + /// Runs the real insertion over a temporary file and hands back the result. + private String migrate(String source, String annotations) throws Exception { + File f = File.createTempFile("MyApp", ".java"); + f.deleteOnExit(); + write(f, source); + new MigrateBuildHintsMojo().insertAnnotations(f, annotations, "MyApp"); + return read(f); + } +} diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/OpenSettingsMojoTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/OpenSettingsMojoTest.java index 2dc23db7330..4bdf4e061e5 100644 --- a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/OpenSettingsMojoTest.java +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/OpenSettingsMojoTest.java @@ -157,6 +157,74 @@ public void bindingContainsProjectFilesAndMultimoduleRoot() throws Exception { assertTrue(binding.contains("multimoduleRoot=" + root.getAbsolutePath())); } + /// What Maven RESOLVED, so the Settings tool does not have to infer it from + /// POM text. It has no model: it cannot evaluate a profile activation, + /// follow an inherited `` or expand a property, and each of + /// those has been a way for it to miss the main class and then offer an + /// annotation-owned hint for editing. + @Test + public void bindingCarriesTheResolvedSourceRootsAndEncoding() throws Exception { + File root = tmp.newFolder("resolved"); + File common = new File(root, "common"); + assertTrue(new File(common, "src/main/java").mkdirs()); + assertTrue(new File(common, "appsrc").mkdirs()); + File input = tmp.newFile("resolved.input"); + + OpenSettingsMojo mojo = new OpenSettingsMojo(); + mojo.project = projectAt(common); + mojo.project.addCompileSourceRoot(new File(common, "appsrc").getAbsolutePath()); + mojo.project.getProperties().setProperty("project.build.sourceEncoding", "Shift_JIS"); + + mojo.writeBinding(input, common); + + String binding = new String(Files.readAllBytes(input.toPath()), StandardCharsets.UTF_8); + assertTrue(binding, binding.contains("sourceRoots=")); + assertTrue(binding, binding.contains(new File(common, "src/main/java").getAbsolutePath())); + assertTrue(binding, binding.contains(new File(common, "appsrc").getAbsolutePath())); + assertTrue(binding, binding.contains("sourceEncoding=Shift_JIS")); + } + + /// Maven does not copy a plugin parameter into the project's properties, so + /// a POM that sets `` inside maven-compiler-plugin -- in a profile, + /// say -- published nothing and left the tool guessing. + @Test + public void theCompilerPluginsEncodingIsPublishedToo() throws Exception { + File root = tmp.newFolder("plugin-encoding"); + File common = new File(root, "common"); + assertTrue(new File(common, "src/main/java").mkdirs()); + File input = tmp.newFile("plugin-encoding.input"); + + OpenSettingsMojo mojo = new OpenSettingsMojo(); + mojo.project = projectAt(common); + org.apache.maven.model.Plugin compiler = new org.apache.maven.model.Plugin(); + compiler.setArtifactId("maven-compiler-plugin"); + compiler.setConfiguration(org.codehaus.plexus.util.xml.Xpp3DomBuilder.build( + new java.io.StringReader( + "Shift_JIS"))); + mojo.project.getBuild().addPlugin(compiler); + + mojo.writeBinding(input, common); + + String binding = new String(Files.readAllBytes(input.toPath()), StandardCharsets.UTF_8); + assertTrue(binding, binding.contains("sourceEncoding=Shift_JIS")); + } + + /// A project that resolves neither says neither, and the tool falls back to + /// reading the POM itself rather than being handed an empty answer. + @Test + public void bindingOmitsWhatItCannotResolve() throws Exception { + File root = tmp.newFolder("unresolved"); + File common = new File(root, "common"); + assertTrue(common.mkdirs()); + File input = tmp.newFile("unresolved.input"); + + new OpenSettingsMojo().writeBinding(input, common); + + String binding = new String(Files.readAllBytes(input.toPath()), StandardCharsets.UTF_8); + assertFalse(binding, binding.contains("sourceRoots=")); + assertFalse(binding, binding.contains("sourceEncoding=")); + } + @Test public void pluginVersionUsesCodenameOneVersionInsteadOfApplicationVersion() { OpenSettingsMojo mojo = new OpenSettingsMojo(); @@ -202,6 +270,7 @@ private File jarWithIcon(String name) throws Exception { private MavenProject projectAt(File basedir) { MavenProject project = new MavenProject(); + project.setBuild(new org.apache.maven.model.Build()); project.setFile(new File(basedir, "pom.xml")); project.addCompileSourceRoot(new File(basedir, "src/main/java").getAbsolutePath()); return project; diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/processors/BuildHintAnnotationProcessorTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/processors/BuildHintAnnotationProcessorTest.java new file mode 100644 index 00000000000..bf7e6b854f1 --- /dev/null +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/processors/BuildHintAnnotationProcessorTest.java @@ -0,0 +1,1142 @@ +/* + * Copyright (c) 2012, 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.codename1.maven.processors; + +import com.codename1.maven.annotations.AnnotatedClass; +import com.codename1.maven.annotations.ClassScanner; +import com.codename1.maven.annotations.JavaSourceCompiler; +import com.codename1.maven.annotations.ProcessorContext; + +import org.apache.maven.plugin.logging.SystemStreamLog; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.ByteArrayInputStream; +import java.net.URL; +import java.util.Arrays; +import java.util.Map; +import java.util.Properties; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/// Covers the conversion from typed annotation back to wire-format build hint. +/// +/// The cases that matter most are the silent ones: a hint written for an +/// attribute the developer never set, an enum written as its constant name +/// rather than the value the builder compares against, and a list joined with +/// the wrong delimiter. None of those fail a build -- the builder falls back to +/// a default or writes a malformed fragment -- so only a test catches them. +public class BuildHintAnnotationProcessorTest { + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + private static final String MAIN = "com.example.MyApp"; + + // ------------------------------------------------------------------ + // value conversion + // ------------------------------------------------------------------ + + @Test + public void aBooleanAttributeIsWrittenAsTrueOrFalse() throws Exception { + Properties p = hintsOf("@Ios(newStorageLocation = true)"); + assertEquals("true", p.getProperty("codename1.arg.ios.newStorageLocation")); + + p = hintsOf("@Ios(newStorageLocation = false)"); + assertEquals("false", p.getProperty("codename1.arg.ios.newStorageLocation")); + } + + @Test + public void anIntAttributeIsStringified() throws Exception { + Properties p = hintsOf("@Desktop(width = 1280, height = 720)"); + assertEquals("1280", p.getProperty("codename1.arg.desktop.width")); + assertEquals("720", p.getProperty("codename1.arg.desktop.height")); + } + + @Test + public void aStringAttributeIsWrittenVerbatim() throws Exception { + Properties p = hintsOf("@Ios(teamId = \"ABCDE12345\")"); + assertEquals("ABCDE12345", p.getProperty("codename1.arg.ios.teamId")); + } + + /// The builder compares against the catalog's value, not the constant name. + /// `IOS7` happens to lowercase to `ios7`, but `INTERNAL_ONLY` does not + /// lowercase to `internalOnly`, and a builder given an unrecognized value + /// silently uses its default -- so a name-based conversion would fail with + /// no diagnostic anywhere. + @Test + public void anEnumAttributeUsesTheCatalogValueNotTheConstantName() throws Exception { + Properties p = hintsOf("@Android(installLocation = InstallLocation.INTERNAL_ONLY)"); + assertEquals("internalOnly", p.getProperty("codename1.arg.android.installLocation")); + + p = hintsOf("@Ios(themeMode = IosThemeMode.IOS7)"); + assertEquals("ios7", p.getProperty("codename1.arg.ios.themeMode")); + + p = hintsOf("@Desktop(titleBar = DesktopTitleBar.TOOLBAR)"); + assertEquals("toolbar", p.getProperty("codename1.arg.desktop.titleBar")); + } + + @Test + public void aStringArrayIsJoinedWithTheHintsOwnSeparator() throws Exception { + // ios.pods is comma delimited, ios.add_libs is semicolon delimited -- + // the same shape in Java, two different wire formats. + Properties p = hintsOf("@Ios(pods = {\"Alamofire\", \"SwiftyJSON\"}, " + + "addLibs = {\"libz.tbd\", \"libsqlite3.tbd\"})"); + assertEquals("Alamofire,SwiftyJSON", p.getProperty("codename1.arg.ios.pods")); + assertEquals("libz.tbd;libsqlite3.tbd", p.getProperty("codename1.arg.ios.add_libs")); + } + + @Test + public void aNewlineDelimitedListSurvivesThePropertiesRoundTrip() throws Exception { + Properties p = hintsOf("@Android(proguardKeep = {\"-keep class com.a.** { *; }\", " + + "\"-keep class com.b.** { *; }\"})"); + assertEquals("-keep class com.a.** { *; }\n-keep class com.b.** { *; }", + p.getProperty("codename1.arg.android.proguardKeep")); + } + + // ------------------------------------------------------------------ + // set vs unset + // ------------------------------------------------------------------ + + /// The load-bearing one. javac omits a member left at its default from the + /// class file, which is the only thing distinguishing "not set" from "set + /// to the default". Reading attributes through a getOrDefault would write + /// a hint for every attribute of every annotation the project uses. + @Test + public void anAttributeThatWasNotWrittenProducesNoHint() throws Exception { + Properties p = hintsOf("@Ios(pods = {\"Alamofire\"})"); + assertEquals("Alamofire", p.getProperty("codename1.arg.ios.pods")); + assertNull("an unset attribute must not be written at all", + p.getProperty("codename1.arg.ios.newStorageLocation")); + assertNull(p.getProperty("codename1.arg.ios.objC")); + assertNull(p.getProperty("codename1.arg.ios.teamId")); + } + + /// The other half of the same contract: a value the developer typed is + /// written even when it equals the annotation's declared default, because + /// typing it is a statement of intent. + @Test + public void anExplicitlyWrittenDefaultValueIsStillEmitted() throws Exception { + // ios.objC is declared `default true` by the generator. + Properties p = hintsOf("@Ios(objC = true)"); + assertEquals("true", p.getProperty("codename1.arg.ios.objC")); + } + + // ------------------------------------------------------------------ + // determinism and cleanup + // ------------------------------------------------------------------ + + @Test + public void theEmittedResourceIsByteStableAcrossRuns() throws Exception { + String src = "@Ios(pods = {\"A\", \"B\"}, teamId = \"T\")\n@Desktop(width = 640)"; + byte[] first = rawResource(src); + byte[] second = rawResource(src); + assertTrue("the emitted resource must not change between identical builds", + Arrays.equals(first, second)); + } + + @Test + public void removingTheLastAnnotationRemovesTheGeneratedResource() throws Exception { + File classes = compile("@Ios(teamId = \"T\")"); + ProcessorContext ctx = run(classes, settings(), MAIN, true); + File emitted = new File(classes, + BuildHintAnnotationProcessor.MANIFEST_RESOURCE); + emitted.getParentFile().mkdirs(); + FileOutputStream out = new FileOutputStream(emitted); + out.write(ctx.getEmittedResources().get( + BuildHintAnnotationProcessor.MANIFEST_RESOURCE)); + out.close(); + assertTrue(emitted.exists()); + + // Recompile with no build hint annotation at all. + File plain = compile(""); + // Point the processor at the directory still holding yesterday's file. + copyInto(plain, emitted); + run(plain, settings(), MAIN, true); + assertFalse("a stale build-hints resource would ship hints the project no longer " + + "declares", new File(plain, + BuildHintAnnotationProcessor.MANIFEST_RESOURCE).exists()); + } + + // ------------------------------------------------------------------ + // placement + // ------------------------------------------------------------------ + + @Test + public void annotationsOnANonMainClassAreRejected() throws Exception { + File classes = compile("@Ios(teamId = \"T\")"); + ProcessorContext ctx = run(classes, settings(), "com.example.SomethingElse", false); + assertErrorContaining(ctx, "belong on the application's main class"); + } + + @Test + public void aModuleWithNoMainClassIsRejected() throws Exception { + File classes = compile("@Ios(teamId = \"T\")"); + ProcessorContext ctx = run(classes, settings(), null, false); + assertErrorContaining(ctx, "declares no codename1.mainName"); + } + + /// A project that uses none of these annotations must not start failing + /// because it has no main class -- a cn1lib, for instance. + @Test + public void aModuleWithNoAnnotationsAndNoMainClassIsFine() throws Exception { + File classes = compile(""); + ProcessorContext ctx = run(classes, settings(), null, true); + assertFalse(ctx.hasErrors()); + } + + // ------------------------------------------------------------------ + // conflicts with the properties file + // ------------------------------------------------------------------ + + @Test + public void aHintSetInBothPlacesIsAnError() throws Exception { + Properties s = settings(); + s.setProperty("codename1.arg.ios.teamId", "FROMFILE"); + File classes = compile("@Ios(teamId = \"FROMANNOTATION\")"); + ProcessorContext ctx = run(classes, s, MAIN, false); + assertErrorContaining(ctx, "codename1.arg.ios.teamId is declared twice"); + assertErrorContaining(ctx, "@Ios(teamId)"); + } + + @Test + public void aHintOnlyInThePropertiesFileIsFine() throws Exception { + Properties s = settings(); + s.setProperty("codename1.arg.ios.plistInject", "X"); + File classes = compile("@Ios(teamId = \"T\")"); + ProcessorContext ctx = run(classes, s, MAIN, true); + assertFalse(ctx.hasErrors()); + } + + /// A hint's deprecated alias names the same setting, so declaring the alias + /// in the properties file collides with the annotation just as the canonical + /// name would. Without this one value silently wins: AndroidGradleBuilder + /// reads `and.themeMode` and falls back to `cn1.androidTheme`. + @Test + public void aDeprecatedAliasOfAnAnnotatedHintIsAConflict() throws Exception { + Properties s = settings(); + s.setProperty("codename1.arg.cn1.androidTheme", "legacy"); + File classes = compile("@Android(themeMode = AndroidThemeMode.MODERN)"); + ProcessorContext ctx = run(classes, s, MAIN, false); + assertErrorContaining(ctx, "codename1.arg.cn1.androidTheme is declared twice"); + } + + /// A commented-out line is not a declaration, and the archetype ships + /// several. Properties.load skips them, so this is really a guard against + /// anyone reintroducing a hand-rolled line scan. + @Test + public void aCommentedOutPropertyIsNotAConflict() throws Exception { + Properties s = new Properties(); + s.load(new ByteArrayInputStream( + ("codename1.mainName=MyApp\ncodename1.packageName=com.example\n" + + "#codename1.arg.ios.teamId=OLD\n").getBytes("ISO-8859-1"))); + File classes = compile("@Ios(teamId = \"T\")"); + ProcessorContext ctx = run(classes, s, MAIN, true); + assertFalse(ctx.hasErrors()); + } + + /// An annotation with every member left at its default is legal Java, and + /// `@Ios()` is what is left after the last attribute is deleted. The manifest + /// is still emitted for it, carrying only the main-class stamp: its presence + /// is what tells the build that processing ran at all, and dropping it here + /// would make a harmless annotation indistinguishable from an unbound goal. + @Test + public void anAnnotationWithNoMembersStillEmitsAStampedManifest() throws Exception { + Properties p = hintsOf("@Ios()"); + assertEquals(MAIN, p.getProperty("cn1.buildHints.mainClass")); + for (String key : p.stringPropertyNames()) { + assertFalse("no hint should have been written, got " + key, + key.startsWith("codename1.arg.")); + } + } + + /// `and.captureRecord` is not an abbreviation: the builder reads + /// `android.captureRecord` and then lets the short spelling override it, so + /// the two name one setting. Without the alias the annotation and a + /// properties line spelling it the short way were both accepted -- and the + /// properties line wins in the builder, leaving the compile-checked + /// annotation silently ineffective. + @Test + public void theShortSpellingOfAnAliasedHintStillConflicts() throws Exception { + Properties s = new Properties(); + s.load(new ByteArrayInputStream( + ("codename1.mainName=MyApp\ncodename1.packageName=com.example\n" + + "codename1.arg.and.captureRecord=disabled\n").getBytes("ISO-8859-1"))); + File classes = compile("@Android(captureRecord = \"enabled\")"); + ProcessorContext ctx = run(classes, s, MAIN, false); + assertErrorContaining(ctx, "and.captureRecord"); + } + + /// A nested type's binary name is Main$Wrong and no source declares a type + /// spelled that way, so looking for it found nothing and the class was + /// dropped as an orphan -- taking the placement error with it and letting the + /// build succeed with the requested hints silently absent. + @Test + public void anAnnotationOnANestedTypeIsStillReported() throws Exception { + File classes = tmp.newFolder(); + JavaSourceCompiler.compile( + JavaSourceCompiler.singleSource(MAIN, + "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "public class MyApp {\n" + + " @Ios(teamId = \"ABCDE12345\")\n" + + " public static class Wrong {}\n" + + "}\n"), + classes, Arrays.asList(testClassesDir(), coreJar())); + ProcessorContext ctx = run(classes, settings(), MAIN, false); + assertErrorContaining(ctx, "belong on the application's main class"); + } + + /// What counts as a declaration has one answer, shared by the processor's + /// orphan check and the migration goal's source lookup. These pin it. + @Test + public void aDeclarationIsFoundOnlyInCode() { + assertTrue(BuildHintAnnotationProcessor.declaresType("public class MyApp {}", "MyApp")); + assertTrue(BuildHintAnnotationProcessor.declaresType("object MyApp", "MyApp")); + assertFalse(BuildHintAnnotationProcessor.declaresType("// class MyApp", "MyApp")); + assertFalse(BuildHintAnnotationProcessor.declaresType("/* class MyApp */", "MyApp")); + assertFalse(BuildHintAnnotationProcessor.declaresType("String s = \"class MyApp\";", + "MyApp")); + assertTrue(BuildHintAnnotationProcessor.declaresType( + "// class MyApp\nclass MyApp {}", "MyApp")); + assertFalse(BuildHintAnnotationProcessor.declaresType("class MyApplication {}", "MyApp")); + } + + @Test + public void thePackageIsReadFromCodeToo() { + assertEquals("com.example", + BuildHintAnnotationProcessor.declaredPackageIn("package com.example;\n")); + assertEquals("com.example", + BuildHintAnnotationProcessor.declaredPackageIn("package com.example\n")); + assertEquals("", BuildHintAnnotationProcessor.declaredPackageIn("// package com.example;")); + assertEquals("", BuildHintAnnotationProcessor.declaredPackageIn("class MyApp {}")); + } + + /// Blanking preserves length and line breaks, so an offset into the blanked + /// text still means the same place in the original. + @Test + public void blankingKeepsThePositionsIntact() { + String src = "a // b\nc /* d */ e\n"; + String blanked = BuildHintAnnotationProcessor.blankNonCode(src); + assertEquals(src.length(), blanked.length()); + assertEquals(2, blanked.split("\n", -1).length - 1); + } + + /// The whole nesting path, in order. Checking only the innermost name let an + /// unrelated Main.B.Wrong vouch for a deleted Main.A.Wrong; checking only the + /// outer class was the same bug one level out. + @Test + public void aNestedPathMustNestTheSameWay() { + String src = "package com.example;\n" + + "public class Main {\n" + + " static class A { }\n" + + " static class B { static class Wrong { } }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + src, new String[] {"Main", "B", "Wrong"})); + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + src, new String[] {"Main", "A", "Wrong"})); + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + src, new String[] {"Main", "Wrong"})); + } + + /// Braces inside comments and strings must not move the nesting. + @Test + public void bracesInCommentsAndStringsDoNotBreakNesting() { + String src = "class Main {\n" + + " // }\n" + + " String s = \"}\";\n" + + " static class Wrong { }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + src, new String[] {"Main", "Wrong"})); + } + + /// javac names a NAMED local class Main$1Wrong. No source declares that + /// spelling, so looking for it finds nothing -- and concluding "orphan" from + /// that dropped a live annotated class before the placement check could + /// reject it, letting the build succeed with the hints silently discarded. + /// Checking for a wholly numeric segment missed $1Wrong exactly. + @Test + public void anAnnotationOnANamedLocalClassIsStillReported() throws Exception { + String source = "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "public class MyApp {\n" + + " void go() {\n" + + " @Ios(teamId = \"ABCDE12345\")\n" + + " class Wrong {}\n" + + " new Wrong();\n" + + " }\n" + + "}\n"; + File classes = tmp.newFolder(); + JavaSourceCompiler.compile(JavaSourceCompiler.singleSource(MAIN, source), + classes, Arrays.asList(testClassesDir(), coreJar())); + // The source root has to be real, or the orphan filter is never consulted + // and this passes whatever it does. + ProcessorContext ctx = run(classes, settings(), MAIN, false, sourceRootWith(source)); + assertErrorContaining(ctx, "belong on the application's main class"); + } + + /// The rule the case above rests on, stated directly: javac's own segments + /// are unjudgeable, a developer's are not. + @Test + public void javacsOwnNestedSegmentsAreNotLookedFor() { + assertNull(BuildHintAnnotationProcessor.nestedNameOf("com.example.Main$1Wrong")); + assertNull(BuildHintAnnotationProcessor.nestedNameOf("com.example.Main$1")); + assertNull(BuildHintAnnotationProcessor.nestedNameOf("com.example.Main$A$1B")); + assertArrayEquals(new String[] {"Main", "Wrong"}, + BuildHintAnnotationProcessor.nestedNameOf("com.example.Main$Wrong")); + assertNull(BuildHintAnnotationProcessor.nestedNameOf("com.example.Main")); + } + + /// A source root holding MyApp.java with the given text. + private File sourceRootWith(String source) throws Exception { + File root = tmp.newFolder(); + File dir = new File(root, "com" + File.separator + "example"); + assertTrue(dir.mkdirs()); + try (java.io.Writer w = new java.io.OutputStreamWriter( + new FileOutputStream(new File(dir, "MyApp.java")), "UTF-8")) { + w.write(source); + } + return root; + } + + /// A declaration may put any legal whitespace, or a comment, between the + /// keyword and the name. Requiring exactly one space read `class\nWrong` as + /// no declaration at all -- so a live type looked stale to the orphan check, + /// and the migration goal reported it could not find the main source. + @Test + public void anyLegalSeparatorBeforeATypeNameIsAccepted() { + assertTrue(BuildHintAnnotationProcessor.declaresType("class\nWrong {}", "Wrong")); + assertTrue(BuildHintAnnotationProcessor.declaresType("class\tWrong {}", "Wrong")); + assertTrue(BuildHintAnnotationProcessor.declaresType("class /* why */ Wrong {}", "Wrong")); + assertTrue(BuildHintAnnotationProcessor.declaresType( + "public\nfinal\nclass\n Wrong\n{}", "Wrong")); + assertFalse(BuildHintAnnotationProcessor.declaresType("class Wronger {}", "Wrong")); + } + + /// A brace inside a char literal is not syntax. Counting it loses the + /// nesting, so a live nested class reads as an orphan and its misplaced + /// annotation is skipped instead of reported. + @Test + public void aBraceInACharLiteralDoesNotMoveTheNesting() { + // Deliberately UNBALANCED. My first version of this test had both '{' + // and '}', which cancel out, so it passed with the char branch removed + // and proved nothing. + String src = "class Main {\n" + + " char open = '{';\n" + + " static class Wrong { }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + src, new String[] {"Main", "Wrong"})); + + // An escaped quote must not end the literal early, or the brace after it + // is counted again. + String escaped = "class Main {\n" + + " char quote = '\\'';\n" + + " char open = '{';\n" + + " static class Wrong { }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + escaped, new String[] {"Main", "Wrong"})); + } + + /// A declaration below any fixed prefix must still be found: a line bound + /// meant a type after a long header read as absent, so a live class looked + /// stale and its placement error was never reported. + @Test + public void aDeclarationFarDownTheFileIsStillFound() { + StringBuilder src = new StringBuilder("package com.example;\n"); + for (int i = 0; i < 900; i++) { + src.append("import java.util.List").append(i).append(";\n"); + } + src.append("public class MyApp {}\n"); + assertTrue(BuildHintAnnotationProcessor.declaresType(src.toString(), "MyApp")); + assertEquals("com.example", + BuildHintAnnotationProcessor.declaredPackageIn(src.toString())); + } + + /// `package\ncom.example;` is valid Java. A line-oriented parse saw an empty + /// remainder and reported the default package, so a live class looked like it + /// belonged elsewhere, read as an orphan, and its misplaced annotation went + /// unreported. + @Test + public void aPackageDeclarationMaySpanLines() { + assertEquals("com.example", + BuildHintAnnotationProcessor.declaredPackageIn("package\ncom.example;\n")); + assertEquals("com.example", + BuildHintAnnotationProcessor.declaredPackageIn("package com.example ;\n")); + assertEquals("com.example", + BuildHintAnnotationProcessor.declaredPackageIn("package /* x */ com.example\n")); + assertEquals("", BuildHintAnnotationProcessor.declaredPackageIn("// package com.example;")); + } + + /// A value is a place a developer writes arbitrary text, so it must not be + /// able to forge the structure around it. With plain delimiters these two + /// annotations fingerprinted identically, and a stale manifest was then + /// accepted for a genuinely different configuration. + @Test + public void aValueCannotForgeTheDigestStructure() throws Exception { + String forged = digestOf( + "@Ios(bundleVersion = \"1;teamId=java.lang.String:X\")"); + String real = digestOf("@Ios(bundleVersion = \"1\", teamId = \"X\")"); + assertFalse("a value must not be able to imitate another member", + forged.equals(real)); + } + + /// Neighbouring values must not run together either: {"a","bc"} is not + /// {"ab","c"}, and a list of one is not the value itself. + @Test + public void adjacentValuesDoNotRunTogether() throws Exception { + assertFalse(digestOf("@Ios(pods = {\"a\", \"bc\"})") + .equals(digestOf("@Ios(pods = {\"ab\", \"c\"})"))); + assertFalse(digestOf("@Ios(pods = {\"a\"})") + .equals(digestOf("@Ios(teamId = \"a\")"))); + } + + /// ...while the same annotations still fingerprint the same, or the check + /// would refuse every build instead of only the wrong ones. + @Test + public void theSameAnnotationsFingerprintTheSame() throws Exception { + assertEquals(digestOf("@Ios(teamId = \"X\", bundleVersion = \"1\")"), + digestOf("@Ios(bundleVersion = \"1\", teamId = \"X\")")); + } + + /// The digest of a main class annotated so. + private String digestOf(String annotations) throws Exception { + File dir = tmp.newFolder(); + JavaSourceCompiler.compile(JavaSourceCompiler.singleSource(MAIN, source(annotations)), + dir, Arrays.asList(testClassesDir(), coreJar())); + Map index = ClassScanner.scan(dir); + return BuildHintAnnotationProcessor.sourceDigest(index.values().iterator().next()); + } + + /// An element may legally be empty -- a newline-delimited value that starts + /// with a newline is {"", "..."} -- and joining on "what has been written so + /// far" skipped the separator after it, silently dropping the leading + /// newline from the hint the builder receives. + @Test + public void anEmptyListElementStillGetsItsSeparator() throws Exception { + Properties p = hintsOf("@Android(xgradle = {\"\", \"apply plugin: 'x'\"})"); + assertEquals("\napply plugin: 'x'", p.getProperty("codename1.arg.android.xgradle")); + } + + /// Kotlin builds a local class's binary name out of the enclosing FUNCTION + /// names -- Main$start$Wrong -- with nothing marking `start` as synthetic. + /// Requiring it to be a declared type dropped the live annotated class + /// silently. Past the outermost type a Kotlin segment is inconclusive. + @Test + public void aKotlinLocalClassPathIsInconclusiveNotAnOrphan() { + String kt = "package com.example\n" + + "class Main {\n" + + " fun start() {\n" + + " class Wrong\n" + + " }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + kt, new String[] {"Main", "start", "Wrong"}, true)); + // The outermost type is still required: it is what the file declares. + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + kt, new String[] {"Other", "start", "Wrong"}, true)); + // ...and so is the LAST segment, which is the class itself. Leniency + // there would keep a deleted nested type's orphan and fail every + // incremental build. + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + kt, new String[] {"Main", "start", "Gone"}, true)); + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + "package com.example\nclass Main { }\n", new String[] {"Main", "Wrong"}, true)); + // A function that does not exist is not an excuse either. + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + kt, new String[] {"Main", "start", "Wrong", "Deeper"}, true)); + // Java keeps the strict reading, since javac marks its locals with $1. + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + "class Main { void start() { } }", new String[] {"Main", "start", "Wrong"}, + false)); + } + + /// The simulator has no bytecode reader, so it cannot recompute the source + /// digest and was left comparing file timestamps -- which a jar records to + /// two seconds and a reproducible build stamps identically, making the + /// comparison inert rather than coarse. Hashing the class file needs no + /// bytecode reader, so the manifest records that instead. + @Test + public void theManifestRecordsTheCompiledClassesOwnDigest() throws Exception { + File classes = compile("@Ios(teamId = \"ABCDE12345\")"); + ProcessorContext ctx = run(classes, settings(), MAIN, true); + Properties p = new Properties(); + p.load(new ByteArrayInputStream(ctx.getEmittedResources() + .get(BuildHintAnnotationProcessor.MANIFEST_RESOURCE))); + + String recorded = p.getProperty(BuildHintAnnotationProcessor.CLASS_DIGEST_KEY); + assertTrue("no class digest was recorded", recorded != null); + assertEquals(sha256Of(new File(classes, "com/example/MyApp.class")), recorded); + } + + private static String sha256Of(File f) throws Exception { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); + java.io.InputStream in = new java.io.FileInputStream(f); + try { + byte[] buf = new byte[8192]; + for (int n = in.read(buf); n > 0; n = in.read(buf)) { + md.update(buf, 0, n); + } + } finally { + in.close(); + } + StringBuilder hex = new StringBuilder(); + for (byte b : md.digest()) { + hex.append(Character.forDigit((b >> 4) & 0xF, 16)); + hex.append(Character.forDigit(b & 0xF, 16)); + } + return hex.toString(); + } + + /// A processor may REPLACE the main class through `emitClass`, and those are + /// flushed only after every processor's `finish()` -- so a manifest written + /// during ours records the class as the compiler left it, not as the build + /// ships it. The simulator would then read a freshly generated manifest as + /// stale and drop every annotated hint under `cn1:run`. + @Test + public void theStampIsCorrectedOnceTheClassesAreFlushed() throws Exception { + File classes = compile("@Ios(teamId = \"ABCDE12345\")"); + ProcessorContext ctx = run(classes, settings(), MAIN, true); + File manifest = new File(classes, BuildHintAnnotationProcessor.MANIFEST_RESOURCE); + manifest.getParentFile().mkdirs(); + java.nio.file.Files.write(manifest.toPath(), + ctx.getEmittedResources() + .get(BuildHintAnnotationProcessor.MANIFEST_RESOURCE)); + + // Stand in for the instrumented replacement a later processor writes. + File classFile = new File(classes, "com/example/MyApp.class"); + byte[] original = java.nio.file.Files.readAllBytes(classFile.toPath()); + byte[] replaced = new byte[original.length + 1]; + System.arraycopy(original, 0, replaced, 0, original.length); + java.nio.file.Files.write(classFile.toPath(), replaced); + + BuildHintAnnotationProcessor.restampClassDigest(classes); + + Properties after = new Properties(); + java.io.InputStream in = new java.io.FileInputStream(manifest); + try { + after.load(in); + } finally { + in.close(); + } + assertEquals(sha256Of(classFile), + after.getProperty(BuildHintAnnotationProcessor.CLASS_DIGEST_KEY)); + // Everything else is left exactly as it was. + assertEquals("ABCDE12345", after.getProperty("codename1.arg.ios.teamId")); + assertEquals(MAIN, after.getProperty("cn1.buildHints.mainClass")); + } + + /// Nothing to correct is not an error: a project with no build hint + /// annotations emits no manifest at all. + @Test + public void theStampStepIsSilentWithoutAManifest() throws Exception { + BuildHintAnnotationProcessor.restampClassDigest(tmp.newFolder()); + } + + /// The scan for the package keyword steps over an escaped identifier too. + /// `fun `package helper`() {}` in a default-package file reported `helper` + /// as the declared package, so a live annotated class in it looked like it + /// belonged elsewhere and was dropped as an orphan. + @Test + public void anEscapedIdentifierIsNotAPackageDeclaration() { + assertEquals("", BuildHintAnnotationProcessor.declaredPackageIn( + "fun `package helper`() {}\n\nclass MyApp\n", true)); + // The real one is still found when there is one. + assertEquals("com.example", BuildHintAnnotationProcessor.declaredPackageIn( + "package com.example\n\nfun `package helper`() {}\n", true)); + } + + /// Inside a Kotlin template expression the first quote starts a NEW literal + /// rather than closing the outer one, so a `class` written inside one was + /// exposed as live code and read as a declaration nobody wrote. + @Test + public void aStringInsideAKotlinTemplateIsStillAString() { + String kt = "package com.example\n" + + "class Real {\n" + + " val note = \"${\"class Fake\"}\"\n" + + "}\n"; + assertFalse(BuildHintAnnotationProcessor.declaresType(kt, "Fake", true)); + assertTrue(BuildHintAnnotationProcessor.declaresType(kt, "Real", true)); + + // A brace inside the nested literal must not close the expression early, + // or the nesting scan loses its place from there on. + String braced = "package com.example\n" + + "class Real {\n" + + " val note = \"${\"} class Fake\"}\"\n" + + "}\n"; + assertFalse(BuildHintAnnotationProcessor.declaresType(braced, "Fake", true)); + + // The expression is ordinary code, so it holds ordinary comments and + // char literals, and a quote inside one of those is not a nested string. + String commented = "package com.example\n" + + "class Real {\n" + + " val note = \"${ /* \\\" */ 1 }\"\n" + + "}\n" + + "class After\n"; + assertTrue(BuildHintAnnotationProcessor.declaresType(commented, "After", true)); + + String charLiteral = "package com.example\n" + + "class Real {\n" + + " val note = \"${ if (c == '\\\"') 1 else 2 }\"\n" + + "}\n" + + "class After\n"; + assertTrue(BuildHintAnnotationProcessor.declaresType(charLiteral, "After", true)); + + // A brace inside a comment there must not close the expression either. + String bracedComment = "package com.example\n" + + "class Real {\n" + + " val note = \"${ /* } */ 1 }\"\n" + + "}\n" + + "class After\n"; + assertTrue(BuildHintAnnotationProcessor.declaresType(bracedComment, "After", true)); + + // An escaped identifier inside the expression is a NAME: a quote in it + // does not open a string and a brace does not close the expression. + String escapedName = "package com.example\n" + + "class Real {\n" + + " val note = \"${ `\\\"` }\"\n" + + "}\n" + + "class After\n"; + assertTrue(BuildHintAnnotationProcessor.declaresType(escapedName, "After", true)); + + String bracedName = "package com.example\n" + + "class Real {\n" + + " val note = \"${ `}` }\"\n" + + "}\n" + + "class After\n"; + assertTrue(BuildHintAnnotationProcessor.declaresType(bracedName, "After", true)); + + // A raw string carries templates too. + String raw = "package com.example\n" + + "class Real {\n" + + " val note = \"\"\"${\"class Fake\"}\"\"\"\n" + + "}\n"; + assertFalse(BuildHintAnnotationProcessor.declaresType(raw, "Fake", true)); + } + + /// The compiler's source encoding is a project setting this scan cannot + /// see, and decoding an ISO-8859-1 source as UTF-8 produced replacement + /// characters -- so a name with a non-ASCII character never matched, the + /// class read as an orphan, and its misplaced annotation went unreported. + @Test + public void aSourceEncodingThatIsNotUtf8StillMatches() throws Exception { + String pkg = "com.caf\u00e9"; + for (String charset : new String[] {"UTF-8", "ISO-8859-1"}) { + File src = tmp.newFolder(); + File dir = new File(src, "com/cafe"); + dir.mkdirs(); + java.io.OutputStream os = + new java.io.FileOutputStream(new File(dir, "Accented.java")); + try { + os.write(("package " + pkg + ";\npublic class Accented {\n}\n") + .getBytes(charset)); + } finally { + os.close(); + } + + File classes = tmp.newFolder(); + JavaSourceCompiler.compile( + JavaSourceCompiler.singleSource(pkg + ".Accented", + "package " + pkg + ";\npublic class Accented {\n}\n"), + classes, Arrays.asList(testClassesDir(), coreJar())); + AnnotatedClass cls = ClassScanner.scan(classes) + .get(pkg.replace('.', '/') + "/Accented"); + assertTrue("the class under test must have been compiled", cls != null); + + assertTrue("not matched when the source is " + charset, + BuildHintAnnotationProcessor.hasBackingSource(cls, + java.util.Collections.singletonList(src.getAbsolutePath()))); + + // Read correctly, not merely judged unreadable: the name comes back + // as it was written, whichever of the two encodings the file is in. + assertTrue("misread when the source is " + charset, + BuildHintAnnotationProcessor.readHead(new File(dir, "Accented.java")) + .contains(pkg)); + } + } + + /// Running out of search budget is "cannot tell", not "no such source". + /// Answering no dropped a live annotated class silently, with its placement + /// error lost, for the sake of a bound -- which is the wrong way round: + /// everywhere else in this walk an unanswerable question keeps the class. + @Test + public void aDeepSourceTreeIsNotProofOfAnOrphan() throws Exception { + File classes = tmp.newFolder(); + JavaSourceCompiler.compile( + JavaSourceCompiler.singleSource("com.example.Deep", + "package com.example;\npublic class Deep {\n}\n"), + classes, Arrays.asList(testClassesDir(), coreJar())); + AnnotatedClass cls = ClassScanner.scan(classes).get("com/example/Deep"); + assertTrue("the class under test must have been compiled", cls != null); + + // Deeper than the old cutoff, and the file is genuinely there. + assertTrue(BuildHintAnnotationProcessor.hasBackingSource(cls, + java.util.Collections.singletonList(nest(30).getAbsolutePath()))); + + // Deeper than the budget: unanswerable, so the class is kept. + assertTrue(BuildHintAnnotationProcessor.hasBackingSource(cls, + java.util.Collections.singletonList(nest(70).getAbsolutePath()))); + } + + /// A source root with Deep.java `levels` directories down. + private File nest(int levels) throws Exception { + File root = tmp.newFolder(); + File at = root; + for (int i = 0; i < levels; i++) { + at = new File(at, "d" + i); + } + at.mkdirs(); + java.io.Writer w = new java.io.OutputStreamWriter( + new java.io.FileOutputStream(new File(at, "Deep.java")), "UTF-8"); + try { + w.write("package com.example;\npublic class Deep {\n}\n"); + } finally { + w.close(); + } + return root; + } + + /// javac processes `\\uXXXX` before it tokenizes anything, so + /// `package com.ex\\u0061mple;` really declares com.example -- and it + /// rejects an ill-formed one in a comment too, which is why the sequences + /// here are written with two backslashes. Reading the + /// text literally stopped the component at the backslash and recorded + /// `com.ex`, so a live annotated class looked like it belonged elsewhere and + /// was dropped as an orphan with its placement error unreported. + @Test + public void javaUnicodeEscapesAreTranslatedBeforeTheSourceIsRead() throws Exception { + // Through the orphan filter, which is where it decides anything: the + // source spells its package with an escape, the compiled class does not. + File src = tmp.newFolder(); + File pkgDir = new File(src, "com/example"); + pkgDir.mkdirs(); + java.io.Writer w = new java.io.OutputStreamWriter( + new java.io.FileOutputStream(new File(pkgDir, "Escaped.java")), "UTF-8"); + try { + w.write("package com.ex" + "\\u0061" + "mple;\npublic class Escaped {\n}\n"); + } finally { + w.close(); + } + File classes = tmp.newFolder(); + JavaSourceCompiler.compile( + JavaSourceCompiler.singleSource("com.example.Escaped", + "package com.example;\npublic class Escaped {\n}\n"), + classes, Arrays.asList(testClassesDir(), coreJar())); + AnnotatedClass cls = ClassScanner.scan(classes).get("com/example/Escaped"); + assertTrue("the class under test must have been compiled", cls != null); + assertTrue(BuildHintAnnotationProcessor.hasBackingSource(cls, + java.util.Collections.singletonList(src.getAbsolutePath()))); + + // A doubled backslash is not an escape, which is what keeps a string + // literal spelling one. + assertEquals("String s = \"\\\\u0041\";", + BuildHintAnnotationProcessor.decodeUnicodeEscapes( + "String s = \"\\\\u0041\";")); + + // Any number of u's is one escape, and a malformed one is left alone. + assertEquals("A", BuildHintAnnotationProcessor.decodeUnicodeEscapes("\\uuu0041")); + assertEquals("\\uZZZZ", BuildHintAnnotationProcessor.decodeUnicodeEscapes("\\uZZZZ")); + assertEquals("\\n", BuildHintAnnotationProcessor.decodeUnicodeEscapes("\\n")); + } + + /// `$` is a legal character in a Java type name, so a top-level + /// `class Wrong$Type` has binary name Wrong$Type and is not nested at all. + /// Reading every `$` as nesting looked for a `Wrong` that does not exist, + /// dropped the live class as an orphan, and lost the placement error it + /// should have raised. + @Test + public void aDollarInATopLevelJavaNameIsNotNesting() throws Exception { + File src = tmp.newFolder(); + File pkgDir = new File(src, "com/example"); + pkgDir.mkdirs(); + java.io.Writer w = new java.io.OutputStreamWriter( + new java.io.FileOutputStream(new File(pkgDir, "Wrong$Type.java")), "UTF-8"); + try { + w.write("package com.example;\npublic class Wrong$Type {\n}\n"); + } finally { + w.close(); + } + + File classes = tmp.newFolder(); + JavaSourceCompiler.compile( + JavaSourceCompiler.singleSource("com.example.Wrong$Type", + "package com.example;\npublic class Wrong$Type {\n}\n"), + classes, Arrays.asList(testClassesDir(), coreJar())); + AnnotatedClass cls = ClassScanner.scan(classes).get("com/example/Wrong$Type"); + assertTrue("the class under test must have been compiled", cls != null); + + assertTrue(BuildHintAnnotationProcessor.hasBackingSource(cls, + java.util.Collections.singletonList(src.getAbsolutePath()))); + } + + /// An escaped identifier may contain anything, spaces and keywords + /// included, and it is left as the code it is -- so a declaration scanner + /// has to step over it rather than read what is inside. `val `class Main`` + /// declares a property, and reading it as a declaration of Main made a class + /// that belongs elsewhere look like it belonged here. + @Test + public void anEscapedIdentifierIsNotADeclaration() { + String kt = "package com.example\nval `class Main` = 1\nclass Other\n"; + assertFalse(BuildHintAnnotationProcessor.declaresType(kt, "Main", true)); + assertTrue(BuildHintAnnotationProcessor.declaresType(kt, "Other", true)); + } + + /// A qualified name may escape a COMPONENT: `package com.`when`` is legal + /// Kotlin and the compiled class belongs to `com.when`. Stopping at the + /// backtick recorded `com.`, so a live annotated class looked like it + /// belonged to another package, was dropped as an orphan, and its misplaced + /// hints went unreported on a green build. + @Test + public void aQualifiedNameMayEscapeAComponent() { + assertEquals("com.when", BuildHintAnnotationProcessor.declaredPackageIn( + "package com.`when`\nclass Foo\n", true)); + assertEquals("com.when.x", BuildHintAnnotationProcessor.declaredPackageIn( + "package com.`when`.x\nclass Foo\n", true)); + // The first component too, and an ordinary name is unchanged. + assertEquals("in.example", BuildHintAnnotationProcessor.declaredPackageIn( + "package `in`.example\nclass Foo\n", true)); + assertEquals("com.example", BuildHintAnnotationProcessor.declaredPackageIn( + "package com.example\nclass Foo\n", true)); + } + + /// Kotlin lets a declaration escape its name in backticks, and the binary + /// name is plainly the text between them. Reading it with the identifier + /// rule recorded an empty name, so a LIVE annotated type looked undeclared, + /// was dropped as an orphan before placement validation, and its misplaced + /// hints went unreported on a green build. + @Test + public void aKotlinEscapedNameIsTheTextBetweenTheBackticks() { + assertTrue(BuildHintAnnotationProcessor.declaresType( + "package com.example\nclass `when` {\n}\n", "when", true)); + + // A quote is a legal character in an escaped name, and the name is not a + // literal -- treating it as one blanked the rest of the file. + String quoted = "package com.example\nclass `say\"hi` { }\nclass Real { }\n"; + assertTrue(BuildHintAnnotationProcessor.declaresType(quoted, "Real", true)); + assertTrue(BuildHintAnnotationProcessor.declaresType(quoted, "say\"hi", true)); + + // Functions are escaped at least as often, and a local class takes the + // enclosing function's name as a segment of its own binary name. + String fn = "package com.example\n" + + "class Main {\n" + + " fun `does the thing`() {\n" + + " class Wrong\n" + + " }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + fn, new String[] {"Main", "does the thing", "Wrong"}, true)); + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + fn, new String[] {"Main", "does the thing", "Gone"}, true)); + } + + /// Kotlin's UNNAMED companion object is `Companion` in the binary name and + /// is spelled `companion object` in the source, so nothing there is called + /// Companion. Treating that as inconclusive accepted the whole path without + /// ever checking the class at the end of it, so a deleted + /// `Main$Companion$Wrong` kept its orphan and failed every incremental + /// build until the output directory was cleaned. + @Test + public void anUnnamedCompanionObjectIsAScopeNotAWildcard() { + String kt = "package com.example\n" + + "class Main {\n" + + " companion object {\n" + + " class Wrong\n" + + " }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + kt, new String[] {"Main", "Companion", "Wrong"}, true)); + // The class at the end of the path is still checked. + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + kt, new String[] {"Main", "Companion", "Gone"}, true)); + // No companion at all keeps the surrounding leniency: an intermediate + // segment nothing accounts for is inconclusive, because concluding + // orphan there drops a live annotated class silently while keeping a + // stale one only costs a visible placement error. + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + "package com.example\nclass Main {\n class Wrong\n}\n", + new String[] {"Main", "Companion", "Wrong"}, true)); + + // A NAMED companion carries its own name into the binary name, so the + // ordinary declaration lookup is what applies to it. + String named = "package com.example\n" + + "class Main {\n" + + " companion object Named {\n" + + " class Wrong\n" + + " }\n" + + "}\n"; + assertTrue(BuildHintAnnotationProcessor.declaresNestedPath( + named, new String[] {"Main", "Named", "Wrong"}, true)); + assertFalse(BuildHintAnnotationProcessor.declaresNestedPath( + named, new String[] {"Main", "Named", "Gone"}, true)); + } + + /// A Kotlin file annotation holding a raw string that ends in a quote closes + /// on a run of four. Reading it by Java's rules blanked the package + /// declaration that followed. + @Test + public void aKotlinRawStringBeforeThePackageDoesNotEatIt() { + String kt = "@file:Suppress(\"\"\"a\"\"\"\")\npackage com.example\nclass MyApp\n"; + assertEquals("com.example", BuildHintAnnotationProcessor.declaredPackageIn(kt, true)); + } + + /// `package com /* generated */ . example;` is legal. Reading the name as one + /// contiguous run recorded `com`, so a live class looked like it belonged + /// elsewhere, read as an orphan, and its misplaced annotation went + /// unreported. + @Test + public void aPackageNameMaySpanSeparators() { + assertEquals("com.example", BuildHintAnnotationProcessor.declaredPackageIn( + "package com /* generated */ . example;\n", false)); + assertEquals("com.example", BuildHintAnnotationProcessor.declaredPackageIn( + "package com\n . example\n", true)); + assertEquals("com.example.deep", BuildHintAnnotationProcessor.declaredPackageIn( + "package com . example . deep ;\n", false)); + } + + /// Kotlin block comments NEST; Java's do not. Stopping at the first `*/` in + /// Kotlin ended the comment early, so a commented-out package declaration was + /// read as live code and a class looked like it belonged elsewhere. + @Test + public void aNestedKotlinBlockCommentStaysClosed() { + String kt = "/* docs /* sample */ package old.name */\n" + + "package com.example\nclass MyApp\n"; + assertEquals("com.example", BuildHintAnnotationProcessor.declaredPackageIn(kt, true)); + // Java does not nest, so there the inner `*/` really does close it and + // `package old.name` is what follows. + assertEquals("old.name", BuildHintAnnotationProcessor.declaredPackageIn(kt, false)); + } + + // ------------------------------------------------------------------ + // helpers + // ------------------------------------------------------------------ + + private static String source(String annotations) { + return "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + annotations + "\n" + + "public class MyApp {\n}\n"; + } + + private File compile(String annotations) throws Exception { + File classes = tmp.newFolder(); + JavaSourceCompiler.compile( + JavaSourceCompiler.singleSource(MAIN, source(annotations)), + classes, Arrays.asList(testClassesDir(), coreJar())); + return classes; + } + + private ProcessorContext run(File classes, Properties settings, String mainClass, + boolean expectClean) throws Exception { + return run(classes, settings, mainClass, expectClean, null); + } + + /// With `sourceRoot` the orphan filter runs for real. Without it the context + /// reports no compile source roots, which the filter reads as "not told" and + /// keeps every class -- so a test that means to exercise the filter has to + /// supply one, or it passes whatever the filter does. + private ProcessorContext run(File classes, Properties settings, String mainClass, + boolean expectClean, File sourceRoot) throws Exception { + Map index = ClassScanner.scan(classes); + BuildHintAnnotationProcessor proc = new BuildHintAnnotationProcessor(); + ProcessorContext ctx = new ProcessorContext(classes, tmp.newFolder(), index, + new SystemStreamLog(), tmp.newFolder(), settings, mainClass, + sourceRoot == null ? null + : java.util.Collections.singletonList(sourceRoot.getAbsolutePath())); + proc.start(ctx); + for (AnnotatedClass cls : index.values()) { + proc.processClass(cls, ctx); + } + proc.finish(ctx); + if (expectClean && ctx.hasErrors()) { + StringBuilder sb = new StringBuilder("unexpected errors:\n"); + for (ProcessorContext.ProcessingError e : ctx.getErrors()) { + sb.append(" ").append(e).append('\n'); + } + fail(sb.toString()); + } + return ctx; + } + + private byte[] rawResource(String annotations) throws Exception { + ProcessorContext ctx = run(compile(annotations), settings(), MAIN, true); + byte[] bytes = ctx.getEmittedResources() + .get(BuildHintAnnotationProcessor.MANIFEST_RESOURCE); + assertTrue("build-hints.properties must be emitted", bytes != null); + return bytes; + } + + private Properties hintsOf(String annotations) throws Exception { + Properties p = new Properties(); + p.load(new ByteArrayInputStream(rawResource(annotations))); + return p; + } + + private static Properties settings() { + Properties p = new Properties(); + p.setProperty("codename1.mainName", "MyApp"); + p.setProperty("codename1.packageName", "com.example"); + return p; + } + + private static void assertErrorContaining(ProcessorContext ctx, String fragment) { + assertTrue("expected a validation error", ctx.hasErrors()); + StringBuilder all = new StringBuilder(); + for (ProcessorContext.ProcessingError e : ctx.getErrors()) { + all.append(e).append('\n'); + } + assertTrue("expected an error containing \"" + fragment + "\" but got:\n" + all, + all.toString().contains(fragment)); + } + + private static void copyInto(File classesDir, File existing) throws Exception { + File target = new File(classesDir, BuildHintAnnotationProcessor.MANIFEST_RESOURCE); + target.getParentFile().mkdirs(); + java.nio.file.Files.copy(existing.toPath(), target.toPath(), + java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + + private static File testClassesDir() throws Exception { + URL url = BuildHintAnnotationProcessorTest.class.getProtectionDomain() + .getCodeSource().getLocation(); + return new File(url.toURI()); + } + + /// The generated annotations live in codenameone-core, which is already a + /// dependency of the plugin, so the compiled sources can reference them. + private static File coreJar() throws Exception { + URL url = Class.forName("com.codename1.annotations.buildhints.Ios") + .getProtectionDomain().getCodeSource().getLocation(); + return new File(url.toURI()); + } +} diff --git a/maven/core-unittests/src/test/java/com/codename1/db/ThreadSafeDatabaseTest.java b/maven/core-unittests/src/test/java/com/codename1/db/ThreadSafeDatabaseTest.java index 162675b7636..ae786cb60b5 100644 --- a/maven/core-unittests/src/test/java/com/codename1/db/ThreadSafeDatabaseTest.java +++ b/maven/core-unittests/src/test/java/com/codename1/db/ThreadSafeDatabaseTest.java @@ -30,6 +30,19 @@ public class ThreadSafeDatabaseTest extends UITestBase { + /** + * How long a test waits for a worker thread to stop. + * + *

Deliberately below the 5000ms {@code @FormTest} timeout in + * {@link com.codename1.junit.EDTTestInterceptor}. These waits used to use + * 5000ms as well, so a slow runner spent the whole harness budget inside the + * poll loop and the interceptor fired first: the report was + * "FormTest timed out after 5000ms" with nothing about which condition never + * became true. With headroom the test fails on its own assertion instead, + * which names the thing that went wrong.

+ */ + private static final long WORKER_STOP_TIMEOUT_MILLIS = 2000; + @FormTest public void testDelegation() throws Exception { Database db = TestCodenameOneImplementation.getInstance().openOrCreateDB("test_threadsafe.db"); @@ -91,7 +104,7 @@ public void run() { } } }); - long deadline = System.currentTimeMillis() + 5000; + long deadline = System.currentTimeMillis() + WORKER_STOP_TIMEOUT_MILLIS; while (!tsDb.getThread().isFinished() && System.currentTimeMillis() < deadline) { Thread.sleep(10); } @@ -118,7 +131,7 @@ public void killedThreadReportsItselfFinished() throws Exception { com.codename1.util.EasyThread et = com.codename1.util.EasyThread.start("test-kill-flag"); Assertions.assertFalse(et.isFinished(), "a running thread is not finished"); et.kill(); - long deadline = System.currentTimeMillis() + 5000; + long deadline = System.currentTimeMillis() + WORKER_STOP_TIMEOUT_MILLIS; while (!et.isFinished() && System.currentTimeMillis() < deadline) { Thread.sleep(10); } @@ -150,7 +163,7 @@ public void closingAfterTheWorkerHasGoneStaysQuiet() throws Exception { .openOrCreateDB("test_threadsafe_close_after_worker.db"); ThreadSafeDatabase tsDb = new ThreadSafeDatabase(db); tsDb.getThread().killWhenIdle(); - long deadline = System.currentTimeMillis() + 5000; + long deadline = System.currentTimeMillis() + WORKER_STOP_TIMEOUT_MILLIS; while (!tsDb.getThread().isFinished() && System.currentTimeMillis() < deadline) { Thread.sleep(10); } @@ -202,7 +215,7 @@ public void run() { }); synchronized (started) { while (!started[0]) { - started.wait(5000); + started.wait(WORKER_STOP_TIMEOUT_MILLIS); } } diff --git a/maven/integration-tests/all.sh b/maven/integration-tests/all.sh index e3854a3d131..04fe56dc8d0 100644 --- a/maven/integration-tests/all.sh +++ b/maven/integration-tests/all.sh @@ -9,6 +9,7 @@ bash cssfonts.sh bash native-interfaces.sh bash initializr-roundtrip-test.sh bash cn1app-archetype-test.sh +bash build-hint-annotations-test.sh bash cn1app-desktop-build-test.sh bash bare-bones-kotlin-test.sh bash migrate-kitchensink-test.sh diff --git a/maven/integration-tests/build-hint-annotations-test.sh b/maven/integration-tests/build-hint-annotations-test.sh new file mode 100755 index 00000000000..3160a49ad41 --- /dev/null +++ b/maven/integration-tests/build-hint-annotations-test.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# +# Build hints written as annotations must reach the build request, and the same +# hint set twice must fail. +# +# A build hint used to be an unchecked string: misspell it and the build stayed +# green while the setting silently did nothing. The annotations exist so the +# compiler catches that, and this test covers the part the compiler cannot -- +# that the annotation is actually converted back into the codename1.arg.* pair +# the builders read, and that it is not silently merged with a properties line +# saying something different. +SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" +set -e +source $SCRIPTPATH/inc/env.sh + +cd $SCRIPTPATH/build +rm -rf myapphints +mvn archetype:generate \ + -DarchetypeArtifactId=cn1app-archetype \ + -DarchetypeGroupId=com.codenameone \ + -DarchetypeVersion=$CN1_VERSION \ + -DartifactId=myapphints \ + -DgroupId=com.example \ + -Dversion=1.0-SNAPSHOT \ + -DmainName=MyApp \ + -DinteractiveMode=false + +cd myapphints +chmod 755 mvnw + +MAIN=common/src/main/java/com/example/MyApp.java +SETTINGS=common/codenameone_settings.properties + +# The archetype deliberately still ships its hints as properties: generated +# projects are pinned to a released Codename One whose core has no +# com.codename1.annotations.buildhints, so a template carrying them would not +# compile. The annotations move there in a follow-up. Add them here instead, and +# only for hints the template does NOT declare -- setting one in both places is +# a build error, which is covered separately at the end of this test. +echo "--- annotate the generated main class ---" +perl -0pi -e 's/^import com\.codename1\.system\.Lifecycle;/import com.codename1.annotations.buildhints.*;\nimport com.codename1.system.Lifecycle;/m' $MAIN +perl -0pi -e 's/^public class MyApp extends Lifecycle \{/\@Ios(pods = {"Alamofire", "SwiftyJSON"}, teamId = "ABCDE12345")\n\@Android(installLocation = InstallLocation.INTERNAL_ONLY)\n\@Desktop(width = 1280)\npublic class MyApp extends Lifecycle {/m' $MAIN +grep -q "com.codename1.annotations.buildhints" $MAIN \ + || { echo "FAIL: could not add the import to $MAIN"; exit 1; } +grep -q 'pods = {"Alamofire"' $MAIN || { echo "FAIL: could not annotate $MAIN"; head -40 $MAIN; exit 1; } + +echo "--- process-classes must emit the hints ---" +./mvnw -B -q -pl common process-classes +EMITTED=common/target/classes/META-INF/codenameone/build-hints.properties +test -f $EMITTED || { echo "FAIL: $EMITTED was not emitted"; exit 1; } + +check() { + grep -qF "$1" $EMITTED || { echo "FAIL: expected '$1' in $EMITTED"; cat $EMITTED; exit 1; } +} +# a list joins with the hint's own separator, an enum uses the catalog's value +# rather than the constant name, and an unset attribute writes nothing at all +check "codename1.arg.ios.pods=Alamofire,SwiftyJSON" +check "codename1.arg.ios.teamId=ABCDE12345" +check "codename1.arg.desktop.width=1280" +# The enum is written as the value the builder compares against, not the Java +# constant name -- INTERNAL_ONLY would be silently unrecognized. +check "codename1.arg.android.installLocation=internalOnly" +grep -q "codename1.arg.ios.objC" $EMITTED \ + && { echo "FAIL: an attribute nobody set must not be written"; exit 1; } +# A hint the properties file declares must not appear here: the annotations do +# not set it, and the two sources stay separate. +grep -q "codename1.arg.desktop.titleBar" $EMITTED \ + && { echo "FAIL: $EMITTED should only carry what the annotations declare"; exit 1; } + +echo "--- the hints must reach the build request ---" +# "Build target not supported" is thrown after the merged settings file is +# written, so this asserts the upload payload offline: no SDK, no cloud build. +set +e +./mvnw -B -q -DskipTests -Dcodename1.platform=javase \ + -Dcodename1.buildTarget=local-build-hint-probe package > /tmp/cn1-hints-build.log 2>&1 +set -e +MERGED=common/target/codenameone/antProject/codenameone_settings.properties +test -f $MERGED || MERGED=javase/target/codenameone/antProject/codenameone_settings.properties +# Do not treat an absent file as "nothing to check". This is the only assertion +# that the annotations reach the build request at all -- the checks above cover +# emission and the one below covers the conflict -- so if the probe stops +# producing a merged settings file, through a change in goal ordering, target +# validation or the merge itself, the test has to fail rather than quietly skip +# the thing it exists to prove. +if [ ! -f "$MERGED" ]; then + echo "FAIL: no build request was written; the annotation merge could not be verified." + echo " Looked for common/ and javase/target/codenameone/antProject/codenameone_settings.properties" + tail -40 /tmp/cn1-hints-build.log + exit 1 +fi +grep -q "codename1.arg.ios.pods=Alamofire,SwiftyJSON" $MERGED \ + || { echo "FAIL: annotation hints did not reach the build request"; cat $MERGED; exit 1; } +echo "OK: annotation hints reached $MERGED" + +echo "--- declaring the same hint twice must fail ---" +echo "codename1.arg.ios.teamId=FROMFILE" >> $SETTINGS +set +e +./mvnw -B -pl common process-classes > /tmp/cn1-hints-conflict.log 2>&1 +STATUS=$? +set -e +if [ $STATUS -eq 0 ]; then + echo "FAIL: a hint set in both the annotation and $SETTINGS should fail the build" + exit 1 +fi +grep -q "codename1.arg.ios.teamId is declared twice" /tmp/cn1-hints-conflict.log \ + || { echo "FAIL: the conflict error did not name the hint"; tail -30 /tmp/cn1-hints-conflict.log; exit 1; } +grep -q "@Ios(teamId)" /tmp/cn1-hints-conflict.log \ + || { echo "FAIL: the conflict error did not name the annotation attribute"; exit 1; } + +echo "PASSED build-hint-annotations-test" diff --git a/maven/javase/src/test/java/com/codename1/impl/javase/SimulatorAnnotationManifestTest.java b/maven/javase/src/test/java/com/codename1/impl/javase/SimulatorAnnotationManifestTest.java new file mode 100644 index 00000000000..3ce48681cea --- /dev/null +++ b/maven/javase/src/test/java/com/codename1/impl/javase/SimulatorAnnotationManifestTest.java @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2012, 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.codename1.impl.javase; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.Properties; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * The simulator picks the build-hint manifest that belongs to THIS application. + */ +public class SimulatorAnnotationManifestTest { + + private static File manifestIn(File dir, String mainClass, String hint) throws Exception { + File out = new File(dir, "META-INF/codenameone"); + out.mkdirs(); + File f = new File(out, "build-hints.properties"); + Properties p = new Properties(); + p.setProperty("cn1.buildHints.mainClass", mainClass); + p.setProperty("codename1.arg.desktop.titleBar", hint); + FileOutputStream os = new FileOutputStream(f); + try { + p.store(os, null); + } finally { + os.close(); + } + return f; + } + + /** + * A reactor dependency or a stale output directory earlier on the classpath + * can carry another application's manifest. Taking the first directory that + * has one ended the search there, and the caller then saw a main class that + * was not this one and published nothing -- so cn1:run silently + * dropped every annotated hint while this application's own manifest sat in + * a later classpath entry. + */ + @Test + public void aForeignDirectoryManifestIsPassedOver(@TempDir File tmp) throws Exception { + File other = new File(tmp, "other-classes"); + File mine = new File(tmp, "my-classes"); + manifestIn(other, "com.other.TheirApp", "MINIMAL"); + manifestIn(mine, "com.example.MyApp", "NATIVE"); + + String cp = other.getAbsolutePath() + File.pathSeparator + mine.getAbsolutePath(); + Simulator.FoundManifest found = + Simulator.findAnnotationManifest(tmp, cp, "com.example.MyApp"); + assertNotNull(found); + assertEquals("com.example.MyApp", found.hints.getProperty("cn1.buildHints.mainClass")); + assertEquals("NATIVE", found.hints.getProperty("codename1.arg.desktop.titleBar")); + } + + /** + * With no configured main class there is nothing to compare against, so the + * first manifest on the classpath is still the answer. + */ + @Test + public void withoutAMainClassTheFirstManifestWins(@TempDir File tmp) throws Exception { + File first = new File(tmp, "first"); + manifestIn(first, "com.other.TheirApp", "MINIMAL"); + Simulator.FoundManifest found = + Simulator.findAnnotationManifest(tmp, first.getAbsolutePath(), null); + assertNotNull(found); + assertEquals("MINIMAL", found.hints.getProperty("codename1.arg.desktop.titleBar")); + } + + /** + * Only foreign manifests, and no conventional build: nothing is published + * rather than another application's hints. + */ + @Test + public void onlyForeignManifestsFindNothing(@TempDir File tmp) throws Exception { + File other = new File(tmp, "other-classes"); + manifestIn(other, "com.other.TheirApp", "MINIMAL"); + assertNull(Simulator.findAnnotationManifest( + tmp, other.getAbsolutePath(), "com.example.MyApp")); + } + + /** + * Writes a jar holding the main class and the manifest, with the entry times + * given. + */ + private static File jarWith(File dir, String name, long classTime, long manifestTime) + throws Exception { + File jar = new File(dir, name); + ZipOutputStream out = new ZipOutputStream(new FileOutputStream(jar)); + try { + ZipEntry cls = new ZipEntry("com/example/MyApp.class"); + cls.setTime(classTime); + out.putNextEntry(cls); + out.write(CLASS_BYTES); + out.closeEntry(); + + ZipEntry res = new ZipEntry("META-INF/codenameone/build-hints.properties"); + res.setTime(manifestTime); + out.putNextEntry(res); + out.write("cn1.buildHints.mainClass=com.example.MyApp\n".getBytes("ISO-8859-1")); + out.closeEntry(); + } finally { + out.close(); + } + return jar; + } + + private static Properties stampedFor(String mainClass) { + Properties p = new Properties(); + p.setProperty("cn1.buildHints.mainClass", mainClass); + return p; + } + + /** + * Sharing an archive does not mean sharing a build. Nothing deletes an old + * manifest from target/classes, so a recompiled main class and + * last week's resource get packaged into the same jar -- and skipping the + * staleness check for jars published the old annotation values. + */ + @Test + public void aStaleManifestInsideAJarIsDetected(@TempDir File tmp) throws Exception { + long manifest = 1600000000000L; + long newerClass = manifest + 60000L; + File jar = jarWith(tmp, "app-stale.jar", newerClass, manifest); + + assertEquals("com/example/MyApp.class", Simulator.classNewerThanManifestInJar( + stampedFor("com.example.MyApp"), jar)); + } + + /** A manifest written after the class it describes is current. */ + @Test + public void aCurrentManifestInsideAJarIsAccepted(@TempDir File tmp) throws Exception { + long cls = 1600000000000L; + File jar = jarWith(tmp, "app-current.jar", cls, cls + 60000L); + + assertNull(Simulator.classNewerThanManifestInJar( + stampedFor("com.example.MyApp"), jar)); + } + + /** No class of that name in the jar is nothing to compare against. */ + @Test + public void aJarWithoutTheMainClassIsNotJudged(@TempDir File tmp) throws Exception { + long cls = 1600000000000L; + File jar = jarWith(tmp, "app-other.jar", cls + 60000L, cls); + + assertNull(Simulator.classNewerThanManifestInJar( + stampedFor("com.other.TheirApp"), jar)); + } + + private static final byte[] CLASS_BYTES = + new byte[] {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE}; + + /** SHA-256 of what jarWith puts in the class entry, hex. */ + private static String classBytesDigest() throws Exception { + java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256"); + md.update(CLASS_BYTES); + StringBuilder hex = new StringBuilder(); + for (byte b : md.digest()) { + hex.append(Character.forDigit((b >> 4) & 0xF, 16)); + hex.append(Character.forDigit(b & 0xF, 16)); + } + return hex.toString(); + } + + private static Properties stamped(String mainClass, String classDigest) { + Properties p = stampedFor(mainClass); + if (classDigest != null) { + p.setProperty("cn1.buildHints.classDigest", classDigest); + } + return p; + } + + /** + * Zip records entry times to two seconds, and a build configured for + * reproducible output stamps every entry identically -- so a stale manifest + * and the class it no longer describes can compare EQUAL, which made the + * timestamp rule inert rather than merely coarse. The recorded contents of + * the class settle it. + */ + @Test + public void aStaleManifestIsDetectedWhenTheTimestampsAreEqual(@TempDir File tmp) + throws Exception { + long same = 1600000000000L; + File jar = jarWith(tmp, "app-reproducible.jar", same, same); + + Simulator.FoundManifest found = new Simulator.FoundManifest( + stamped("com.example.MyApp", "0000deadbeef"), null, jar, "app-reproducible.jar"); + assertEquals("does not describe the compiled com/example/MyApp.class", + Simulator.staleManifestReason(found.hints, found)); + } + + /** ...and a digest that matches settles it the other way, timestamps aside. */ + @Test + public void aMatchingClassDigestOutranksTheTimestamps(@TempDir File tmp) throws Exception { + long manifest = 1600000000000L; + File jar = jarWith(tmp, "app-touched.jar", manifest + 60000L, manifest); + + Simulator.FoundManifest found = new Simulator.FoundManifest( + stamped("com.example.MyApp", classBytesDigest()), null, jar, "app-touched.jar"); + assertNull(Simulator.staleManifestReason(found.hints, found)); + } + + /** A manifest an older plugin wrote records no digest, so timestamps still decide. */ + @Test + public void withoutARecordedDigestTheTimestampsStillDecide(@TempDir File tmp) + throws Exception { + long manifest = 1600000000000L; + File jar = jarWith(tmp, "app-old.jar", manifest + 60000L, manifest); + + Simulator.FoundManifest found = new Simulator.FoundManifest( + stamped("com.example.MyApp", null), null, jar, "app-old.jar"); + assertEquals("is older than com/example/MyApp.class", + Simulator.staleManifestReason(found.hints, found)); + } + + /** A directory holding a class file and a manifest that does or does not describe it. */ + private static File outputDir(File parent, String name, String hint, boolean current) + throws Exception { + File dir = new File(parent, name); + File cls = new File(dir, "com/example/MyApp.class"); + cls.getParentFile().mkdirs(); + FileOutputStream cs = new FileOutputStream(cls); + try { + cs.write(CLASS_BYTES); + } finally { + cs.close(); + } + File out = new File(dir, "META-INF/codenameone"); + out.mkdirs(); + Properties p = new Properties(); + p.setProperty("cn1.buildHints.mainClass", "com.example.MyApp"); + p.setProperty("cn1.buildHints.classDigest", + current ? classBytesDigest() : "0000notthisbuild"); + p.setProperty("codename1.arg.desktop.titleBar", hint); + FileOutputStream os = new FileOutputStream(new File(out, "build-hints.properties")); + try { + p.store(os, null); + } finally { + os.close(); + } + return dir; + } + + /** + * A leftover output directory earlier on the classpath carries a manifest + * stamped for this same main class. Taking it ended the search, and the + * caller then reported it stale and published nothing -- while the current + * manifest sat in a later entry, so cn1:run dropped every + * annotated hint. + */ + @Test + public void aStaleManifestForThisApplicationIsPassedOver(@TempDir File tmp) throws Exception { + File old = outputDir(tmp, "stale-classes", "MINIMAL", false); + File now = outputDir(tmp, "current-classes", "NATIVE", true); + + String cp = old.getAbsolutePath() + File.pathSeparator + now.getAbsolutePath(); + Simulator.FoundManifest found = + Simulator.findAnnotationManifest(tmp, cp, "com.example.MyApp"); + assertNotNull(found); + assertEquals("NATIVE", found.hints.getProperty("codename1.arg.desktop.titleBar")); + } + + /** + * With nothing current anywhere the stale one is still returned, so the + * caller can say which file it is and why it was not used. + */ + @Test + public void withNothingCurrentTheStaleOneIsStillReported(@TempDir File tmp) throws Exception { + File old = outputDir(tmp, "only-stale", "MINIMAL", false); + + Simulator.FoundManifest found = + Simulator.findAnnotationManifest(tmp, old.getAbsolutePath(), "com.example.MyApp"); + assertNotNull(found); + assertEquals("MINIMAL", found.hints.getProperty("codename1.arg.desktop.titleBar")); + assertEquals("does not describe the compiled com/example/MyApp.class", + Simulator.staleManifestReason(found.hints, found)); + } +} diff --git a/maven/pom.xml b/maven/pom.xml index 303a83ec859..8184e0fff39 100644 --- a/maven/pom.xml +++ b/maven/pom.xml @@ -81,6 +81,7 @@ cn1-binaries platform-feature-catalog + build-hint-catalog java-runtime core factory diff --git a/scripts/build-hint-catalog-baseline.txt b/scripts/build-hint-catalog-baseline.txt new file mode 100644 index 00000000000..1c1820530bf --- /dev/null +++ b/scripts/build-hint-catalog-baseline.txt @@ -0,0 +1,8 @@ +# Build hints read by a builder or a mojo that the catalog does not describe, +# as of the day this gate was added. +# +# This is a ratchet, not an allow-list: new code must not add entries. Delete a +# line when the hint is added to maven/build-hint-catalog. Regenerate with +# scripts/check-build-hint-catalog.sh --write-baseline +# +# Format: |: diff --git a/scripts/build-hint-computed-sites.txt b/scripts/build-hint-computed-sites.txt new file mode 100644 index 00000000000..8b8ba7c5d77 --- /dev/null +++ b/scripts/build-hint-computed-sites.txt @@ -0,0 +1,42 @@ +# Call sites that BUILD a hint name rather than writing it as a literal, so no +# literal anywhere in the tree names the hint. The miner cannot resolve these -- +# the platform, or the entitlement, is only known at run time -- and before this +# file existed it did not report them either, so the gate could print "all +# described" while android.maps.provider and ios.nativeVerify had no catalog row +# at all. +# +# Every site the miner finds must be listed here with what it expands to, and +# every expansion must be catalogued or match a dynamic pattern. A new computed +# site therefore forces a catalog decision instead of disappearing. +# +# Format: ||[,...][#] +# +# The call count defaults to 1 and only matters when one file makes the same +# call twice: two `getArg(hintAndMarker[0], ...)` over different tables produce +# an identical key, so without it the second would be validated against the +# first one's expansions and its own hints never checked at all. +# +# Keyed by the expression, not just the file: a builder that already appears here +# would otherwise absorb a SECOND computed hint for free -- adding +# `platform + ".maps.apiKey"` beside the provider one kept the gate green while +# the new hint had no catalog row. The line number is deliberately not part of +# the key, so moving code does not churn this file. +# +# Reported when the expression BUILDS a name (contains a string literal) or reads +# one out of a table (contains a subscript). A helper that merely forwards a +# variable -- getArg(key, ...) inside a wrapper -- gets its literal from its +# caller, which the ordinary literal pass already mines, and is not reported. +# +# The table case is why the subscript counts: IPhoneBuilder's +# WALLET_INJECTION_HINTS holds ten real hints in a String[][] and reaches getArg +# as hintAndMarker[0], so no literal anywhere sits at a getArg call and every +# literal search -- including this gate -- reported success while all ten had no +# catalog row. + +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/MapsProviderInjector.java|platform + ".maps.provider"|android.maps.provider,ios.maps.provider +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/NativeVerifyOption.java|platformPrefix + "." + HINT|ios.nativeVerify,linux.nativeVerify,windows.nativeVerify +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/MacNativeBuilder.java|"macNative.provisioningProfile." + (isAppStore ? "appStore" : "developerID")|macNative.provisioningProfile.appStore,macNative.provisioningProfile.developerID +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/IPhoneBuilder.java|"ios.entitlements.com.apple.developer.healthkit." + suffix|ios.entitlements.com.apple.developer.healthkit.access +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/WatchNativeBuilder.java|"ios.entitlements.com.apple.developer.healthkit." + canonicalKey|ios.entitlements.com.apple.developer.healthkit.access +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/IPhoneBuilder.java|hintAndMarker[0]|ios.wallet.nonuiImportsInject,ios.wallet.statusInject,ios.wallet.passEntriesInject,ios.wallet.remotePassEntriesInject,ios.wallet.generateRequestInject,ios.wallet.generateResponseInject,ios.wallet.uiImportsInject,ios.wallet.uiViewDidLoadInject,ios.wallet.uiAuthRequestInject,ios.wallet.uiAuthResponseInject +maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/IPhoneBuilder.java|"ios." + privacyKey|ios.NSBluetoothAlwaysUsageDescription,ios.NSBluetoothPeripheralUsageDescription,ios.NSCameraUsageDescription,ios.NSMicrophoneUsageDescription,ios.NSSpeechRecognitionUsageDescription diff --git a/scripts/build_hint_miner.py b/scripts/build_hint_miner.py new file mode 100644 index 00000000000..a485f1e918a --- /dev/null +++ b/scripts/build_hint_miner.py @@ -0,0 +1,330 @@ +#!/usr/bin/env python3 +"""Mines every build hint the Maven plugin and the builders read. + +Three accessor shapes reach a hint; a getArg() grep alone misses the whole +@Desktop group, which is read only by a private arg() helper in +GenerateDesktopAppWrapperMojo. + +Arguments are split with a paren/quote-balanced scan rather than a regex, +because calls nest: getArg("ios.urlSchemes", getArg("ios.urlScheme", "")). +A regex that stops at the first comma both mis-reads the outer default and +consumes the inner call, silently dropping a hint from the catalog. + +Not every hint name is written as a literal at the point it is read. Two shapes +occur and both used to be invisible, which let the gate report "all described" +while real hints had no catalog row at all: + + getArg(HINT, null) NativeVerifyOption, HINT="nativeVerify" + getArg(platform + ".maps.provider", ...) MapsProviderInjector + +The first is resolved: a `static final String` in the same file whose value is a +literal is substituted. The second cannot be -- the platform is only known at +run time -- so it is reported as a COMPUTED site instead of ignored, and the +checker holds those against the catalog rather than letting them pass in +silence. +""" +import re, os, sys, json, collections + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SRC = os.path.join(ROOT, "maven/codenameone-maven-plugin/src/main/java/com/codename1") + +OPENERS = [ + (re.compile(r'\bgetArg\(\s*"'), False), + (re.compile(r'(?\[\], .?]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(([^)]*)\)\s*' + r'(?:throws [A-Za-z0-9_., ]+)?\{') + +# A local that is ASSEMBLED from a literal and then passed to an accessor: +# String requestKey = "ios." + privacyKey; +# request.getArg(requestKey, null) +# The accessor's argument is a bare variable, so it reads as a forwarder, but the +# name is built two lines up and no literal ever sits at a getArg call. +LOCAL_ASSEMBLY = re.compile( + r'\b(?:String\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([^;\n]*"[^;\n]*)\s*;') + +# Anything that gives the name a NEW value which is not an assembled literal: +# a for-each variable, a catch parameter, a declaration or an assignment with no +# literal in it. Such a binding shadows an earlier assembly, and ignoring that +# attributed IPhoneBuilder's PRODUCT_BUNDLE_IDENTIFIER key to three unrelated +# `for (String key : request.getArgs())` loops further down the same file. +REBINDS = re.compile( + r'for\s*\(\s*(?:final\s+)?[A-Za-z_][A-Za-z0-9_<>\[\], .?]*\s+([A-Za-z_][A-Za-z0-9_]*)\s*:' + r'|\b(?:String|var|Object|CharSequence)\s+([A-Za-z_][A-Za-z0-9_]*)\s*[=;)]' + r'|\b([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([^;\n"]*)\s*;') + +FORWARDS = re.compile(r'\b(?:getArg|booleanArg)\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,' + r'|(?` -- + backslashes the build never sees -- which then reached the developer guide. + """ + out = [] + while i < len(text): + c = text[i] + if c == '\\': + nxt = text[i + 1] if i + 1 < len(text) else '' + if nxt == 'u': + try: + out.append(chr(int(text[i + 2:i + 6], 16))); i += 6; continue + except ValueError: + # Not a well-formed \uXXXX after all. Fall through and treat + # the backslash as a plain escape rather than guessing at a + # code point; a malformed escape in a builder source is not + # this script's problem to diagnose. + pass + out.append(_ESCAPES.get(nxt, nxt)); i += 2; continue + if c == '"': + return "".join(out), i + 1 + out.append(c); i += 1 + return None, i + +def split_args(text, i): + """Split the argument list; i points just after the opening paren.""" + args, depth, cur = [], 0, [] + while i < len(text): + c = text[i] + if c == '"': + lit, j = read_literal(text, i + 1) + # Re-quote with proper escaping so a decoded inner quote does not + # break the literal-default check below. + cur.append(json.dumps(lit or "", ensure_ascii=False)); i = j; continue + if c == "'": + j = i + 1 + while j < len(text) and text[j] != "'": + j += 2 if text[j] == '\\' else 1 + cur.append(text[i:j+1]); i = j + 1; continue + if c in "([": + depth += 1 + elif c in ")]": + if depth == 0: + args.append("".join(cur).strip()); return args + depth -= 1 + elif c == ',' and depth == 0: + args.append("".join(cur).strip()); cur = []; i += 1; continue + cur.append(c); i += 1 + return args + +LITERAL_DEFAULT = re.compile(r'null|true|false|-?\d+|"(?:[^"\\]|\\.)*"') + +hits = collections.defaultdict(list) +computed = [] + + +def first_argument(text, open_paren): + """The first argument's source text, or None when the call is malformed.""" + args = split_args(text, open_paren + 1) + return args[0] if args else None + + +def resolve_constants(expr, constants): + """Substitute same-file string constants into a first-argument expression.""" + return re.sub(r'\b([A-Za-z_][A-Za-z0-9_]*)\b', + lambda m: json.dumps(constants[m.group(1)]) if m.group(1) in constants + else m.group(0), + expr) + + +def nearest(assembled, name, before): + """The rhs of the closest binding of `name` before `before`, if it assembles. + + None when the closest binding rebinds the name to something else -- a + for-each variable, a plain assignment -- because the earlier assembly no + longer describes what the accessor is handed. + """ + best = None + for offset, var, rhs in assembled: + if offset >= before: + break + if var == name: + best = rhs + return best + + +def concat_of_literals(expr): + """The value of a `"a" + "b"` expression, or None when a piece is not a literal.""" + parts = [p.strip() for p in expr.split('+')] + out = [] + for part in parts: + if len(part) >= 2 and part.startswith('"') and part.endswith('"'): + lit, _ = read_literal(part, 1) + if lit is None: + return None + out.append(lit) + else: + return None + return "".join(out) + +for dirpath, _, files in os.walk(SRC): + for fn in sorted(files): + if not fn.endswith(".java"): + continue + path = os.path.join(dirpath, fn) + with open(path, encoding="utf-8", errors="replace") as fh: + text = fh.read() + rel = os.path.relpath(path, ROOT) + constants = {m.group(1): (read_literal(m.group(0), m.group(0).index('"') + 1)[0] or "") + for m in CONST_DECL.finditer(text)} + # (offset, name, rhs) for every local built from a literal, in order. + # + # Kept as a LIST and matched to the nearest PRECEDING assignment, not as a + # name->rhs map. A map is file-wide, and `key` is a common enough variable + # name that an assignment far below -- IPhoneBuilder builds an Xcode + # setting key called PRODUCT_BUNDLE_IDENTIFIER+qualifier -- was being + # attributed to an unrelated getArg(key, ...) thousands of lines above it, + # reporting a computed hint site that does not exist. + assembled = [] + for m in LOCAL_ASSEMBLY.finditer(text): + rhs = m.group(2).strip() + # Only an assembly, not a plain literal: a plain one is already mined + # wherever it reaches an accessor. + if '+' in rhs: + assembled.append((m.start(), m.group(1), rhs)) + # A declaration that IS the assembly matches both patterns at the same + # offset; it must not cancel itself out. + assembly_offsets = {offset for offset, _, _ in assembled} + for m in REBINDS.finditer(text): + name = m.group(1) or m.group(2) or m.group(3) + if name and m.start() not in assembly_offsets: + assembled.append((m.start(), name, None)) + assembled.sort(key=lambda e: e[0]) + for m in COMPUTED_OPENER.finditer(text): + open_paren = text.rindex('(', m.start(), m.end()) + expr = first_argument(text, open_paren) + if not expr: + continue + line = text.count("\n", 0, m.start()) + 1 + resolved = concat_of_literals(resolve_constants(expr, constants)) + if resolved is not None: + # Fully resolved -- an ordinary hint read that merely spelled its + # name with a constant. + hits[resolved].append(("", rel, line)) + elif re.fullmatch(r'[A-Za-z_][A-Za-z0-9_]*', expr) and nearest( + assembled, expr, m.start()) is not None: + # A bare variable, but one built from a literal ABOVE this call. + computed.append({"expr": " ".join(nearest(assembled, expr, m.start()).split()), + "file": rel, "line": line}) + elif '"' in expr or '[' in expr: + # The name is BUILT here, or read out of a table -- either way no + # literal at a getArg call names it, so the literal pass cannot + # see it. IPhoneBuilder's WALLET_INJECTION_HINTS is the second + # kind: ten real hints living in a String[][] and reaching getArg + # as hintAndMarker[0], invisible to every literal search until + # subscripts were reported too. + computed.append({"expr": " ".join(expr.split()), + "file": rel, "line": line}) + # Anything else is a forwarding helper -- getArg(key, ...) inside a + # wrapper, or the declaration of getArg itself -- whose caller passes a + # literal that the literal pass already mines. Reporting those would bury + # the handful of sites that genuinely compute a name. + # Literals that only ever reach an accessor through a helper. + for wrapper, index in sorted(accessor_wrappers(text).items()): + for m in re.finditer(r'(?= 2 and arg.startswith('"') and arg.endswith('"')): + continue + key, _ = read_literal(arg, 1) + if key is None or not re.fullmatch(r'[A-Za-z][A-Za-z0-9_.!]*', key): + continue + line = text.count("\n", 0, m.start()) + 1 + hits[key].append(("", rel, line)) + for pat, prefixed in OPENERS: + for m in pat.finditer(text): + # position of the char just after the opening quote of arg 1 + key, after = read_literal(text, m.end()) + if key is None: + continue + if prefixed: + if not key: + continue + else: + if not re.fullmatch(r'[A-Za-z][A-Za-z0-9_.!]*', key): + continue + # find the call's opening paren to split the whole arg list + open_paren = text.rindex('(', m.start(), m.end()) + args = split_args(text, open_paren + 1) + default = args[1].strip() if len(args) > 1 else "" + if not LITERAL_DEFAULT.fullmatch(default or "null"): + default = "" + line = text.count("\n", 0, m.start()) + 1 + hits[key].append((default or "null", rel, line)) + +def hits_computed(): + """(expression, file, line) for every site that builds a hint name.""" + return sorted((c["expr"], c["file"], c["line"]) for c in computed) + + +if __name__ == "__main__": + print(f"distinct keys mined: {len(hits)}, computed sites: {len(computed)}", + file=sys.stderr) + out = sys.argv[1] if len(sys.argv) > 1 else "-" + payload = {k: v for k, v in sorted(hits.items())} + # Under a key no hint name can take, so a consumer reading this as a plain + # name->sites map cannot mistake it for a hint. + payload["#computed"] = sorted( + (c["expr"], c["file"], c["line"]) for c in computed) + if out == "-": + json.dump(payload, sys.stdout, indent=1) + else: + with open(out, "w", encoding="utf-8") as fh: + json.dump(payload, fh, indent=1) diff --git a/scripts/certificatewizard/common/codenameone_settings.properties b/scripts/certificatewizard/common/codenameone_settings.properties index 86cf88fa524..b6d065730e0 100644 --- a/scripts/certificatewizard/common/codenameone_settings.properties +++ b/scripts/certificatewizard/common/codenameone_settings.properties @@ -7,10 +7,4 @@ codename1.secondaryTitle=Certificate Wizard codename1.icon=icon.png codename1.cssTheme=true codename1.arg.java.version=17 -codename1.arg.nativeTheme=modern -codename1.arg.ios.themeMode=modern -codename1.arg.and.themeMode=modern -codename1.arg.desktop.width=1260 -codename1.arg.desktop.height=820 -codename1.arg.desktop.titleBar=native codename1.kotlin=false diff --git a/scripts/certificatewizard/common/src/main/java/com/codename1/certificatewizard/CertificateWizard.java b/scripts/certificatewizard/common/src/main/java/com/codename1/certificatewizard/CertificateWizard.java index 116a660dd0a..99254d5b752 100644 --- a/scripts/certificatewizard/common/src/main/java/com/codename1/certificatewizard/CertificateWizard.java +++ b/scripts/certificatewizard/common/src/main/java/com/codename1/certificatewizard/CertificateWizard.java @@ -67,7 +67,12 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; +import com.codename1.annotations.buildhints.*; +@Android(themeMode = AndroidThemeMode.MODERN) +@Build(nativeTheme = NativeThemeMode.MODERN) +@Desktop(height = 820, titleBar = DesktopTitleBar.NATIVE, width = 1260) +@Ios(themeMode = IosThemeMode.MODERN) public class CertificateWizard extends Lifecycle { public enum Section { OVERVIEW, CREDENTIAL, CERTIFICATES, BUNDLES, DEVICES, PROFILES, APNS, MAC, ANDROID, WINDOWS, MAINTENANCE } diff --git a/scripts/check-build-hint-catalog.py b/scripts/check-build-hint-catalog.py new file mode 100755 index 00000000000..a45d4dc8c38 --- /dev/null +++ b/scripts/check-build-hint-catalog.py @@ -0,0 +1,264 @@ +#!/usr/bin/env python3 +"""Reports build hints the code reads that the catalog does not describe. + +A hint the catalog does not know about is invisible to everything downstream: +it gets no annotation, no doc row, no entry in the Settings tool, and no +value checking. That is how `android.xPermissions` shipped in our own agent +reference for a hint the builder actually spells `android.xpermissions` -- +green build, no effect, nobody noticed. + +Held against a baseline rather than failing outright: a large tail of hints +predates the catalog. The point is that *new* code cannot add another one. +""" +import collections, fnmatch, os, re, sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, os.path.join(ROOT, "scripts")) +BASELINE = os.path.join(ROOT, "scripts", "build-hint-catalog-baseline.txt") +COMPUTED_SITES = os.path.join(ROOT, "scripts", "build-hint-computed-sites.txt") +CATALOG_CLASSES = os.path.join(ROOT, "maven/build-hint-catalog/target/classes") + + +def catalog(): + """(known names, dynamic patterns) straight out of the compiled catalog.""" + src = os.path.join(ROOT, "maven/build-hint-catalog/src/main/java/com/codename1/build/shared") + names, patterns = set(), set() + for fn in sorted(os.listdir(src)): + if not fn.startswith("BuildHints") or not fn.endswith(".java"): + continue + with open(os.path.join(src, fn), encoding="utf-8") as fh: + text = fh.read() + for m in re.finditer(r'new Hint\("((?:[^"\\]|\\.)*)"\)', text): + names.add(m.group(1)) + for m in re.finditer(r'\.dynamic\("((?:[^"\\]|\\.)*)"\)', text): + patterns.add(m.group(1)) + # BuildHintsDynamic registers through a helper; take its literals too + for m in re.finditer(r'family\(h,\s*"((?:[^"\\]|\\.)*)"', text): + names.add(m.group(1)) + patterns.add(m.group(1)) + return names, patterns + + +DOC_ROOTS = [ + "scripts/initializr/common/src/main/resources/skill", + "maven/cn1app-archetype/src/main/resources/archetype-resources", +] + + +def documented_hints(): + """Every codename1.arg.* key our own docs and templates name. + + These are read by people and by coding agents, and a key that no builder + reads is silently inert -- which is exactly how android.xPermissions, + android.minSdkVersion and android.sdkVersion came to be recommended in the + agent reference for hints the builder spells differently or not at all. + """ + found = {} + for root in DOC_ROOTS: + base = os.path.join(ROOT, root) + for dirpath, _, files in os.walk(base): + for fn in files: + if not fn.endswith((".md", ".properties", ".java", ".adoc")): + continue + path = os.path.join(dirpath, fn) + try: + with open(path, encoding="utf-8", errors="replace") as fh: + text = fh.read() + except OSError: + continue + for m in re.finditer(r'codename1\.arg\.([A-Za-z][A-Za-z0-9_.]*)', text): + key = m.group(1) + # "codename1.arg.var." is written with a placeholder suffix; + # keep the trailing dot so it still matches the var.* family. + if key.endswith("."): + key += "*" + found.setdefault(key, os.path.relpath(path, ROOT)) + return found + + +def main(): + write = "--write-baseline" in sys.argv + import build_hint_miner as miner + + known, patterns = catalog() + if not known: + print("check-build-hint-catalog: found no catalog entries -- is the source tree intact?", + file=sys.stderr) + return 2 + + findings = [] + for key, sites in sorted(miner.hits.items()): + if key in known: + continue + if any(fnmatch.fnmatch(key, p) for p in patterns): + continue + rel, line = sites[0][1], sites[0][2] + findings.append(f"{key}|{rel}:{line}") + + if write: + with open(BASELINE, "w") as f: + f.write(HEADER) + for line in findings: + f.write(line + "\n") + print(f"check-build-hint-catalog: wrote {len(findings)} baseline entries") + return 0 + + baseline = set() + if os.path.exists(BASELINE): + with open(BASELINE, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if line and not line.startswith("#"): + baseline.add(line.split("|")[0]) + + current = {f.split("|")[0]: f for f in findings} + added = sorted(set(current) - baseline) + removed = sorted(baseline - set(current)) + + if added: + print("check-build-hint-catalog: build hints read by the code that the catalog " + "does not describe:", file=sys.stderr) + for key in added: + print(" " + current[key].replace("|", " read at "), file=sys.stderr) + print("\nAdd each one to maven/build-hint-catalog/.../BuildHints*.java. A hint the " + "catalog does not know about gets no annotation, no documentation and no " + "value checking.", file=sys.stderr) + if removed: + print("\ncheck-build-hint-catalog: these baseline entries are now catalogued; " + "delete them from\n scripts/build-hint-catalog-baseline.txt", file=sys.stderr) + for key in removed: + print(" " + key, file=sys.stderr) + if added or removed: + return 1 + + # Our own docs and project templates must not name a hint that does not exist. + doc_bad = [] + for key, where in sorted(documented_hints().items()): + if key in known: + continue + if any(fnmatch.fnmatch(key, p) for p in patterns): + continue + doc_bad.append(f"{key} named in {where}") + if doc_bad: + print("check-build-hint-catalog: our own documentation names build hints that do " + "not exist:", file=sys.stderr) + for line in doc_bad: + print(" " + line, file=sys.stderr) + print("\nA hint nothing reads is silently ignored, so a reader who copies it gets a " + "green build and no effect.", file=sys.stderr) + return 1 + + # Sites that build a hint name instead of writing it. Nothing in the tree + # names the hint they read, so the pass above cannot see it -- which is how + # this gate came to report "all described" while android.maps.provider and + # ios.nativeVerify had no catalog row. + declared = {} + if os.path.exists(COMPUTED_SITES): + with open(COMPUTED_SITES, encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#"): + continue + # Split from both ends: the expression sits in the middle and may + # itself contain a pipe, while the file and the expansion list + # cannot. + path, _, rest = line.partition("|") + expr, _, expansions = rest.rpartition("|") + names, _, count = expansions.partition("#") + declared[(path, " ".join(expr.split()))] = ( + [e for e in names.split(",") if e], + int(count) if count.strip() else 1) + + computed_bad = [] + mined = miner.hits_computed() + seen_counts = collections.Counter( + (path, " ".join(expr.split())) for expr, path, _ in mined) + for expr, path, line_no in mined: + key = (path, " ".join(expr.split())) + if key not in declared: + # Keyed by the expression as well as the file, so a builder already + # listed cannot absorb a second computed hint for free. + computed_bad.append( + f"{path}:{line_no} builds a hint name from `{expr}` and is not listed") + continue + for name in declared[key][0]: + if name in known or any(fnmatch.fnmatch(name, p) for p in patterns): + continue + computed_bad.append( + f"{path}:{line_no} expands to {name}, which the catalog does not describe") + # Two calls in one file can read the same expression -- a second + # getArg(hintAndMarker[0], ...) over a different table -- and the key alone + # cannot tell them apart, so the newcomer would be validated against the old + # table's expansions and its own hints would never be checked. The declared + # occurrence count is what notices; the accounting line has to be revisited + # for the second call, which is the point. + for key, expected in sorted(declared.items()): + actual = seen_counts.get(key, 0) + if actual != expected[1]: + path, expr = key + computed_bad.append( + f"{path} is listed once for `{expr}` covering {expected[1]} call(s), " + f"but {actual} were mined -- list the expansions of every one and " + f"record the count as `#{actual}`") + if computed_bad: + print("check-build-hint-catalog: computed hint names are unaccounted for:", + file=sys.stderr) + for line in sorted(set(computed_bad)): + print(" " + line, file=sys.stderr) + print("\nList the site in scripts/build-hint-computed-sites.txt with what it " + "expands to, and catalogue each expansion. A hint whose name is only ever " + "computed is invisible to every literal search, including this one.", + file=sys.stderr) + return 1 + + # The plist keys the platform feature catalog injects become ios. build + # hints that an app may override. They reach getArg through a locally built + # name, so the computed-site accounting covers them -- but that accounting + # lists today's expansions, and a NEW entry there would change neither the + # expression nor the call count. This reads the other catalog directly, so + # adding a plist entry without a build hint row fails here instead. + # + # A CONCRETE row, not a dynamic pattern. ios.NS*UsageDescription exists so an + # app can set an arbitrary Apple key, and it was quietly absorbing these -- + # which is why the gate reported success while ios.NSBluetoothAlwaysUsage- + # Description had no annotation, no doc row and no editor entry. A key WE + # inject is a known one, and known keys get described individually. + plist_src = os.path.join( + ROOT, "maven/platform-feature-catalog/src/main/java/com/codename1/build/shared", + "PlatformFeatureCatalog.java") + plist_bad = [] + if os.path.exists(plist_src): + with open(plist_src, encoding="utf-8") as fh: + for m in re.finditer(r'\.iosPlist\(\s*"([^"\\]+)"', fh.read()): + name = "ios." + m.group(1) + if name in known: + continue + plist_bad.append(name) + if plist_bad: + print("check-build-hint-catalog: the platform feature catalog injects plist entries the " + "build hint catalog does not describe:", file=sys.stderr) + for name in sorted(set(plist_bad)): + print(f" {name} injected by PlatformFeatureCatalog.iosPlist", file=sys.stderr) + print("\nAn app can override any of these with a build hint of that name, so each one " + "needs a catalog row like the other ios.NS*UsageDescription entries.", + file=sys.stderr) + return 1 + + print(f"check-build-hint-catalog: {len(miner.hits)} hints read, all described by the " + f"catalog; {len(declared)} computed site(s) accounted for" + + (f" ({len(baseline)} baselined)" if baseline else "")) + return 0 + + +HEADER = """# Build hints read by a builder or a mojo that the catalog does not describe, +# as of the day this gate was added. +# +# This is a ratchet, not an allow-list: new code must not add entries. Delete a +# line when the hint is added to maven/build-hint-catalog. Regenerate with +# scripts/check-build-hint-catalog.sh --write-baseline +# +# Format: |: +""" + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/check-build-hint-catalog.sh b/scripts/check-build-hint-catalog.sh new file mode 100755 index 00000000000..ac276d5bcf1 --- /dev/null +++ b/scripts/check-build-hint-catalog.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# +# Fails when code reads a build hint that the catalog does not describe. +# +# Build hints are string keys. Nothing checks them, so a hint that is misspelled +# where it is read -- or added to a builder and nowhere else -- simply does +# nothing: the build is green and the feature is inert. The catalog in +# maven/build-hint-catalog is what gives every hint a type, a default, a value +# domain and a doc row, and it is what the @Ios/@Android annotations are +# generated from. A hint missing from it is invisible to all of that. +# +# scripts/check-build-hint-catalog.sh [--write-baseline] +# +# The result is held against scripts/build-hint-catalog-baseline.txt, a ratchet +# of pre-existing debt rather than an allow-list. That file is currently empty: +# every hint the code reads is described. Keep it that way -- a new entry means +# a new hint went in without a catalog row. +# +# Reads source, not bytecode, so nothing has to be built first and no module can +# silently drop out of coverage. +set -euo pipefail + +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +exec python3 "$SCRIPT_DIR/check-build-hint-catalog.py" "$@" diff --git a/scripts/ci/retry.sh b/scripts/ci/retry.sh index d5e43beeced..3c7ff5f00bd 100755 --- a/scripts/ci/retry.sh +++ b/scripts/ci/retry.sh @@ -22,6 +22,12 @@ set -uo pipefail # gets a second chance. Leave it unset for steps that merely download and build. attempts="${RETRY_ATTEMPTS:-3}" delay="${RETRY_DELAY_SECONDS:-30}" +# The wait GROWS. A flat retry spends all its attempts inside the same window +# Central is still refusing in -- observed as three 403s in sixty seconds, which +# failed the branch for a reason that had nothing to do with it. Quadrupling +# from the first delay gives 30s, 2m, 5m, which is the same shape the Windows +# cross-compile workflow settled on for the same reason. +max_delay="${RETRY_MAX_DELAY_SECONDS:-300}" only_matching="${RETRY_ONLY_MATCHING:-}" if [ "$#" -eq 0 ]; then @@ -38,6 +44,13 @@ esac case "$delay" in ''|*[!0-9]*) echo "retry.sh: RETRY_DELAY_SECONDS must be a non-negative integer, got '${delay}'" >&2; exit 2 ;; esac +case "$max_delay" in + ''|*[!0-9]*) echo "retry.sh: RETRY_MAX_DELAY_SECONDS must be a non-negative integer, got '${max_delay}'" >&2; exit 2 ;; +esac +if [ "$max_delay" -lt "$delay" ]; then + max_delay="$delay" +fi +wait_seconds="$delay" # Counted with arithmetic rather than `seq`: BSD and GNU seq disagree on # degenerate ranges, and this loop body must run exactly `attempts` times. @@ -69,8 +82,12 @@ while [ "$attempt" -le "$attempts" ]; do fi if [ "$attempt" -lt "$attempts" ]; then echo "retry.sh: attempt ${attempt}/${attempts} failed with status ${status};" \ - "retrying in ${delay}s (possible transient Maven Central 403/429/5xx)" >&2 - sleep "$delay" + "retrying in ${wait_seconds}s (possible transient Maven Central 403/429/5xx)" >&2 + sleep "$wait_seconds" + wait_seconds=$((wait_seconds * 4)) + if [ "$wait_seconds" -gt "$max_delay" ]; then + wait_seconds="$max_delay" + fi fi attempt=$((attempt + 1)) done diff --git a/scripts/cn1playground/common/codenameone_settings.properties b/scripts/cn1playground/common/codenameone_settings.properties index 454539b07fc..10505aa8793 100644 --- a/scripts/cn1playground/common/codenameone_settings.properties +++ b/scripts/cn1playground/common/codenameone_settings.properties @@ -2,14 +2,9 @@ codename1.android.keystore= codename1.android.keystoreAlias= codename1.android.keystorePassword= codename1.arg.block_server_registration=true -codename1.arg.ios.newStorageLocation=true -codename1.arg.ios.NSCameraUsageDescription=Some functionality of the application requires your camera # Preview the iOS Modern (liquid-glass) and Android Material 3 # themes inside the playground so users see the modern look when # they explore components. -codename1.arg.nativeTheme=modern -codename1.arg.ios.themeMode=modern -codename1.arg.and.themeMode=modern codename1.arg.java.version=17 codename1.arg.javascript.inject_proxy=false codename1.cssTheme=true diff --git a/scripts/cn1playground/common/pom.xml b/scripts/cn1playground/common/pom.xml index d4ca37ab375..aa34a1fdd46 100644 --- a/scripts/cn1playground/common/pom.xml +++ b/scripts/cn1playground/common/pom.xml @@ -403,6 +403,7 @@ bytecode-compliance css + process-annotations diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/GeneratedCN1Access.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/GeneratedCN1Access.java index b201e255758..754b57a9faa 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/GeneratedCN1Access.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/GeneratedCN1Access.java @@ -35,6 +35,7 @@ import bsh.cn1.gen.GeneratedAccess_com_codename1_ai_vision; import bsh.cn1.gen.GeneratedAccess_com_codename1_analytics; import bsh.cn1.gen.GeneratedAccess_com_codename1_annotations; +import bsh.cn1.gen.GeneratedAccess_com_codename1_annotations_buildhints; import bsh.cn1.gen.GeneratedAccess_com_codename1_annotations_graphql; import bsh.cn1.gen.GeneratedAccess_com_codename1_annotations_grpc; import bsh.cn1.gen.GeneratedAccess_com_codename1_annotations_rest; @@ -88,6 +89,11 @@ import bsh.cn1.gen.GeneratedAccess_com_codename1_health_nutrition; import bsh.cn1.gen.GeneratedAccess_com_codename1_health_sensors; import bsh.cn1.gen.GeneratedAccess_com_codename1_health_workout; +import bsh.cn1.gen.GeneratedAccess_com_codename1_home; +import bsh.cn1.gen.GeneratedAccess_com_codename1_home_commissioning; +import bsh.cn1.gen.GeneratedAccess_com_codename1_home_spi; +import bsh.cn1.gen.GeneratedAccess_com_codename1_intents; +import bsh.cn1.gen.GeneratedAccess_com_codename1_intents_spi; import bsh.cn1.gen.GeneratedAccess_com_codename1_io; import bsh.cn1.gen.GeneratedAccess_com_codename1_io_bonjour; import bsh.cn1.gen.GeneratedAccess_com_codename1_io_graphql; @@ -125,6 +131,7 @@ import bsh.cn1.gen.GeneratedAccess_com_codename1_push; import bsh.cn1.gen.GeneratedAccess_com_codename1_router; import bsh.cn1.gen.GeneratedAccess_com_codename1_security; +import bsh.cn1.gen.GeneratedAccess_com_codename1_security_hardening; import bsh.cn1.gen.GeneratedAccess_com_codename1_security_shield; import bsh.cn1.gen.GeneratedAccess_com_codename1_security_shield_spi; import bsh.cn1.gen.GeneratedAccess_com_codename1_sensors; @@ -264,24 +271,31 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.ai.language.Translator", "com.codename1.ai.language.Translator.Session", "com.codename1.ai.vision.Barcode", + "com.codename1.ai.vision.BarcodeFormat", "com.codename1.ai.vision.BarcodeScanner", + "com.codename1.ai.vision.CodeScanner", + "com.codename1.ai.vision.CodeScannerOptions", "com.codename1.ai.vision.DocumentScanResult", "com.codename1.ai.vision.DocumentScanner", "com.codename1.ai.vision.Face", "com.codename1.ai.vision.FaceDetector", + "com.codename1.ai.vision.FaceLandmarks", "com.codename1.ai.vision.ImageLabel", "com.codename1.ai.vision.ImageLabeler", "com.codename1.ai.vision.Pose", "com.codename1.ai.vision.Pose.Landmark", "com.codename1.ai.vision.PoseDetector", + "com.codename1.ai.vision.PoseLandmarks", "com.codename1.ai.vision.SegmentationMask", "com.codename1.ai.vision.SelfieSegmenter", "com.codename1.ai.vision.TextRecognitionResult", "com.codename1.ai.vision.TextRecognitionResult.TextBlock", "com.codename1.ai.vision.TextRecognizer", + "com.codename1.ai.vision.TextScript", "com.codename1.ai.vision.VisionAnalyzer", "com.codename1.ai.vision.VisionBackend", "com.codename1.ai.vision.VisionBackends", + "com.codename1.ai.vision.VisionCameraView", "com.codename1.ai.vision.VisionException", "com.codename1.ai.vision.VisionFeature", "com.codename1.ai.vision.VisionImage", @@ -311,6 +325,7 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.analytics.LegacyAnalyticsProviderAdapter", "com.codename1.analytics.LoggingAnalyticsProvider", "com.codename1.analytics.MatomoAnalyticsProvider", + "com.codename1.annotations.AppIntent", "com.codename1.annotations.Async", "com.codename1.annotations.Async.Execute", "com.codename1.annotations.Async.Schedule", @@ -323,9 +338,17 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.annotations.DisableNullChecksAndArrayBoundsChecks", "com.codename1.annotations.Email", "com.codename1.annotations.Entity", + "com.codename1.annotations.EntityId", + "com.codename1.annotations.EntityImage", + "com.codename1.annotations.EntityQuery", + "com.codename1.annotations.EntityQuery.Kind", + "com.codename1.annotations.EntitySubtitle", + "com.codename1.annotations.EntityTitle", "com.codename1.annotations.ExistIn", "com.codename1.annotations.Fused", "com.codename1.annotations.Id", + "com.codename1.annotations.IntentEntity", + "com.codename1.annotations.IntentParam", "com.codename1.annotations.JsonIgnore", "com.codename1.annotations.JsonProperty", "com.codename1.annotations.Length", @@ -342,6 +365,23 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.annotations.XmlElement", "com.codename1.annotations.XmlRoot", "com.codename1.annotations.XmlTransient", + "com.codename1.annotations.buildhints.Android", + "com.codename1.annotations.buildhints.AndroidThemeMode", + "com.codename1.annotations.buildhints.Build", + "com.codename1.annotations.buildhints.Desktop", + "com.codename1.annotations.buildhints.DesktopTitleBar", + "com.codename1.annotations.buildhints.HardenControlFlow", + "com.codename1.annotations.buildhints.HardenLevel", + "com.codename1.annotations.buildhints.HardenStrings", + "com.codename1.annotations.buildhints.Hardening", + "com.codename1.annotations.buildhints.InstallLocation", + "com.codename1.annotations.buildhints.Ios", + "com.codename1.annotations.buildhints.IosDependencyManager", + "com.codename1.annotations.buildhints.IosPrivacy", + "com.codename1.annotations.buildhints.IosProjectType", + "com.codename1.annotations.buildhints.IosThemeMode", + "com.codename1.annotations.buildhints.NativeThemeMode", + "com.codename1.annotations.buildhints.OnDeviceDebug", "com.codename1.annotations.graphql.GraphQLClient", "com.codename1.annotations.graphql.Mutation", "com.codename1.annotations.graphql.Query", @@ -671,7 +711,10 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.crash.CrashProtection", "com.codename1.crash.PiiScrubber", "com.codename1.db.Cursor", + "com.codename1.db.CursorExt", "com.codename1.db.Database", + "com.codename1.db.DatabaseConfig", + "com.codename1.db.DatabaseEncryptionException", "com.codename1.db.Row", "com.codename1.db.RowExt", "com.codename1.db.ThreadSafeDatabase", @@ -961,6 +1004,70 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.health.workout.WorkoutSession", "com.codename1.health.workout.WorkoutSessionListener", "com.codename1.health.workout.WorkoutSessionState", + "com.codename1.home.Accessory", + "com.codename1.home.AccessoryCategory", + "com.codename1.home.AccessoryService", + "com.codename1.home.AirQualityLevel", + "com.codename1.home.AlarmState", + "com.codename1.home.ChargingState", + "com.codename1.home.DoorState", + "com.codename1.home.FanMode", + "com.codename1.home.HeatingCoolingMode", + "com.codename1.home.HomeAuthorizationStatus", + "com.codename1.home.HomeAvailability", + "com.codename1.home.HomeBackend", + "com.codename1.home.HomeChangeListener", + "com.codename1.home.HomeConfigurationException", + "com.codename1.home.HomeError", + "com.codename1.home.HomeException", + "com.codename1.home.HomeRoom", + "com.codename1.home.HomeStructure", + "com.codename1.home.HomeStructureEvent", + "com.codename1.home.HomeStructureListener", + "com.codename1.home.HomeZone", + "com.codename1.home.LockState", + "com.codename1.home.PositionState", + "com.codename1.home.Scene", + "com.codename1.home.SceneAction", + "com.codename1.home.SceneType", + "com.codename1.home.ServiceType", + "com.codename1.home.SmartHome", + "com.codename1.home.StructureChangeKind", + "com.codename1.home.SubscriptionRequest", + "com.codename1.home.Trait", + "com.codename1.home.TraitChangeBatch", + "com.codename1.home.TraitConstraint", + "com.codename1.home.TraitReadRequest", + "com.codename1.home.TraitReading", + "com.codename1.home.TraitSubscription", + "com.codename1.home.TraitUnit", + "com.codename1.home.TraitUnitDimension", + "com.codename1.home.TraitValue", + "com.codename1.home.TraitValueKind", + "com.codename1.home.TraitWrite", + "com.codename1.home.TraitWriteResult", + "com.codename1.home.commissioning.Commissioner", + "com.codename1.home.commissioning.CommissioningRequest", + "com.codename1.home.commissioning.CommissioningResult", + "com.codename1.home.commissioning.CommissioningStyle", + "com.codename1.home.commissioning.SetupPayload", + "com.codename1.home.spi.HomeBridge", + "com.codename1.intents.AppEntity", + "com.codename1.intents.DynamicIntent", + "com.codename1.intents.EntitySelectionHandler", + "com.codename1.intents.Exposure", + "com.codename1.intents.IntentCompletion", + "com.codename1.intents.IntentContext", + "com.codename1.intents.IntentDates", + "com.codename1.intents.IntentDeclaration", + "com.codename1.intents.IntentDispatcher", + "com.codename1.intents.IntentParameterInfo", + "com.codename1.intents.IntentParameterType", + "com.codename1.intents.IntentResult", + "com.codename1.intents.IntentSerializer", + "com.codename1.intents.IntentSource", + "com.codename1.intents.Intents", + "com.codename1.intents.spi.IntentBridge", "com.codename1.io.AccessToken", "com.codename1.io.BufferedInputStream", "com.codename1.io.BufferedOutputStream", @@ -1361,6 +1468,8 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.security.SecureRandom", "com.codename1.security.SecureStorage", "com.codename1.security.Signature", + "com.codename1.security.TapjackingPolicy", + "com.codename1.security.hardening.Hardening", "com.codename1.security.shield.AppShield", "com.codename1.security.shield.FailureMode", "com.codename1.security.shield.HostPolicy", @@ -1820,6 +1929,7 @@ public final class GeneratedCN1Access implements CN1Access { "com.codename1.vr.VRSettings", "com.codename1.vr.VRView", "com.codename1.wearable.WearableConnection", + "com.codename1.wearable.WearableConnection.DroppedDeliveryHandler", "com.codename1.wearable.WearableDataListener", "com.codename1.wearable.WearableMessage", "com.codename1.wearable.WearableMessageListener", @@ -2072,6 +2182,8 @@ private static Map buildMethodIndex() { fillMethodIndex26(index); fillMethodIndex27(index); fillMethodIndex28(index); + fillMethodIndex29(index); + fillMethodIndex30(index); return index; } @@ -2157,24 +2269,31 @@ private static void fillMethodIndex1(Map index) { index.put("com.codename1.ai.language.Translator", splitMembers("")); index.put("com.codename1.ai.language.Translator.Session", splitMembers("")); index.put("com.codename1.ai.vision.Barcode", splitMembers("")); + index.put("com.codename1.ai.vision.BarcodeFormat", splitMembers("")); index.put("com.codename1.ai.vision.BarcodeScanner", splitMembers("")); + index.put("com.codename1.ai.vision.CodeScanner", splitMembers("")); + index.put("com.codename1.ai.vision.CodeScannerOptions", splitMembers("")); index.put("com.codename1.ai.vision.DocumentScanResult", splitMembers("")); index.put("com.codename1.ai.vision.DocumentScanner", splitMembers("")); index.put("com.codename1.ai.vision.Face", splitMembers("")); index.put("com.codename1.ai.vision.FaceDetector", splitMembers("")); + index.put("com.codename1.ai.vision.FaceLandmarks", splitMembers("")); index.put("com.codename1.ai.vision.ImageLabel", splitMembers("")); index.put("com.codename1.ai.vision.ImageLabeler", splitMembers("")); index.put("com.codename1.ai.vision.Pose", splitMembers("")); index.put("com.codename1.ai.vision.Pose.Landmark", splitMembers("")); index.put("com.codename1.ai.vision.PoseDetector", splitMembers("")); + index.put("com.codename1.ai.vision.PoseLandmarks", splitMembers("")); index.put("com.codename1.ai.vision.SegmentationMask", splitMembers("")); index.put("com.codename1.ai.vision.SelfieSegmenter", splitMembers("")); index.put("com.codename1.ai.vision.TextRecognitionResult", splitMembers("")); index.put("com.codename1.ai.vision.TextRecognitionResult.TextBlock", splitMembers("")); index.put("com.codename1.ai.vision.TextRecognizer", splitMembers("")); + index.put("com.codename1.ai.vision.TextScript", splitMembers("")); index.put("com.codename1.ai.vision.VisionAnalyzer", splitMembers("")); index.put("com.codename1.ai.vision.VisionBackend", splitMembers("")); index.put("com.codename1.ai.vision.VisionBackends", splitMembers("")); + index.put("com.codename1.ai.vision.VisionCameraView", splitMembers("")); index.put("com.codename1.ai.vision.VisionException", splitMembers("")); index.put("com.codename1.ai.vision.VisionFeature", splitMembers("")); index.put("com.codename1.ai.vision.VisionImage", splitMembers("")); @@ -2200,16 +2319,17 @@ private static void fillMethodIndex1(Map index) { index.put("com.codename1.analytics.ConsentMode", splitMembers("")); index.put("com.codename1.analytics.FirebaseAnalyticsProvider", splitMembers("")); index.put("com.codename1.analytics.FirebaseAnalyticsProvider.Bridge", splitMembers("")); + } + + private static void fillMethodIndex2(Map index) { index.put("com.codename1.analytics.GoogleAnalyticsProvider", splitMembers("")); index.put("com.codename1.analytics.LegacyAnalyticsProviderAdapter", splitMembers("")); index.put("com.codename1.analytics.LoggingAnalyticsProvider", splitMembers("")); index.put("com.codename1.analytics.MatomoAnalyticsProvider", splitMembers("")); + index.put("com.codename1.annotations.AppIntent", splitMembers("")); index.put("com.codename1.annotations.Async", splitMembers("")); index.put("com.codename1.annotations.Async.Execute", splitMembers("")); index.put("com.codename1.annotations.Async.Schedule", splitMembers("")); - } - - private static void fillMethodIndex2(Map index) { index.put("com.codename1.annotations.Bind", splitMembers("")); index.put("com.codename1.annotations.Bindable", splitMembers("")); index.put("com.codename1.annotations.Column", splitMembers("")); @@ -2219,9 +2339,17 @@ private static void fillMethodIndex2(Map index) { index.put("com.codename1.annotations.DisableNullChecksAndArrayBoundsChecks", splitMembers("")); index.put("com.codename1.annotations.Email", splitMembers("")); index.put("com.codename1.annotations.Entity", splitMembers("")); + index.put("com.codename1.annotations.EntityId", splitMembers("")); + index.put("com.codename1.annotations.EntityImage", splitMembers("")); + index.put("com.codename1.annotations.EntityQuery", splitMembers("")); + index.put("com.codename1.annotations.EntityQuery.Kind", splitMembers("")); + index.put("com.codename1.annotations.EntitySubtitle", splitMembers("")); + index.put("com.codename1.annotations.EntityTitle", splitMembers("")); index.put("com.codename1.annotations.ExistIn", splitMembers("")); index.put("com.codename1.annotations.Fused", splitMembers("")); index.put("com.codename1.annotations.Id", splitMembers("")); + index.put("com.codename1.annotations.IntentEntity", splitMembers("")); + index.put("com.codename1.annotations.IntentParam", splitMembers("")); index.put("com.codename1.annotations.JsonIgnore", splitMembers("")); index.put("com.codename1.annotations.JsonProperty", splitMembers("")); index.put("com.codename1.annotations.Length", splitMembers("")); @@ -2238,9 +2366,29 @@ private static void fillMethodIndex2(Map index) { index.put("com.codename1.annotations.XmlElement", splitMembers("")); index.put("com.codename1.annotations.XmlRoot", splitMembers("")); index.put("com.codename1.annotations.XmlTransient", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Android", splitMembers("")); + index.put("com.codename1.annotations.buildhints.AndroidThemeMode", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Build", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Desktop", splitMembers("")); + index.put("com.codename1.annotations.buildhints.DesktopTitleBar", splitMembers("")); + index.put("com.codename1.annotations.buildhints.HardenControlFlow", splitMembers("")); + index.put("com.codename1.annotations.buildhints.HardenLevel", splitMembers("")); + index.put("com.codename1.annotations.buildhints.HardenStrings", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Hardening", splitMembers("")); + index.put("com.codename1.annotations.buildhints.InstallLocation", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Ios", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosDependencyManager", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosPrivacy", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosProjectType", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosThemeMode", splitMembers("")); + index.put("com.codename1.annotations.buildhints.NativeThemeMode", splitMembers("")); + index.put("com.codename1.annotations.buildhints.OnDeviceDebug", splitMembers("")); index.put("com.codename1.annotations.graphql.GraphQLClient", splitMembers("")); index.put("com.codename1.annotations.graphql.Mutation", splitMembers("")); index.put("com.codename1.annotations.graphql.Query", splitMembers("")); + } + + private static void fillMethodIndex3(Map index) { index.put("com.codename1.annotations.graphql.Subscription", splitMembers("")); index.put("com.codename1.annotations.graphql.Var", splitMembers("")); index.put("com.codename1.annotations.grpc.GrpcClient", splitMembers("")); @@ -2274,9 +2422,6 @@ private static void fillMethodIndex2(Map index) { index.put("com.codename1.ar.ARHitResult.Type", splitMembers("")); index.put("com.codename1.ar.ARImageAnchor", splitMembers("")); index.put("com.codename1.ar.ARLightEstimate", splitMembers("")); - } - - private static void fillMethodIndex3(Map index) { index.put("com.codename1.ar.ARModel", splitMembers("")); index.put("com.codename1.ar.ARNode", splitMembers("")); index.put("com.codename1.ar.ARPlane", splitMembers("")); @@ -2308,6 +2453,9 @@ private static void fillMethodIndex3(Map index) { index.put("com.codename1.binding.Binding", splitMembers("")); index.put("com.codename1.binding.NotifiableBinding", splitMembers("")); index.put("com.codename1.bluetooth.AdapterState", splitMembers("")); + } + + private static void fillMethodIndex4(Map index) { index.put("com.codename1.bluetooth.AdapterStateListener", splitMembers("")); index.put("com.codename1.bluetooth.Bluetooth", splitMembers("")); index.put("com.codename1.bluetooth.BluetoothDevice", splitMembers("")); @@ -2341,9 +2489,6 @@ private static void fillMethodIndex3(Map index) { index.put("com.codename1.bluetooth.le.L2capServer", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanFilter", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanListener", splitMembers("")); - } - - private static void fillMethodIndex4(Map index) { index.put("com.codename1.bluetooth.le.ScanMode", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanResult", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanSettings", splitMembers("")); @@ -2375,6 +2520,9 @@ private static void fillMethodIndex4(Map index) { index.put("com.codename1.calendar.CalendarCache", splitMembers("")); index.put("com.codename1.calendar.CalendarCapabilities", splitMembers("")); index.put("com.codename1.calendar.CalendarCapability", splitMembers("")); + } + + private static void fillMethodIndex5(Map index) { index.put("com.codename1.calendar.CalendarChange", splitMembers("")); index.put("com.codename1.calendar.CalendarChange.ChangeType", splitMembers("")); index.put("com.codename1.calendar.CalendarChange.EntityType", splitMembers("")); @@ -2408,9 +2556,6 @@ private static void fillMethodIndex4(Map index) { index.put("com.codename1.calendar.CalendarTokenProvider", splitMembers("")); index.put("com.codename1.calendar.DefaultCalendarHttpTransport", splitMembers("")); index.put("com.codename1.calendar.FreeBusyInterval", splitMembers("")); - } - - private static void fillMethodIndex5(Map index) { index.put("com.codename1.calendar.GoogleCalendarSource", splitMembers("")); index.put("com.codename1.calendar.ICalendarCodec", splitMembers("")); index.put("com.codename1.calendar.LocalCalendarSource", splitMembers("")); @@ -2442,6 +2587,9 @@ private static void fillMethodIndex5(Map index) { index.put("com.codename1.car.CarActionListener", splitMembers("")); index.put("com.codename1.car.CarActionStrip", splitMembers("")); index.put("com.codename1.car.CarApplication", splitMembers("")); + } + + private static void fillMethodIndex6(Map index) { index.put("com.codename1.car.CarColor", splitMembers("")); index.put("com.codename1.car.CarConnectionListener", splitMembers("")); index.put("com.codename1.car.CarContext", splitMembers("")); @@ -2475,9 +2623,6 @@ private static void fillMethodIndex5(Map index) { index.put("com.codename1.charts.models.Point", splitMembers("")); index.put("com.codename1.charts.models.RangeCategorySeries", splitMembers("")); index.put("com.codename1.charts.models.SeriesSelection", splitMembers("")); - } - - private static void fillMethodIndex6(Map index) { index.put("com.codename1.charts.models.TimeSeries", splitMembers("")); index.put("com.codename1.charts.models.XYMultipleSeriesDataset", splitMembers("")); index.put("com.codename1.charts.models.XYSeries", splitMembers("")); @@ -2509,6 +2654,9 @@ private static void fillMethodIndex6(Map index) { index.put("com.codename1.charts.views.CubicLineChart", splitMembers("")); index.put("com.codename1.charts.views.DialChart", splitMembers("")); index.put("com.codename1.charts.views.DoughnutChart", splitMembers("")); + } + + private static void fillMethodIndex7(Map index) { index.put("com.codename1.charts.views.LineChart", splitMembers("")); index.put("com.codename1.charts.views.PieChart", splitMembers("")); index.put("com.codename1.charts.views.PieMapper", splitMembers("")); @@ -2542,9 +2690,6 @@ private static void fillMethodIndex6(Map index) { index.put("com.codename1.components.FileTreeModel", splitMembers("addExtensionFilter(String)getChildren(Object)isLeaf(Object)")); index.put("com.codename1.components.FloatingActionButton", splitMembers("accessibilityChanged()accessibilityChanged(int)addActionListener(ActionListener)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindFabToContainer(Component)bindFabToContainer(Component, int, int)bindProperty(String, BindTarget)bindStateTo(Button)blocksSideSwipe()clearClientProperties()contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)createSubFAB(char, String)drop(Component, int, int)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getActionListeners()getAlignment()getAllStyles()getAnimationManager()getBadgeStyleComponent()getBadgeText()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getCommand()getComponentForm()getComponentState()getCursor()getDirtyRegion()getDisabledIcon()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getFloatingActionTextUIID()getFontIcon()getFontIconSize()getGap()getHeight()getIcon()getIconFont()getIconFromState()getIconStyleComponent()getIconUIID()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getListeners()getMask()getMaskName()getMaskedIcon()getMaterialIcon()getMaterialIconSize()getMaxAutoSize()getMinAutoSize()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedIcon()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getReleaseRadius()getRolloverIcon()getRolloverPressedIcon()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getShiftMillimeters()getShiftMillimetersF()getShiftText()getSideGap()getState()getStringWidth(Font)getStyle()getTabIndex()getTensileLength()getText()getTextPosition()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVerticalAlignment()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()isAlwaysTensile()isAutoRelease()isAutoSizeMode()isBlockLead()isCapsText()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isEndsWith3Points()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isLegacyRenderer()isOpaque()isOppositeSide()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSelected()isShouldLocalize()isShowEvenIfBlank()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTextSelectionEnabled()isTickerEnabled()isTickerRunning()isToggle()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])pressed()putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)released()released(int, int)remove()removeActionListener(ActionListener)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlignment(int)setAlwaysTensile(boolean)setAutoRelease(boolean)setAutoSizeMode(boolean)setBadgeText(String)setBadgeUIID(String)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCapsText(boolean)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCommand(Command)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledIcon(Image)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setEndsWith3Points(boolean)setFlatten(boolean)setFloatingActionTextUIID(String)setFocus(boolean)setFocusable(boolean)setFontIcon(char)setFontIcon(Font, char)setFontIcon(Font, char, float)setGap(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIcon(Image)setIconUIID(String)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLegacyRenderer(boolean)setMask(Object)setMaskName(String)setMaterialIcon(char)setMaterialIcon(char, float)setMaxAutoSize(float)setMinAutoSize(float)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedIcon(Image)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setReleaseRadius(int)setReleased()setRippleEffect(boolean)setRolloverIcon(Image)setRolloverPressedIcon(Image)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShiftMillimeters(float)setShiftMillimeters(int)setShiftText(int)setShouldCalcPreferredSize(boolean)setShouldLocalize(boolean)setShowEvenIfBlank(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextPosition(int)setTextSelectionEnabled(boolean)setTickerEnabled(boolean)setToggle(boolean)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalAlignment(int)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)shouldTickerStart()startEditingAsync()startTicker()startTicker(long, boolean)stopEditing(Runnable)stopTicker()stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbind()unbindProperty(String, BindTarget)unbindStateFrom(Button)visibleBoundsContains(int, int)createBadge(String)createFAB(char)createFAB(char, String)getIconDefaultSize()isAutoSizing()setAutoSizing(boolean)setIconDefaultSize(float)")); index.put("com.codename1.components.FloatingHint", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)findDropTargetAt(int, int)findFirstFocusable()flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)")); - } - - private static void fillMethodIndex7(Map index) { index.put("com.codename1.components.ImageViewer", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)deinitialize()drop(Component, int, int)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getCroppedImage(int)getCroppedImage(int, int, int)getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getImage()getImageList()getImageX()getImageY()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getSwipePlaceholder()getSwipeThreshold()getTabIndex()getTensileLength()getTextSelectionSupport()getThumbnailBarHeight()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()getZoom()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()initComponent()isAllowScaleDown()isAlwaysTensile()isAnimatedZoom()isBlockLead()isCellRenderer()isChildOf(Container)isCycleLeft()isCycleRight()isDraggable()isDropTarget()isEagerLock()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isNavigationArrowsVisible()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isThumbnailsVisible()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAllowScaleDown(boolean)setAlwaysTensile(boolean)setAnimateZoom(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setCycleLeft(boolean)setCycleRight(boolean)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEagerLock(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setImage(Image)setImageInitialPosition(int)setImageList(ListModel)setImageNoReposition(Image)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setName(String)setNavigationArrowsVisible(boolean)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setSwipePlaceholder(Image)setSwipeThreshold(float)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setThumbnailBarHeight(float)setThumbnailsVisible(boolean)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)setZoom(float)setZoom(float, float, float)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); index.put("com.codename1.components.InfiniteProgress", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animate(boolean)announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)drop(Component, int, int)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAngleIncrease()getAnimation()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getMaterialDesignColor()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTickCount()getTintColor()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isMaterialDesignMode()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setAngleIncrease(int)setAnimation(Image)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setMaterialDesignColor(int)setMaterialDesignMode(boolean)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTickCount(int)setTintColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)showInfiniteBlocking()showInifiniteBlocking()startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)getDefaultMaterialDesignColor()isDefaultMaterialDesignMode()setDefaultMaterialDesignColor(int)setDefaultMaterialDesignMode(boolean)")); index.put("com.codename1.components.InfiniteScrollAdapter", splitMembers("addMoreComponents(Component[], boolean)continueFetching()getComponentLimit()getInfiniteProgress()setComponentLimit(int)addMoreComponents(Container, Component[], boolean)continueFetching(Container)createInfiniteScroll(Container, Runnable)createInfiniteScroll(Container, Runnable, boolean)")); @@ -2576,13 +2721,19 @@ private static void fillMethodIndex7(Map index) { index.put("com.codename1.components.ToastBar", splitMembers("createStatus()getDefaultMessageUIID()getDefaultUIID()getPosition()setDefaultMessageUIID(String)setDefaultUIID(String)setPosition(int)setVisible(boolean)useFormLayeredPane(boolean)getDefaultMessageTimeout()getInstance()setDefaultMessageTimeout(int)showConnectionProgress(String, ConnectionRequest, SuccessCallback, FailureCallback)showErrorMessage(String)showErrorMessage(String, int)showInfoMessage(String)showMessage(String, char)showMessage(String, char, int)showMessage(String, char, ActionListener)showMessage(String, char, int, ActionListener)")); index.put("com.codename1.components.WebBrowser", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)destroy()drop(Component, int, int)findDropTargetAt(int, int)findFirstFocusable()flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getBrowserNavigationCallback()getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getInternal()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getPage()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTitle()getTooltip()getUIID()getUIManager()getURL()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)onError(String, int)onLoad(String)onStart(String)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)reload()remove()removeAll()removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setBrowserNavigationCallback(BrowserNavigationCallback)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPage(String, String)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setURL(String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stop()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)createDataURI(byte[], String)")); index.put("com.codename1.contacts.Address", splitMembers("")); + } + + private static void fillMethodIndex8(Map index) { index.put("com.codename1.contacts.Contact", splitMembers("")); index.put("com.codename1.contacts.ContactsManager", splitMembers("")); index.put("com.codename1.contacts.ContactsModel", splitMembers("")); index.put("com.codename1.crash.CrashProtection", splitMembers("")); index.put("com.codename1.crash.PiiScrubber", splitMembers("")); index.put("com.codename1.db.Cursor", splitMembers("")); + index.put("com.codename1.db.CursorExt", splitMembers("")); index.put("com.codename1.db.Database", splitMembers("")); + index.put("com.codename1.db.DatabaseConfig", splitMembers("")); + index.put("com.codename1.db.DatabaseEncryptionException", splitMembers("")); index.put("com.codename1.db.Row", splitMembers("")); index.put("com.codename1.db.RowExt", splitMembers("")); index.put("com.codename1.db.ThreadSafeDatabase", splitMembers("")); @@ -2609,9 +2760,6 @@ private static void fillMethodIndex7(Map index) { index.put("com.codename1.gaming.VirtualButton", splitMembers("")); index.put("com.codename1.gaming.VirtualJoystick", splitMembers("")); index.put("com.codename1.gaming.VoiceListener", splitMembers("")); - } - - private static void fillMethodIndex8(Map index) { index.put("com.codename1.gaming.level.AssetCatalog", splitMembers("")); index.put("com.codename1.gaming.level.AssetDef", splitMembers("")); index.put("com.codename1.gaming.level.AssetDef.Kind", splitMembers("")); @@ -2640,6 +2788,9 @@ private static void fillMethodIndex8(Map index) { index.put("com.codename1.gaming.level.TileLayer", splitMembers("")); index.put("com.codename1.gaming.physics.BodyType", splitMembers("")); index.put("com.codename1.gaming.physics.ContactListener", splitMembers("")); + } + + private static void fillMethodIndex9(Map index) { index.put("com.codename1.gaming.physics.PhysicsBody", splitMembers("")); index.put("com.codename1.gaming.physics.PhysicsContact", splitMembers("")); index.put("com.codename1.gaming.physics.PhysicsJoint", splitMembers("")); @@ -2676,9 +2827,6 @@ private static void fillMethodIndex8(Map index) { index.put("com.codename1.gaming.physics.box2d.collision.TimeOfImpact.TOIOutput", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.TimeOfImpact.TOIOutputState", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.WorldManifold", splitMembers("")); - } - - private static void fillMethodIndex9(Map index) { index.put("com.codename1.gaming.physics.box2d.collision.broadphase.BroadPhase", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.broadphase.BroadPhaseStrategy", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.broadphase.DynamicTree", splitMembers("")); @@ -2707,6 +2855,9 @@ private static void fillMethodIndex9(Map index) { index.put("com.codename1.gaming.physics.box2d.common.Vec3", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.Body", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.BodyDef", splitMembers("")); + } + + private static void fillMethodIndex10(Map index) { index.put("com.codename1.gaming.physics.box2d.dynamics.BodyType", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.ContactManager", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.Filter", splitMembers("")); @@ -2743,9 +2894,6 @@ private static void fillMethodIndex9(Map index) { index.put("com.codename1.gaming.physics.box2d.dynamics.joints.FrictionJoint", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.FrictionJointDef", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.GearJoint", splitMembers("")); - } - - private static void fillMethodIndex10(Map index) { index.put("com.codename1.gaming.physics.box2d.dynamics.joints.GearJointDef", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.Jacobian", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.Joint", splitMembers("")); @@ -2774,6 +2922,9 @@ private static void fillMethodIndex10(Map index) { index.put("com.codename1.gaming.physics.box2d.pooling.arrays.IntArray", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.arrays.Vec2Array", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.normal.CircleStack", splitMembers("")); + } + + private static void fillMethodIndex11(Map index) { index.put("com.codename1.gaming.physics.box2d.pooling.normal.DefaultWorldPool", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.normal.MutableStack", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.normal.OrderedStack", splitMembers("")); @@ -2810,9 +2961,6 @@ private static void fillMethodIndex10(Map index) { index.put("com.codename1.health.AggregateResult", splitMembers("")); index.put("com.codename1.health.BloodPressureSample", splitMembers("")); index.put("com.codename1.health.CategorySample", splitMembers("")); - } - - private static void fillMethodIndex11(Map index) { index.put("com.codename1.health.Health", splitMembers("")); index.put("com.codename1.health.HealthAccess", splitMembers("")); index.put("com.codename1.health.HealthAggregationStyle", splitMembers("")); @@ -2841,6 +2989,9 @@ private static void fillMethodIndex11(Map index) { index.put("com.codename1.health.HealthUnitDimension", splitMembers("")); index.put("com.codename1.health.HealthWriteResult", splitMembers("")); index.put("com.codename1.health.QuantitySample", splitMembers("")); + } + + private static void fillMethodIndex12(Map index) { index.put("com.codename1.health.RecordingMethod", splitMembers("")); index.put("com.codename1.health.SamplePage", splitMembers("")); index.put("com.codename1.health.SampleQuery", splitMembers("")); @@ -2877,9 +3028,6 @@ private static void fillMethodIndex11(Map index) { index.put("com.codename1.health.sensors.TemperatureMeasurement", splitMembers("")); index.put("com.codename1.health.sensors.WeightMeasurement", splitMembers("")); index.put("com.codename1.health.workout.WorkoutConfiguration", splitMembers("")); - } - - private static void fillMethodIndex12(Map index) { index.put("com.codename1.health.workout.WorkoutEvent", splitMembers("")); index.put("com.codename1.health.workout.WorkoutEvent.Kind", splitMembers("")); index.put("com.codename1.health.workout.WorkoutLocationType", splitMembers("")); @@ -2887,6 +3035,73 @@ private static void fillMethodIndex12(Map index) { index.put("com.codename1.health.workout.WorkoutSession", splitMembers("")); index.put("com.codename1.health.workout.WorkoutSessionListener", splitMembers("")); index.put("com.codename1.health.workout.WorkoutSessionState", splitMembers("")); + index.put("com.codename1.home.Accessory", splitMembers("")); + index.put("com.codename1.home.AccessoryCategory", splitMembers("")); + index.put("com.codename1.home.AccessoryService", splitMembers("")); + index.put("com.codename1.home.AirQualityLevel", splitMembers("")); + index.put("com.codename1.home.AlarmState", splitMembers("")); + index.put("com.codename1.home.ChargingState", splitMembers("")); + index.put("com.codename1.home.DoorState", splitMembers("")); + index.put("com.codename1.home.FanMode", splitMembers("")); + index.put("com.codename1.home.HeatingCoolingMode", splitMembers("")); + index.put("com.codename1.home.HomeAuthorizationStatus", splitMembers("")); + index.put("com.codename1.home.HomeAvailability", splitMembers("")); + index.put("com.codename1.home.HomeBackend", splitMembers("")); + index.put("com.codename1.home.HomeChangeListener", splitMembers("")); + index.put("com.codename1.home.HomeConfigurationException", splitMembers("")); + index.put("com.codename1.home.HomeError", splitMembers("")); + index.put("com.codename1.home.HomeException", splitMembers("")); + index.put("com.codename1.home.HomeRoom", splitMembers("")); + index.put("com.codename1.home.HomeStructure", splitMembers("")); + index.put("com.codename1.home.HomeStructureEvent", splitMembers("")); + index.put("com.codename1.home.HomeStructureListener", splitMembers("")); + index.put("com.codename1.home.HomeZone", splitMembers("")); + } + + private static void fillMethodIndex13(Map index) { + index.put("com.codename1.home.LockState", splitMembers("")); + index.put("com.codename1.home.PositionState", splitMembers("")); + index.put("com.codename1.home.Scene", splitMembers("")); + index.put("com.codename1.home.SceneAction", splitMembers("")); + index.put("com.codename1.home.SceneType", splitMembers("")); + index.put("com.codename1.home.ServiceType", splitMembers("")); + index.put("com.codename1.home.SmartHome", splitMembers("")); + index.put("com.codename1.home.StructureChangeKind", splitMembers("")); + index.put("com.codename1.home.SubscriptionRequest", splitMembers("")); + index.put("com.codename1.home.Trait", splitMembers("")); + index.put("com.codename1.home.TraitChangeBatch", splitMembers("")); + index.put("com.codename1.home.TraitConstraint", splitMembers("")); + index.put("com.codename1.home.TraitReadRequest", splitMembers("")); + index.put("com.codename1.home.TraitReading", splitMembers("")); + index.put("com.codename1.home.TraitSubscription", splitMembers("")); + index.put("com.codename1.home.TraitUnit", splitMembers("")); + index.put("com.codename1.home.TraitUnitDimension", splitMembers("")); + index.put("com.codename1.home.TraitValue", splitMembers("")); + index.put("com.codename1.home.TraitValueKind", splitMembers("")); + index.put("com.codename1.home.TraitWrite", splitMembers("")); + index.put("com.codename1.home.TraitWriteResult", splitMembers("")); + index.put("com.codename1.home.commissioning.Commissioner", splitMembers("")); + index.put("com.codename1.home.commissioning.CommissioningRequest", splitMembers("")); + index.put("com.codename1.home.commissioning.CommissioningResult", splitMembers("")); + index.put("com.codename1.home.commissioning.CommissioningStyle", splitMembers("")); + index.put("com.codename1.home.commissioning.SetupPayload", splitMembers("")); + index.put("com.codename1.home.spi.HomeBridge", splitMembers("")); + index.put("com.codename1.intents.AppEntity", splitMembers("")); + index.put("com.codename1.intents.DynamicIntent", splitMembers("")); + index.put("com.codename1.intents.EntitySelectionHandler", splitMembers("")); + index.put("com.codename1.intents.Exposure", splitMembers("")); + index.put("com.codename1.intents.IntentCompletion", splitMembers("")); + index.put("com.codename1.intents.IntentContext", splitMembers("")); + index.put("com.codename1.intents.IntentDates", splitMembers("")); + index.put("com.codename1.intents.IntentDeclaration", splitMembers("")); + index.put("com.codename1.intents.IntentDispatcher", splitMembers("")); + index.put("com.codename1.intents.IntentParameterInfo", splitMembers("")); + index.put("com.codename1.intents.IntentParameterType", splitMembers("")); + index.put("com.codename1.intents.IntentResult", splitMembers("")); + index.put("com.codename1.intents.IntentSerializer", splitMembers("")); + index.put("com.codename1.intents.IntentSource", splitMembers("")); + index.put("com.codename1.intents.Intents", splitMembers("")); + index.put("com.codename1.intents.spi.IntentBridge", splitMembers("")); index.put("com.codename1.io.AccessToken", splitMembers("")); index.put("com.codename1.io.BufferedInputStream", splitMembers("")); index.put("com.codename1.io.BufferedOutputStream", splitMembers("")); @@ -2908,6 +3123,9 @@ private static void fillMethodIndex12(Map index) { index.put("com.codename1.io.JSONParser", splitMembers("")); index.put("com.codename1.io.JSONParser.RawJson", splitMembers("")); index.put("com.codename1.io.JSONWriter", splitMembers("")); + } + + private static void fillMethodIndex14(Map index) { index.put("com.codename1.io.JSONWriter.ArrayBuilder", splitMembers("")); index.put("com.codename1.io.JSONWriter.ObjectBuilder", splitMembers("")); index.put("com.codename1.io.Log", splitMembers("")); @@ -2944,9 +3162,6 @@ private static void fillMethodIndex12(Map index) { index.put("com.codename1.io.bonjour.BonjourService", splitMembers("")); index.put("com.codename1.io.bonjour.BonjourServiceListener", splitMembers("")); index.put("com.codename1.io.graphql.GraphQL", splitMembers("")); - } - - private static void fillMethodIndex13(Map index) { index.put("com.codename1.io.graphql.GraphQLClients", splitMembers("")); index.put("com.codename1.io.graphql.GraphQLClients.Factory", splitMembers("")); index.put("com.codename1.io.graphql.GraphQLError", splitMembers("")); @@ -2975,6 +3190,9 @@ private static void fillMethodIndex13(Map index) { index.put("com.codename1.io.gzip.GZIPHeader", splitMembers("")); index.put("com.codename1.io.gzip.GZIPInputStream", splitMembers("")); index.put("com.codename1.io.gzip.GZIPOutputStream", splitMembers("")); + } + + private static void fillMethodIndex15(Map index) { index.put("com.codename1.io.gzip.Inflater", splitMembers("")); index.put("com.codename1.io.gzip.InflaterInputStream", splitMembers("")); index.put("com.codename1.io.gzip.JZlib", splitMembers("")); @@ -3011,9 +3229,6 @@ private static void fillMethodIndex13(Map index) { index.put("com.codename1.io.usb.UsbDeviceListener", splitMembers("")); index.put("com.codename1.io.usb.UsbPlatform", splitMembers("")); index.put("com.codename1.io.webauthn.PublicKeyCredential", splitMembers("")); - } - - private static void fillMethodIndex14(Map index) { index.put("com.codename1.io.webauthn.PublicKeyCredentialCreationOptions", splitMembers("")); index.put("com.codename1.io.webauthn.PublicKeyCredentialCreationOptions.Builder", splitMembers("")); index.put("com.codename1.io.webauthn.PublicKeyCredentialRequestOptions", splitMembers("")); @@ -3042,6 +3257,9 @@ private static void fillMethodIndex14(Map index) { index.put("com.codename1.l10n.ParseException", splitMembers("")); index.put("com.codename1.l10n.SimpleDateFormat", splitMembers("")); index.put("com.codename1.location.Geofence", splitMembers("")); + } + + private static void fillMethodIndex16(Map index) { index.put("com.codename1.location.GeofenceListener", splitMembers("")); index.put("com.codename1.location.GeofenceManager", splitMembers("")); index.put("com.codename1.location.GeofenceManager.Listener", splitMembers("")); @@ -3078,9 +3296,6 @@ private static void fillMethodIndex14(Map index) { index.put("com.codename1.maps.layers.AbstractLayer", splitMembers("")); index.put("com.codename1.maps.layers.ArrowLinesLayer", splitMembers("")); index.put("com.codename1.maps.layers.Layer", splitMembers("")); - } - - private static void fillMethodIndex15(Map index) { index.put("com.codename1.maps.layers.LinesLayer", splitMembers("")); index.put("com.codename1.maps.layers.PointLayer", splitMembers("")); index.put("com.codename1.maps.layers.PointsLayer", splitMembers("")); @@ -3109,6 +3324,9 @@ private static void fillMethodIndex15(Map index) { index.put("com.codename1.maps.vector.StyleLayer", splitMembers("")); index.put("com.codename1.maps.vector.TileCallback", splitMembers("")); index.put("com.codename1.maps.vector.TileSource", splitMembers("")); + } + + private static void fillMethodIndex17(Map index) { index.put("com.codename1.maps.vector.VectorFeature", splitMembers("")); index.put("com.codename1.maps.vector.VectorLayer", splitMembers("")); index.put("com.codename1.maps.vector.VectorMapEngine", splitMembers("")); @@ -3145,9 +3363,6 @@ private static void fillMethodIndex15(Map index) { index.put("com.codename1.media.SpeechRecognizer", splitMembers("")); index.put("com.codename1.media.TextToSpeech", splitMembers("")); index.put("com.codename1.media.TimedRecognitionCallback", splitMembers("")); - } - - private static void fillMethodIndex16(Map index) { index.put("com.codename1.media.Transcriber", splitMembers("")); index.put("com.codename1.media.TranscriptionRequest", splitMembers("")); index.put("com.codename1.media.TranscriptionResult", splitMembers("")); @@ -3176,6 +3391,9 @@ private static void fillMethodIndex16(Map index) { index.put("com.codename1.nfc.NfcError", splitMembers("")); index.put("com.codename1.nfc.NfcException", splitMembers("")); index.put("com.codename1.nfc.NfcF", splitMembers("")); + } + + private static void fillMethodIndex18(Map index) { index.put("com.codename1.nfc.NfcListener", splitMembers("")); index.put("com.codename1.nfc.NfcReadOptions", splitMembers("")); index.put("com.codename1.nfc.NfcV", splitMembers("")); @@ -3212,9 +3430,6 @@ private static void fillMethodIndex16(Map index) { index.put("com.codename1.plugin.event.OpenGalleryEvent", splitMembers("")); index.put("com.codename1.plugin.event.PluginEvent", splitMembers("")); index.put("com.codename1.printing.PrintResult", splitMembers("")); - } - - private static void fillMethodIndex17(Map index) { index.put("com.codename1.printing.PrintResultListener", splitMembers("")); index.put("com.codename1.printing.Printer", splitMembers("")); index.put("com.codename1.processing.Result", splitMembers("")); @@ -3243,6 +3458,9 @@ private static void fillMethodIndex17(Map index) { index.put("com.codename1.properties.UiBinding", splitMembers("")); index.put("com.codename1.properties.UiBinding.BooleanConverter", splitMembers("")); index.put("com.codename1.properties.UiBinding.BoundTableModel", splitMembers("")); + } + + private static void fillMethodIndex19(Map index) { index.put("com.codename1.properties.UiBinding.CheckBoxRadioSelectionAdapter", splitMembers("")); index.put("com.codename1.properties.UiBinding.ComponentAdapter", splitMembers("")); index.put("com.codename1.properties.UiBinding.DateConverter", splitMembers("")); @@ -3279,9 +3497,6 @@ private static void fillMethodIndex17(Map index) { index.put("com.codename1.router.PopGuard", splitMembers("")); index.put("com.codename1.router.PopReason", splitMembers("")); index.put("com.codename1.router.RouteDispatcher", splitMembers("")); - } - - private static void fillMethodIndex18(Map index) { index.put("com.codename1.security.AuthenticationOptions", splitMembers("")); index.put("com.codename1.security.Base32", splitMembers("")); index.put("com.codename1.security.BiometricError", splitMembers("")); @@ -3305,9 +3520,14 @@ private static void fillMethodIndex18(Map index) { index.put("com.codename1.security.SecureRandom", splitMembers("")); index.put("com.codename1.security.SecureStorage", splitMembers("")); index.put("com.codename1.security.Signature", splitMembers("")); + index.put("com.codename1.security.TapjackingPolicy", splitMembers("")); + index.put("com.codename1.security.hardening.Hardening", splitMembers("")); index.put("com.codename1.security.shield.AppShield", splitMembers("")); index.put("com.codename1.security.shield.FailureMode", splitMembers("")); index.put("com.codename1.security.shield.HostPolicy", splitMembers("")); + } + + private static void fillMethodIndex20(Map index) { index.put("com.codename1.security.shield.PinSet", splitMembers("")); index.put("com.codename1.security.shield.ShieldConfig", splitMembers("")); index.put("com.codename1.security.shield.ShieldException", splitMembers("")); @@ -3346,9 +3566,6 @@ private static void fillMethodIndex18(Map index) { index.put("com.codename1.social.Login", splitMembers("")); index.put("com.codename1.social.LoginCallback", splitMembers("")); index.put("com.codename1.social.MicrosoftConnect", splitMembers("")); - } - - private static void fillMethodIndex19(Map index) { index.put("com.codename1.surfaces.LiveActivity", splitMembers("")); index.put("com.codename1.surfaces.LiveActivityDescriptor", splitMembers("")); index.put("com.codename1.surfaces.SurfaceActionEvent", splitMembers("")); @@ -3375,6 +3592,9 @@ private static void fillMethodIndex19(Map index) { index.put("com.codename1.surfaces.WidgetKind", splitMembers("")); index.put("com.codename1.surfaces.WidgetSize", splitMembers("")); index.put("com.codename1.surfaces.WidgetTimeline", splitMembers("")); + } + + private static void fillMethodIndex21(Map index) { index.put("com.codename1.surfaces.WidgetTimeline.Entry", splitMembers("")); index.put("com.codename1.surfaces.spi.SurfaceBridge", splitMembers("")); index.put("com.codename1.system.CrashReport", splitMembers("")); @@ -3413,12 +3633,9 @@ private static void fillMethodIndex19(Map index) { index.put("com.codename1.ui.CheckBox", splitMembers("accessibilityChanged()accessibilityChanged(int)addActionListener(ActionListener)addChangeListener(ActionListener)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)bindStateTo(Button)blocksSideSwipe()clearClientProperties()contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)drop(Component, int, int)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getActionListeners()getAlignment()getAllStyles()getAnimationManager()getBadgeStyleComponent()getBadgeText()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getCommand()getComponentForm()getComponentState()getCursor()getDirtyRegion()getDisabledIcon()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getFontIcon()getFontIconSize()getGap()getHeight()getIcon()getIconFont()getIconFromState()getIconStyleComponent()getIconUIID()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getListeners()getMask()getMaskName()getMaskedIcon()getMaterialIcon()getMaterialIconSize()getMaxAutoSize()getMinAutoSize()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedIcon()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getReleaseRadius()getRolloverIcon()getRolloverPressedIcon()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getShiftMillimeters()getShiftMillimetersF()getShiftText()getSideGap()getState()getStringWidth(Font)getStyle()getTabIndex()getTensileLength()getText()getTextPosition()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVerticalAlignment()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()isAlwaysTensile()isAutoRelease()isAutoSizeMode()isBlockLead()isCapsText()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isEndsWith3Points()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isLegacyRenderer()isOpaque()isOppositeSide()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSelected()isShouldLocalize()isShowEvenIfBlank()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTextSelectionEnabled()isTickerEnabled()isTickerRunning()isToggle()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])pressed()putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)released()released(int, int)remove()removeActionListener(ActionListener)removeChangeListeners(ActionListener)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlignment(int)setAlwaysTensile(boolean)setAutoRelease(boolean)setAutoSizeMode(boolean)setBadgeText(String)setBadgeUIID(String)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCapsText(boolean)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCommand(Command)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledIcon(Image)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setEndsWith3Points(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontIcon(char)setFontIcon(Font, char)setFontIcon(Font, char, float)setGap(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIcon(Image)setIconUIID(String)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLegacyRenderer(boolean)setMask(Object)setMaskName(String)setMaterialIcon(char)setMaterialIcon(char, float)setMaxAutoSize(float)setMinAutoSize(float)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOppositeSide(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedIcon(Image)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setReleaseRadius(int)setReleased()setRippleEffect(boolean)setRolloverIcon(Image)setRolloverPressedIcon(Image)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelected(boolean)setSelectedStyle(Style)setShiftMillimeters(float)setShiftMillimeters(int)setShiftText(int)setShouldCalcPreferredSize(boolean)setShouldLocalize(boolean)setShowEvenIfBlank(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextPosition(int)setTextSelectionEnabled(boolean)setTickerEnabled(boolean)setToggle(boolean)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalAlignment(int)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)shouldTickerStart()startEditingAsync()startTicker()startTicker(long, boolean)stopEditing(Runnable)stopTicker()stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)unbindStateFrom(Button)visibleBoundsContains(int, int)createToggle(Image)createToggle(String)createToggle(String, Image)")); index.put("com.codename1.ui.ClipboardContent", splitMembers("findPreferredMimeType(String[])getBytes(String)getData(String)getMimeTypes()getText(String)hasMimeType(String)setData(String, Object)")); index.put("com.codename1.ui.CodeCompletion", splitMembers("getDetail()getDisplayText()getInsertText()getType()setDetail(String)setType(String)")); - } - - private static void fillMethodIndex20(Map index) { index.put("com.codename1.ui.CodeCompletionProvider", splitMembers("getCompletions(CodeEditor, String, int, SuccessCallback)")); index.put("com.codename1.ui.CodeDiagnostic", splitMembers("getColumn()getEndColumn()getEndLine()getLine()getMessage()getSeverity()setSeverity(String)")); - index.put("com.codename1.ui.CodeEditor", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addChangeListener(ActionListener)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addReadyListener(ActionListener)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()blurEditor()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)editorChanged()findDropTargetAt(int, int)findFirstFocusable()fireEditorEvent(String, String)flushReplace()focusEditor()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getCompletionProvider()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getCursorPosition(SuccessCallback)getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLanguage()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTabSize()getTensileLength()getText(SuccessCallback)getTextSelectionSupport()getTheme()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()insertAtCursor(String)invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEditorReady()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isNativeEditor()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isReadOnly()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isShowLineNumbers()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTextInputSupported()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)onReady(Runnable)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeChangeListener(ActionListener)removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeReadyListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCompletionProvider(CodeCompletionProvider)setComponentState(Object)setCursor(int)setDiagnostics(List)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditable(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLanguage(String)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setReadOnly(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setShowLineNumbers(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTabSize(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTheme(String)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()startTextInput(TextInputClient, TextInputConfig)stopEditing(Runnable)stopTextInput(Object)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)updateTextInputState(Object, TextInputState)visibleBoundsContains(int, int)getRegisteredSyntaxHighlighter(String)registerSyntaxHighlighter(String, SyntaxHighlighter)")); + index.put("com.codename1.ui.CodeEditor", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addChangeListener(ActionListener)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addProtectedEditListener(ActionListener)addPullToRefresh(Runnable)addReadyListener(ActionListener)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()blurEditor()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)editorChanged()findDropTargetAt(int, int)findFirstFocusable()fireEditorEvent(String, String)flushReplace()focusEditor()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getCompletionProvider()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getCursorPosition(SuccessCallback)getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLanguage()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTabSize()getTensileLength()getText(SuccessCallback)getTextSelectionSupport()getTheme()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()insertAtCursor(String)invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEditorReady()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isNativeEditor()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isReadOnly()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isShowLineNumbers()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTextInputSupported()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)onReady(Runnable)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeChangeListener(ActionListener)removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeProtectedEditListener(ActionListener)removeReadyListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCompletionProvider(CodeCompletionProvider)setComponentState(Object)setCursor(int)setCursorPosition(int)setDiagnostics(List)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditable(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLanguage(String)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setProtectedRegionMarkers(String, String)setPullToRefresh(Runnable)setRTL(boolean)setReadOnly(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setShowLineNumbers(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTabSize(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTheme(String)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()startTextInput(TextInputClient, TextInputConfig)stopEditing(Runnable)stopTextInput(Object)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)updateTextInputState(Object, TextInputState)visibleBoundsContains(int, int)getRegisteredSyntaxHighlighter(String)registerSyntaxHighlighter(String, SyntaxHighlighter)")); index.put("com.codename1.ui.ComboBox", splitMembers("accessibilityChanged()accessibilityChanged(int)addActionListener(ActionListener)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addSelectionListener(SelectionListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)drop(Component, int, int)getAbsoluteX()getAbsoluteY()getAccessibilityItemBounds(int, Rectangle)getAccessibilityItemText(int)getAccessibilityNode()getAccessibilityText()getAccessibilityVisibleItemIndices()getActionListeners()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComboBoxImage()getComponentForm()getComponentState()getCurrentSelected()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getFixedSelection()getHeight()getHint()getHintIcon()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getItemGap()getLabelForComponent()getListSizeCalculationSampleCount()getListeners()getMaxElementHeight()getMinElementHeight()getModel()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOrientation()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPopupPlacement()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getRenderer()getRenderingPrototype()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedIndex()getSelectedItem()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()isActAsSpinnerDialog()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isCommandList()isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnoreFocusComponentWhenUnfocused()isIgnorePointerEvents()isIncludeSelectCancel()isLongPointerPressActionEnabled()isMutableRendererBackgrounds()isNumericKeyActions()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isShowingPopupDialog()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeActionListener(ActionListener)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeSelectionListener(SelectionListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)requestFocus()respondsToPointerEvents()scrollRectToVisible(Rectangle)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setActAsSpinnerDialog(boolean)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComboBoxImage(Image)setCommandList(boolean)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFireOnClick(boolean)setFixedSelection(int)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHint(String)setHint(String, Image)setHintIcon(Image)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnoreFocusComponentWhenUnfocused(boolean)setIgnorePointerEvents(boolean)setIncludeSelectCancel(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setInputOnFocus(boolean)setIsScrollVisible(boolean)setItemGap(int)setLabelForComponent(Label)setListCellRenderer(ListCellRenderer)setListSizeCalculationSampleCount(int)setLongPointerPressActionEnabled(boolean)setMaxElementHeight(int)setMinElementHeight(int)setModel(ListModel)setMutableRendererBackgrounds(boolean)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setNumericKeyActions(boolean)setOpaque(boolean)setOrientation(int)setOwner(Component)setPaintFocusBehindList(boolean)setPinchBlocksDragAndDrop(boolean)setPopupPlacement(int)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRenderer(ListCellRenderer)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollToSelected(boolean)setScrollVisible(boolean)setSelectCommandText(String)setSelectedIndex(int)setSelectedIndex(int, boolean)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)size()startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)isDefaultActAsSpinnerDialog()isDefaultIncludeSelectCancel()setDefaultActAsSpinnerDialog(boolean)setDefaultIncludeSelectCancel(boolean)")); index.put("com.codename1.ui.Command", splitMembers("actionPerformed(ActionEvent)equals(Object)getClientProperty(String)getCommandName()getDesktopMenu()getDesktopShortcutKeyChar()getDesktopShortcutModifiers()getDisabledIcon()getIcon()getIconFont()getIconGapMM()getId()getMaterialIcon()getMaterialIconSize()getPressedIcon()getRolloverIcon()hashCode()isDisposesDialog()isEnabled()putClientProperty(String, Object)setCommandName(String)setDesktopMenu(String)setDesktopShortcut(char)setDesktopShortcut(char, int)setDisabledIcon(Image)setDisposesDialog(boolean)setEnabled(boolean)setIcon(Image)setIconFont(Font)setIconGapMM(float)setMaterialIcon(char)setMaterialIconSize(float)setPressedIcon(Image)setRolloverIcon(Image)toString()create(String, Image, ActionListener)createMaterial(String, char, ActionListener)")); index.put("com.codename1.ui.CommonProgressAnimations", splitMembers("")); @@ -3437,11 +3654,14 @@ private static void fillMethodIndex20(Map index) { index.put("com.codename1.ui.Container", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)findDropTargetAt(int, int)findFirstFocusable()flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)encloseIn(Layout, Component[]...)encloseIn(Layout, Component, Object)")); index.put("com.codename1.ui.DevicePosture", splitMembers("getFoldBounds(Rectangle)getFoldOrientation()getHingeAngle()getPosture()isFoldable()isSeparating()isTableTop()getInstance()")); index.put("com.codename1.ui.Dialog", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addCommand(Command)addCommand(Command, int)addCommandListener(ActionListener)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addComponentAwaitingRelease(Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addGameKeyListener(int, ActionListener)addKeyListener(int, ActionListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addOrientationListener(ActionListener)addPasteListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addShowListener(ActionListener)addSizeChangedListener(ActionListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()checkPopGuard(PopReason)clearClientProperties()clearComponentsAwaitingRelease()configureCommands(Command[], boolean)contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)deregisterAnimated(Animation)dispatchCommand(Command, ActionEvent)dispatchPaste(ActionEvent)dispose()drop(Component, int, int)findCurrentlyEditingComponent()findDropTargetAt(int, int)findFirstFocusable()findNextFocusHorizontal(boolean)findNextFocusVertical(boolean)flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBackCommand()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBlurBackgroundRadius()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClearCommand()getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getCommand(int)getCommandCount()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getContentPane()getCurrentInputDevice()getCursor()getDefaultCommand()getDialogComponent()getDialogPosition()getDialogPreferredSize()getDialogStyle()getDialogType()getDialogUIID()getDirtyRegion()getDisabledStyle()getDragRegionStatus(int, int)getDragTransparency()getDraggedx()getDraggedy()getEditOnShow()getEditingDelegate()getFocused()getFormLayeredPane(Class, boolean)getGlassPane()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getInvisibleAreaUnderVKB()getLabelForComponent()getLayeredPane()getLayeredPane(Class, boolean)getLayeredPane(Class, int)getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getMenuBar()getMenuStyle()getName()getNativeOverlay()getNextComponent(Component)getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPopGuard()getPopupDirectionBiasPortrait()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPreviousComponent(Component)getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeArea()getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getSoftButton(int)getSoftButtonCount()getSourceCommand()getStyle()getTabIndex()getTabIterator(Component)getTensileLength()getTextSelection()getTextSelectionSupport()getTintColor()getTitle()getTitleArea()getTitleComponent()getTitleStyle()getToolbar()getTooltip()getTransitionInAnimator()getTransitionOutAnimator()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()grabAnimationLock()growOrShrink()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasMedia()invalidate()isAlwaysTensile()isAutoDispose()isBlockLead()isCellRenderer()isChildOf(Container)isCyclicFocus()isDisposeWhenPointerOutOfBounds()isDragRegion(int, int)isDraggable()isDropTarget()isEditable()isEditing()isEnableCursors()isEnabled()isFlatten()isFocusScrolling()isFocusable()isFormBottomPaddingEditingMode()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isInteractionDialogMode()isMinimizeOnBack()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollable()isScrollableX()isScrollableY()isSingleFocusMode()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTitleCentered()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackground(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)placeButtonCommands(Command[])pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)registerAnimated(Animation)releaseAnimationLock()remove()removeAll()removeAllCommands()removeAllShowListeners()removeCommand(Command)removeCommandListener(ActionListener)removeComponent(Component)removeComponentAwaitingRelease(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeGameKeyListener(int, ActionListener)removeKeyListener(int, ActionListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removeOrientationListener(ActionListener)removePasteListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeShowListener(ActionListener)removeSizeChangedListener(ActionListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAllowEnableLayoutOnPaint(boolean)setAlwaysTensile(boolean)setAutoDispose(boolean)setBackCommand(Command)setBackCommand(String, Image, ActionListener)setBgImage(Image)setBlockLead(boolean)setBlurBackgroundRadius(float)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setClearCommand(Command)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCurrentInputDevice(VirtualInputDevice)setCursor(int)setCyclicFocus(boolean)setDefaultCommand(Command)setDialogPosition(String)setDialogStyle(Style)setDialogType(int)setDialogUIID(String)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDisposeWhenPointerOutOfBounds(boolean)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditOnShow(TextArea)setEditingDelegate(Editable)setEnableCursors(boolean)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusScrolling(boolean)setFocusable(boolean)setFocused(Component)setFormBottomPaddingEditingMode(boolean)setGlassPane(Painter)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setInteractionDialogMode(boolean)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setMenuBar(MenuBar)setMenuCellRenderer(ListCellRenderer)setMenuTransitions(Transition, Transition)setMinimizeOnBack(boolean)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOverrideInvisibleAreaUnderVKB(int)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPopGuard(PopGuard)setPopupDirectionBiasPortrait(Boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPreviousForm(Form)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaChanged()setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setSourceCommand(Command)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTimeout(long)setTintColor(int)setTitle(String)setTitleCentered(boolean)setTitleComponent(Label)setTitleComponent(Label, Transition)setTitleStyle(Style)setToolBar(Toolbar)setToolbar(Toolbar)setTooltip(String)setTransitionInAnimator(Transition)setTransitionOutAnimator(Transition)setTransitions(Transition)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIIDByPopupPosition(boolean)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)show()show(int, int, int, int)show(int, int, int, int, boolean)show(int, int, int, int, boolean, boolean)showAtPosition(int, int, int, int, boolean)showBack()showDialog()showModeless()showPacked(String, boolean)showPopupDialog(Component)showPopupDialog(Rectangle)showStetched(String, boolean)showStretched(String, boolean)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)wasDisposedDueToOutOfBoundsTouch()wasDisposedDueToRotation()getDefaultBlurBackgroundRadius()getDefaultDialogPosition()getDefaultDialogType()isAutoAdjustDialogSize()isCommandsAsButtons()isDefaultDisposeWhenPointerOutOfBounds()isDefaultInteractionDialogMode()isDefaultTitleCentered()isDisableStaticDialogScrolling()setAutoAdjustDialogSize(boolean)setCommandsAsButtons(boolean)setDefaultBlurBackgroundRadius(float)setDefaultDialogPosition(String)setDefaultDialogType(int)setDefaultDisposeWhenPointerOutOfBounds(boolean)setDefaultInteractionDialogMode(boolean)setDefaultTitleCentered(boolean)setDisableStaticDialogScrolling(boolean)show(String, Component, Command[]...)show(String, String, Command[]...)show(String, String, String, String)show(String, Component, Command[], int, Image)show(String, String, int, Image, String, String)show(String, String, Command[], int, Image, long)show(String, Component, Command[], int, Image, long)show(String, String, int, Image, String, String, long)show(String, String, Command, Command[], int, Image, long)show(String, String, Command[], int, Image, long, Transition)show(String, Component, Command[], int, Image, long, Transition)show(String, String, Command, Command[], int, Image, long, Transition)show(String, Component, Command, Command[], int, Image, long, Transition)")); - index.put("com.codename1.ui.Display", splitMembers("accessibilityTreeChanged(int)addCompletionHandler(Media, Runnable)addEdtErrorHandler(ActionListener)addMessageListener(ActionListener)addPostureListener(ActionListener)addVirtualKeyboardListener(ActionListener)addWindowListener(ActionListener)announceForAccessibility(String)announceForAccessibility(Component, String)areMutableImagesFast()callSerially(Runnable)callSeriallyAndWait(Runnable)callSeriallyAndWait(Runnable, int)callSeriallyOnIdle(Runnable)canDial()canExecute(String)canForceOrientation()canInstallOnHomescreen()cancelBackgroundProcessing(String)cancelBackgroundWork(String)cancelLocalNotification(String)captureAudio(ActionListener)captureAudio(MediaRecorderBuilder, ActionListener)capturePhoto(ActionListener)captureScreen()captureVideo(ActionListener)captureVideo(VideoCaptureConstraints, ActionListener)confirmAttestation(String)consumePendingNativeCrash()convertBidiLogicalToVisual(String)convertToPixels(float)convertToPixels(float, byte)convertToPixels(int, boolean)convertToPixels(float, byte, boolean)copyToClipboard(ClipboardContent)createBackgroundMedia(String)createBackgroundMediaAsync(String)createContact(String, String, String, String, String, String)createGpuPeer(RenderView)createMedia(String, boolean, Runnable)createMediaAsync(String, boolean, Runnable)createMediaRecorder(MediaRecorderBuilder)createMediaRecorder(String)createMediaRecorder(String, String)createNotificationChannelGroup(String, String)createSFSymbolImage(String, int, float, int)createSoftWeakRef(Object)createSoundPool(int)createThread(Runnable, String)delete(String)deleteContact(String)deleteNotificationChannel(String)deregisterPush()dial(String)dismissNotification(Object)dispatchMessage(MessageEvent)downloadBytesAsFile(String, byte[])editString(Component, int, int, String)editString(Component, int, int, String, int)execute(String)execute(String, ActionListener)exists(String)exitApplication()exitFullScreen()extractHardRef(Object)fireMagnifyGesture(int, int, float)fireMouseWheelEvent(int, int, int, int, boolean, int)fireRotationGesture(int, int, float)fireVirtualKeyboardEvent(boolean)fireWindowEvent(WindowEvent)flashBacklight(int)gaussianBlurImage(Image, float)getAllContacts(boolean)getAllContacts(boolean, boolean, boolean, boolean, boolean, boolean)getAppSignerDigests()getAvailableRecordingMimeTypes()getBiometrics()getBluetooth()getBonjourPlatform()getCarBridge()getCharLocation(String, int)getClipboardContent()getCodeScanner()getColorVisionDeficiency()getCommandBehavior()getCompromiseReasons()getContactById(String)getContactById(String, boolean, boolean, boolean, boolean, boolean)getCrashReporter()getCurrent()getCurrentPointerEvent()getDatabasePath(String)getDensityStr()getDesktopSize()getDeviceDensity()getDevicePosture()getDisplayCount()getDisplayHeight()getDisplaySafeArea(Rectangle)getDisplayWidth()getDragSpeed(boolean)getDragStartPercentage()getEnabledAccessibilityServices()getFrameRate()getGameAction(int)getHealth()getImageIO()getInAppPurchase()getInAppPurchase(boolean)getInitialWindowSizeHintPercent()getInvisibleAreaUnderVKB()getKeyCode(int)getKeyboardType()getLargerTextScale()getLineSeparator()getLinkedContactIds(Contact)getLocalCalendarSource()getLocalizationManager()getLocationManager()getLongPointerPressInterval()getMediaRecorderingMimeType()getMotionSensorManager()getMsisdn()getNativeLogSnapshot()getNetworkTypePlatform()getNfc()getPasteDataFromClipboard()getPlatformName()getPlatformOverrides()getPluginSupport()getPointerButton()getPointerContactSize()getPointerPressure()getPointerTiltX()getPointerTiltY()getPointerType()getPreferredBackgroundFetchInterval(int)getPressedButtonMask()getProjectBuildHints()getProperty(String, String)getSMSSupport()getSecureStorage()getSharedJavascriptContext()getShowDuringEditBehavior()getStackTrace(Thread, Throwable)getSupportedVirtualKeyboard()getSurfaceBridge()getUdid()getUsbPlatform()getVideoIO()getVirtualKeyboardListener()getWearableBridge()getWifiDirectPlatform()getWifiPlatform()getWindowBounds()gpuRequestRender(PeerComponent)gpuSetContinuous(PeerComponent, boolean)hasCamera()hasDragOccured()hasNativeTheme()hideNotify()installNativeCrashHandler()installNativeTheme()invokeAndBlock(Runnable)invokeAndBlock(Runnable, boolean)invokeWithoutBlocking(Runnable)invokeWithoutBlockingWithResultSync(RunnableWithResultSync)isAccessibilityTreeSupported()isAccessibilityTreeUpdateRequired()isAllowMinimizing()isAltGraphKeyDown()isAltKeyDown()isAttestationSupported()isAutoFoldVKBOnFormSwitch()isBackgroundFetchSupported()isBackgroundProcessingSupported()isBackgroundWorkSupported()isBadgingSupported()isBidiAlgorithm()isBoldTextEnabled()isBuiltinSoundAvailable(String)isBuiltinSoundsEnabled()isCallDetectionSupported()isCarConnected()isClickTouchScreen()isContactsPermissionGranted()isControlKeyDown()isDarkMode()isDatabaseCustomPathSupported()isDebuggableBuild()isDesktop()isDesktopMode()isDeviceCompromised()isDifferentiateWithoutColorEnabled()isEdt()isEnableAsyncStackTraces()isExternalDisplayConnected()isFoldable()isForegroundServiceSupported()isFullScreenSupported()isGalleryTypeSupported(int)isGaussianBlurSupported()isGetAllContactsFast()isGpuSupported()isGrayscaleEnabled()isHighContrastEnabled()isInCall()isInFullScreenMode()isInTransition()isInvertColorsEnabled()isJailbrokenDevice()isLargerTextEnabled()isLockOrientation()isMetaKeyDown()isMinimized()isMultiKeyMode()isMultiTouch()isNativeCommands()isNativeInAppReviewSupported()isNativeInputSupported()isNativePickerTypeSupported(int)isNativeShareSupported()isNativeTitle()isNativeVideoPlayerControlsIncluded()isNotificationSupported()isOnOffSwitchLabelsEnabled()isOpenNativeNavigationAppSupported()isPortrait()isPrintingSupported()isPureTouch()isRTL(char)isReceiveSharedContentSupported()isReduceMotionEnabled()isReduceTransparencyEnabled()isRightMouseButtonDown()isScreenReaderEnabled()isScreenSaverDisableSupported()isScrollWheeling()isShiftKeyDown()isSimulator()isSoundPoolSupported()isSpeechRecognitionSupported()isStylusPointer()isTV()isTablet()isTextToSpeechSupported()isThirdSoftButton()isTouchScreenDevice()isVirtualKeyboardShowing()isWalletExtensionSupported()isWatch()keyPressed(int)keyReleased(int)lockOrientation(boolean)minimizeApplication()notifyPushCompletion()notifyStatusBar(String, String, String, boolean, boolean)notifyStatusBar(String, String, String, boolean, boolean, Hashtable)numAlphaLevels()numColors()onCanInstallOnHomescreen(Runnable)onEditingComplete(Component, String)openFileChooser(ActionListener, String)openGallery(ActionListener, int)openImageGallery(ActionListener)openNativeNavigationApp(String)openNativeNavigationApp(double, double)openOrCreate(String)platformUsesInputMode()playBuiltinSound(String)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int[], int[])pointerReleased(int[], int[])postMessage(MessageEvent)postureChanged()print(String, String, PrintResultListener)promptInstallOnHomescreen()refreshContacts()refreshNativeTitle()registerNotificationChannel(NotificationChannelBuilder)registerPush()registerPush(String, boolean)registerPush(Hashtable, boolean)removeCompletionHandler(Media, Runnable)removeEdtErrorHandler(ActionListener)removeMessageListener(ActionListener)removePostureListener(ActionListener)removeVirtualKeyboardListener(ActionListener)removeWindowListener(ActionListener)requestFullScreen()requestIntegrityToken(String)requestNativeInAppReview(SuccessCallback)requestNotificationPermission(NotificationPermissionCallback)requestNotificationPermission(NotificationPermissionRequest, NotificationPermissionCallback)resetAttestation()restoreMinimizedApplication()restoreToBookmark()scheduleBackgroundProcessing(String, long, boolean, boolean, Runnable)scheduleBackgroundTask(Runnable)scheduleBackgroundWork(WorkRequest)scheduleLocalNotification(LocalNotification, long, int)screenshot(SuccessCallback)sendMessage(String[], String, Message)sendSMS(String, String)sendSMS(String, String, boolean)setAllowMinimizing(boolean)setAutoFoldVKBOnFormSwitch(boolean)setBadgeNumber(int)setBidiAlgorithm(boolean)setBookmark(Runnable)setBuiltinSoundsEnabled(boolean)setCommandBehavior(int)setCrashReporter(CrashReport)setDarkMode(Boolean)setDragStartPercentage(int)setEnableAsyncStackTraces(boolean)setFramerate(int)setInitialWindowSizeHintPercent(Dimension)setInterval(int, Runnable)setLongPointerPressInterval(int)setMultiKeyMode(boolean)setNativeCommands(boolean)setNoSleep(boolean)setPollingFrequency(int)setPreferredBackgroundFetchInterval(int)setProjectBuildHint(String, String)setProperty(String, String)setPureTouch(boolean)setScreenSaverEnabled(boolean)setSecureScreen(boolean)setShowDuringEditBehavior(int)setShowVirtualKeyboard(boolean)setThirdSoftButton(boolean)setTimeout(int, Runnable)setTouchScreenDevice(boolean)setTransitionYield(int)setVirtualKeyboardListener(ActionListener)setWindowSize(int, int)share(String)share(String, String, String)share(String, String, String, Rectangle)share(String, String, String, Rectangle, ShareResultListener)shouldRenderSelection()shouldRenderSelection(Component)showNativePicker(int, Component, Object, Object)showNativeScreen(Object)showNotify()sizeChanged(int, int)startForegroundService(String, String, String, String, Task, ForegroundService)startRemoteControl()startSpeechRecognition(RecognitionOptions, RecognitionCallback)startThread(Runnable, String)stopEditing(Component)stopEditing(Component, Runnable)stopForegroundService(Object)stopRemoteControl()stopSpeechRecognition()subscribeToPushTopic(String)textToSpeechAvailableVoices()textToSpeechSpeak(String, TtsOptions)textToSpeechStop()unlockOrientation()unsubscribeFromPushTopic(String)updateForegroundServiceNotification(Object, String, String)vibrate(int)walletExtensionClear()walletExtensionSetAuthToken(String)walletExtensionSetPassEntries(boolean, WalletPassEntry[])walletExtensionSetRequiresAuthentication(boolean)deinitialize()getInstance()init(Object)isInitialized()")); + index.put("com.codename1.ui.Display", splitMembers("accessibilityTreeChanged(int)addCompletionHandler(Media, Runnable)addEdtErrorHandler(ActionListener)addMessageListener(ActionListener)addPostureListener(ActionListener)addTapjackingListener(ActionListener)addVirtualKeyboardListener(ActionListener)addWindowListener(ActionListener)announceForAccessibility(String)announceForAccessibility(Component, String)areMutableImagesFast()callSerially(Runnable)callSeriallyAndWait(Runnable)callSeriallyAndWait(Runnable, int)callSeriallyOnIdle(Runnable)canDial()canExecute(String)canForceOrientation()canInstallOnHomescreen()cancelBackgroundProcessing(String)cancelBackgroundWork(String)cancelLocalNotification(String)captureAudio(ActionListener)captureAudio(MediaRecorderBuilder, ActionListener)capturePhoto(ActionListener)captureScreen()captureVideo(ActionListener)captureVideo(VideoCaptureConstraints, ActionListener)confirmAttestation(String)consumePendingNativeCrash()convertBidiLogicalToVisual(String)convertToPixels(float)convertToPixels(float, byte)convertToPixels(int, boolean)convertToPixels(float, byte, boolean)copyToClipboard(ClipboardContent)createBackgroundMedia(String)createBackgroundMediaAsync(String)createContact(String, String, String, String, String, String)createGpuPeer(RenderView)createMedia(String, boolean, Runnable)createMediaAsync(String, boolean, Runnable)createMediaRecorder(MediaRecorderBuilder)createMediaRecorder(String)createMediaRecorder(String, String)createNotificationChannelGroup(String, String)createSFSymbolImage(String, int, float, int)createSoftWeakRef(Object)createSoundPool(int)createThread(Runnable, String)databaseIdentityForEngineFile(String)databaseManagedKeyIdentity(String)databaseRegistryIdentity(String)delete(String)deleteContact(String)deleteNotificationChannel(String)deregisterPush()dial(String)dismissNotification(Object)dispatchMessage(MessageEvent)downloadBytesAsFile(String, byte[])editString(Component, int, int, String)editString(Component, int, int, String, int)execute(String)execute(String, ActionListener)exists(String)exitApplication()exitFullScreen()extractHardRef(Object)fireMagnifyGesture(int, int, float)fireMouseWheelEvent(int, int, int, int, boolean, int)fireRotationGesture(int, int, float)fireVirtualKeyboardEvent(boolean)fireWindowEvent(WindowEvent)flashBacklight(int)gaussianBlurImage(Image, float)getAllContacts(boolean)getAllContacts(boolean, boolean, boolean, boolean, boolean, boolean)getAppSignerDigests()getAvailableRecordingMimeTypes()getBiometrics()getBluetooth()getBonjourPlatform()getCarBridge()getCharLocation(String, int)getClipboardContent()getCodeScanner()getColorVisionDeficiency()getCommandBehavior()getCompromiseReasons()getContactById(String)getContactById(String, boolean, boolean, boolean, boolean, boolean)getCrashReporter()getCurrent()getCurrentPointerEvent()getDatabasePath(String)getDensityStr()getDesktopSize()getDeviceDensity()getDevicePosture()getDisplayCount()getDisplayHeight()getDisplaySafeArea(Rectangle)getDisplayWidth()getDragSpeed(boolean)getDragStartPercentage()getEnabledAccessibilityServices()getFrameRate()getGameAction(int)getHealth()getHomeBridge()getImageIO()getInAppPurchase()getInAppPurchase(boolean)getInitialWindowSizeHintPercent()getIntentBridge()getInvisibleAreaUnderVKB()getKeyCode(int)getKeyboardType()getLargerTextScale()getLineSeparator()getLinkedContactIds(Contact)getLocalCalendarSource()getLocalizationManager()getLocationManager()getLongPointerPressInterval()getMediaRecorderingMimeType()getMotionSensorManager()getMsisdn()getNativeLogSnapshot()getNetworkTypePlatform()getNfc()getPasteDataFromClipboard()getPlatformName()getPlatformOverrides()getPluginSupport()getPointerButton()getPointerContactSize()getPointerPressure()getPointerTiltX()getPointerTiltY()getPointerType()getPreferredBackgroundFetchInterval(int)getPressedButtonMask()getProjectBuildHints()getProperty(String, String)getSMSSupport()getSecureStorage()getSharedJavascriptContext()getShowDuringEditBehavior()getStackTrace(Thread, Throwable)getSupportedVirtualKeyboard()getSurfaceBridge()getTapjackingPolicy()getUdid()getUsbPlatform()getVideoIO()getVirtualKeyboardListener()getWearableBridge()getWifiDirectPlatform()getWifiPlatform()getWindowBounds()gpuRequestRender(PeerComponent)gpuSetContinuous(PeerComponent, boolean)hasCamera()hasDragOccured()hasNativeTheme()hideNotify()installNativeCrashHandler()installNativeTheme()invokeAndBlock(Runnable)invokeAndBlock(Runnable, boolean)invokeWithoutBlocking(Runnable)invokeWithoutBlockingWithResultSync(RunnableWithResultSync)isAccessibilityTreeSupported()isAccessibilityTreeUpdateRequired()isAllowMinimizing()isAltGraphKeyDown()isAltKeyDown()isAttestationSupported()isAutoFoldVKBOnFormSwitch()isBackgroundFetchSupported()isBackgroundProcessingSupported()isBackgroundWorkSupported()isBadgingSupported()isBidiAlgorithm()isBlobQueryParameterSupported()isBoldTextEnabled()isBuiltinSoundAvailable(String)isBuiltinSoundsEnabled()isCallDetectionSupported()isCarConnected()isClickTouchScreen()isContactsPermissionGranted()isControlKeyDown()isDarkMode()isDatabaseCustomPathSupported()isDatabaseEncryptionSupported()isDatabaseFileEncrypted(String)isDatabaseManagedKeyHardwareBacked()isDebuggableBuild()isDesktop()isDesktopMode()isDeviceCompromised()isDifferentiateWithoutColorEnabled()isEdt()isEnableAsyncStackTraces()isExternalDisplayConnected()isFoldable()isForegroundServiceSupported()isFullScreenSupported()isGalleryTypeSupported(int)isGaussianBlurSupported()isGetAllContactsFast()isGpuSupported()isGrayscaleEnabled()isHideOverlayWindowsSupported()isHighContrastEnabled()isInCall()isInFullScreenMode()isInTransition()isInvertColorsEnabled()isJailbrokenDevice()isLargerTextEnabled()isLockOrientation()isMetaKeyDown()isMinimized()isMultiKeyMode()isMultiTouch()isNativeCommands()isNativeInAppReviewSupported()isNativeInputSupported()isNativePickerTypeSupported(int)isNativeShareSupported()isNativeTitle()isNativeVideoPlayerControlsIncluded()isNotificationSupported()isOnOffSwitchLabelsEnabled()isOpenNativeNavigationAppSupported()isPortrait()isPrintingSupported()isPureTouch()isRTL(char)isReceiveSharedContentSupported()isReduceMotionEnabled()isReduceTransparencyEnabled()isRelativeAttachmentNameResolvable()isRightMouseButtonDown()isScreenObscured()isScreenReaderEnabled()isScreenSaverDisableSupported()isScrollWheeling()isShiftKeyDown()isSimulator()isSoundPoolSupported()isSpeechRecognitionSupported()isStylusPointer()isTV()isTablet()isTextToSpeechSupported()isThirdSoftButton()isTouchScreenDevice()isVirtualKeyboardShowing()isWalletExtensionSupported()isWatch()keyPressed(int)keyReleased(int)lockOrientation(boolean)minimizeApplication()notifyPushCompletion()notifyStatusBar(String, String, String, boolean, boolean)notifyStatusBar(String, String, String, boolean, boolean, Hashtable)numAlphaLevels()numColors()onCanInstallOnHomescreen(Runnable)onEditingComplete(Component, String)openDatabaseConnections(String)openFileChooser(ActionListener, String)openGallery(ActionListener, int)openImageGallery(ActionListener)openNativeNavigationApp(String)openNativeNavigationApp(double, double)openOrCreate(String)openOrCreate(String, DatabaseConfig)openOrCreateForRekey(String)platformUsesInputMode()playBuiltinSound(String)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int[], int[])pointerReleased(int[], int[])postMessage(MessageEvent)postureChanged()print(String, String, PrintResultListener)promptInstallOnHomescreen()refreshContacts()refreshNativeTitle()registerNotificationChannel(NotificationChannelBuilder)registerPush()registerPush(String, boolean)registerPush(Hashtable, boolean)removeCompletionHandler(Media, Runnable)removeEdtErrorHandler(ActionListener)removeMessageListener(ActionListener)removePostureListener(ActionListener)removeTapjackingListener(ActionListener)removeVirtualKeyboardListener(ActionListener)removeWindowListener(ActionListener)requestFullScreen()requestIntegrityToken(String)requestNativeInAppReview(SuccessCallback)requestNotificationPermission(NotificationPermissionCallback)requestNotificationPermission(NotificationPermissionRequest, NotificationPermissionCallback)resetAttestation()restoreMinimizedApplication()restoreToBookmark()scheduleBackgroundProcessing(String, long, boolean, boolean, Runnable)scheduleBackgroundTask(Runnable)scheduleBackgroundWork(WorkRequest)scheduleLocalNotification(LocalNotification, long, int)screenshot(SuccessCallback)sendMessage(String[], String, Message)sendSMS(String, String)sendSMS(String, String, boolean)setAllowMinimizing(boolean)setAutoFoldVKBOnFormSwitch(boolean)setBadgeNumber(int)setBidiAlgorithm(boolean)setBookmark(Runnable)setBuiltinSoundsEnabled(boolean)setCommandBehavior(int)setCrashReporter(CrashReport)setDarkMode(Boolean)setDragStartPercentage(int)setEnableAsyncStackTraces(boolean)setFramerate(int)setHideOverlayWindows(boolean)setInitialWindowSizeHintPercent(Dimension)setInterval(int, Runnable)setLongPointerPressInterval(int)setMultiKeyMode(boolean)setNativeCommands(boolean)setNoSleep(boolean)setPollingFrequency(int)setPreferredBackgroundFetchInterval(int)setProjectBuildHint(String, String)setProperty(String, String)setPureTouch(boolean)setScreenSaverEnabled(boolean)setSecureScreen(boolean)setShowDuringEditBehavior(int)setShowVirtualKeyboard(boolean)setTapjackingProtection(TapjackingPolicy)setThirdSoftButton(boolean)setTimeout(int, Runnable)setTouchScreenDevice(boolean)setTransitionYield(int)setVirtualKeyboardListener(ActionListener)setWindowSize(int, int)share(String)share(String, String, String)share(String, String, String, Rectangle)share(String, String, String, Rectangle, ShareResultListener)shouldRenderSelection()shouldRenderSelection(Component)showNativePicker(int, Component, Object, Object)showNativeScreen(Object)showNotify()sizeChanged(int, int)startForegroundService(String, String, String, String, Task, ForegroundService)startRemoteControl()startSpeechRecognition(RecognitionOptions, RecognitionCallback)startThread(Runnable, String)stopEditing(Component)stopEditing(Component, Runnable)stopForegroundService(Object)stopRemoteControl()stopSpeechRecognition()subscribeToPushTopic(String)textToSpeechAvailableVoices()textToSpeechSpeak(String, TtsOptions)textToSpeechStop()unlockOrientation()unsubscribeFromPushTopic(String)updateForegroundServiceNotification(Object, String, String)vibrate(int)walletExtensionClear()walletExtensionSetAuthToken(String)walletExtensionSetPassEntries(boolean, WalletPassEntry[])walletExtensionSetRequiresAuthentication(boolean)deinitialize()getInstance()init(Object)isInitialized()")); index.put("com.codename1.ui.DynamicImage", splitMembers("addActionListener(ActionListener)animate()applyMask(Object)applyMask(Object, int, int)applyMaskAutoScale(Object)asyncLock(Image)createMask()dispose()fill(int, int)fireChangedEvent()flipHorizontally(boolean)flipVertically(boolean)getGraphics()getHeight()getImage()getImageName()getRGB()getRGB(int[])getRGBCached()getSVGDocument()getStyle()getWidth()isAnimation()isLocked()isOpaque()isSVG()lock()mirror()modifyAlpha(byte)modifyAlpha(byte, int)modifyAlphaWithTranslucency(byte)removeActionListener(ActionListener)requiresDrawImage()rotate(int)rotate180Degrees(boolean)rotate270Degrees(boolean)rotate90Degrees(boolean)scale(int, int)scaled(int, int)scaledHeight(int)scaledLargerRatio(int, int)scaledSmallerRatio(int, int)scaledWidth(int)setImageName(String)setStyle(Style)subImage(int, int, int, int, boolean)toRGB(RGBImage, int, int, int, int, int, int)unlock()setIcon(Label, DynamicImage)")); - index.put("com.codename1.ui.EditField", splitMembers("accessibilityChanged()accessibilityChanged(int)addActionListener(ActionListener)addContextMenuListener(ActionListener)addDataChangedListener(DataChangedListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)deleteSurroundingText(int, int)drop(Component, int, int)editorChanged()finishComposing()fireEditorEvent(String, String)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getColumns()getComponentForm()getComponentState()getConfig()getConstraint()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getHint()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getRows()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()inputFocusGained()inputFocusLost()insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSingleLineTextArea()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTextInputSupported()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeActionListener(ActionListener)removeContextMenuListener(ActionListener)removeDataChangedListener(DataChangedListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setActionType(int)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setColumns(int)setComponentState(Object)setComposingText(String, int)setConstraint(int)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditable(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHint(String)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setRows(int)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setSingleLineTextArea(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()startTextInput(TextInputClient, TextInputConfig)stopEditing(Runnable)stopTextInput(Object)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTextInputState(Object, TextInputState)visibleBoundsContains(int, int)")); + index.put("com.codename1.ui.EditField", splitMembers("accessibilityChanged()accessibilityChanged(int)addActionListener(ActionListener)addContextMenuListener(ActionListener)addDataChangedListener(DataChangedListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)copySelection()createStyleAnimation(String, int)cutSelection()deleteBackward()deleteSurroundingText(int, int)drop(Component, int, int)editorChanged()finishComposing()fireEditorEvent(String, String)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getColumns()getComponentForm()getComponentState()getConfig()getConstraint()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getHint()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getRows()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()inputFocusGained()inputFocusLost()insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSingleLineTextArea()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTextInputSupported()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pasteClipboard()performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeActionListener(ActionListener)removeContextMenuListener(ActionListener)removeDataChangedListener(DataChangedListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setActionType(int)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setColumns(int)setComponentState(Object)setComposingText(String, int)setConstraint(int)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditable(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHint(String)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setRows(int)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setSingleLineTextArea(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()startTextInput(TextInputClient, TextInputConfig)stopEditing(Runnable)stopTextInput(Object)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTextInputState(Object, TextInputState)visibleBoundsContains(int, int)")); index.put("com.codename1.ui.Editable", splitMembers("isEditable()isEditing()startEditingAsync()stopEditing(Runnable)")); index.put("com.codename1.ui.EncodedImage", splitMembers("addActionListener(ActionListener)animate()applyMask(Object)applyMask(Object, int, int)applyMaskAutoScale(Object)asyncLock(Image)createMask()dispose()fill(int, int)fireChangedEvent()flipHorizontally(boolean)flipVertically(boolean)getGraphics()getHeight()getImage()getImageData()getImageName()getRGB()getRGB(int[])getRGBCached()getSVGDocument()getWidth()isAnimation()isDisposed()isLocked()isOpaque()isSVG()lock()mirror()modifyAlpha(byte)modifyAlpha(byte, int)modifyAlphaWithTranslucency(byte)removeActionListener(ActionListener)requiresDrawImage()rotate(int)rotate180Degrees(boolean)rotate270Degrees(boolean)rotate90Degrees(boolean)scale(int, int)scaled(int, int)scaledEncoded(int, int)scaledHeight(int)scaledLargerRatio(int, int)scaledSmallerRatio(int, int)scaledWidth(int)setImageName(String)subImage(int, int, int, int, boolean)toRGB(RGBImage, int, int, int, int, int, int)unlock()create(String)create(byte[])create(byte[], int, int, boolean)createFromImage(Image, boolean)createFromRGB(int[], int, int, boolean)createMulti(int[], byte[][])")); + } + + private static void fillMethodIndex22(Map index) { index.put("com.codename1.ui.Font", splitMembers("addContrast(byte)charWidth(char)charsWidth(char[], int, int)derive(float, int)derive(float, int, byte)deriveLetterSpacing(float)equals(Object)getAscent()getCharset()getDescent()getFace()getHeight()getNativeFont()getPixelSize()getSize()getStyle()hashCode()isTTFNativeFont()stringWidth(String)substringWidth(String, int, int)clearBitmapCache()clearDerivedFontCache()create(String)createBitmapFont(Image, int[], int[], String)createBitmapFont(String, Image, int[], int[], String)createSystemFont(int, int, int)createTrueTypeFont(String)createTrueTypeFont(String, float)createTrueTypeFont(String, String)createTrueTypeFont(String, float, byte)getBitmapFont(String)getDefaultFont()isBitmapFontEnabled()isCreationByStringSupported()isNativeFontSchemeSupported()isTrueTypeFileSupported()setBitmapFontEnabled(boolean)setDefaultFont(Font)")); index.put("com.codename1.ui.FontImage", splitMembers("addActionListener(ActionListener)animate()applyMask(Object)applyMask(Object, int, int)applyMaskAutoScale(Object)asyncLock(Image)createMask()dispose()fill(int, int)fireChangedEvent()flipHorizontally(boolean)flipVertically(boolean)getFont()getGraphics()getHeight()getImage()getImageName()getPadding()getRGB()getRGB(int[])getRGBCached()getSVGDocument()getText()getWidth()isAnimation()isLocked()isOpaque()isSVG()lock()mirror()modifyAlpha(byte)modifyAlpha(byte, int)modifyAlphaWithTranslucency(byte)removeActionListener(ActionListener)requiresDrawImage()rotate(int)rotate180Degrees(boolean)rotate270Degrees(boolean)rotate90Degrees(boolean)rotateAnimation()scale(int, int)scaled(int, int)scaledHeight(int)scaledLargerRatio(int, int)scaledSmallerRatio(int, int)scaledWidth(int)setBgTransparency(int)setFgAlpha(int)setImageName(String)setPadding(int)subImage(int, int, int, int, boolean)toEncodedImage()toImage()toRGB(RGBImage, int, int, int, int, int, int)unlock()create(String, Style)create(String, Style, Font)createFixed(String, Font, int, int, int)createFixed(String, Font, int, int, int, int)createMaterial(char, Style)createMaterial(char, Style, float)createMaterial(char, String, float)createSFOrMaterial(char, Style, float)getDefaultPadding()getDefaultSize()getMaterialDesignFont()setDefaultPadding(int)setDefaultSize(float)setFontIcon(SpanButton, Font, char)setFontIcon(Label, Font, char)setFontIcon(MultiButton, Font, char, float)setFontIcon(SpanButton, Font, char, float)setFontIcon(SpanLabel, Font, char, float)setFontIcon(Label, Font, char, float)setFontIcon(Label, Font, char[], float)setFontIcon(Command, Font, char, String, float)setIcon(IconHolder, char, float)setIcon(IconHolder, Font, char, float)setIcon(IconHolder, Font, char[], float)setMaterialIcon(MultiButton, char)setMaterialIcon(SpanButton, char)setMaterialIcon(SpanLabel, char)setMaterialIcon(Label, char)setMaterialIcon(IconHolder, char)setMaterialIcon(MultiButton, char, float)setMaterialIcon(SpanButton, char, float)setMaterialIcon(SpanLabel, char, float)setMaterialIcon(Command, char, String)setMaterialIcon(Label, char, float)setMaterialIcon(Label, char[], float)setMaterialIcon(Component, char, float)setMaterialIcon(Component, char[], float)setMaterialIcon(Command, char, String, float)setMaterialIcon(Label, Font, char, float)")); index.put("com.codename1.ui.Form", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addCommand(Command)addCommand(Command, int)addCommandListener(ActionListener)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addComponentAwaitingRelease(Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addGameKeyListener(int, ActionListener)addKeyListener(int, ActionListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addOrientationListener(ActionListener)addPasteListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addShowListener(ActionListener)addSizeChangedListener(ActionListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()checkPopGuard(PopReason)clearClientProperties()clearComponentsAwaitingRelease()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)deregisterAnimated(Animation)dispatchCommand(Command, ActionEvent)dispatchPaste(ActionEvent)drop(Component, int, int)findCurrentlyEditingComponent()findDropTargetAt(int, int)findFirstFocusable()findNextFocusHorizontal(boolean)findNextFocusVertical(boolean)flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBackCommand()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClearCommand()getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getCommand(int)getCommandCount()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getContentPane()getCurrentInputDevice()getCursor()getDefaultCommand()getDirtyRegion()getDisabledStyle()getDragRegionStatus(int, int)getDragTransparency()getDraggedx()getDraggedy()getEditOnShow()getEditingDelegate()getFocused()getFormLayeredPane(Class, boolean)getGlassPane()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getInvisibleAreaUnderVKB()getLabelForComponent()getLayeredPane()getLayeredPane(Class, boolean)getLayeredPane(Class, int)getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getMenuBar()getMenuStyle()getName()getNativeOverlay()getNextComponent(Component)getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPopGuard()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPreviousComponent(Component)getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeArea()getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getSoftButton(int)getSoftButtonCount()getSourceCommand()getStyle()getTabIndex()getTabIterator(Component)getTensileLength()getTextSelection()getTextSelectionSupport()getTintColor()getTitle()getTitleArea()getTitleComponent()getTitleStyle()getToolbar()getTooltip()getTransitionInAnimator()getTransitionOutAnimator()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()grabAnimationLock()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasMedia()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isCyclicFocus()isDragRegion(int, int)isDraggable()isDropTarget()isEditable()isEditing()isEnableCursors()isEnabled()isFlatten()isFocusScrolling()isFocusable()isFormBottomPaddingEditingMode()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isMinimizeOnBack()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollable()isScrollableX()isScrollableY()isSingleFocusMode()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackground(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)registerAnimated(Animation)releaseAnimationLock()remove()removeAll()removeAllCommands()removeAllShowListeners()removeCommand(Command)removeCommandListener(ActionListener)removeComponent(Component)removeComponentAwaitingRelease(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeGameKeyListener(int, ActionListener)removeKeyListener(int, ActionListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removeOrientationListener(ActionListener)removePasteListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeShowListener(ActionListener)removeSizeChangedListener(ActionListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAllowEnableLayoutOnPaint(boolean)setAlwaysTensile(boolean)setBackCommand(Command)setBackCommand(String, Image, ActionListener)setBgImage(Image)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setClearCommand(Command)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCurrentInputDevice(VirtualInputDevice)setCursor(int)setCyclicFocus(boolean)setDefaultCommand(Command)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditOnShow(TextArea)setEditingDelegate(Editable)setEnableCursors(boolean)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusScrolling(boolean)setFocusable(boolean)setFocused(Component)setFormBottomPaddingEditingMode(boolean)setGlassPane(Painter)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setMenuBar(MenuBar)setMenuCellRenderer(ListCellRenderer)setMenuTransitions(Transition, Transition)setMinimizeOnBack(boolean)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOverrideInvisibleAreaUnderVKB(int)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPopGuard(PopGuard)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaChanged()setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setSourceCommand(Command)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTintColor(int)setTitle(String)setTitleComponent(Label)setTitleComponent(Label, Transition)setTitleStyle(Style)setToolBar(Toolbar)setToolbar(Toolbar)setTooltip(String)setTransitionInAnimator(Transition)setTransitionOutAnimator(Transition)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)show()showBack()startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)")); @@ -3480,9 +3700,6 @@ private static void fillMethodIndex20(Map index) { index.put("com.codename1.ui.RichTextFormat", splitMembers("")); index.put("com.codename1.ui.SelectableIconHolder", splitMembers("getDisabledIcon()getGap()getIcon()getIconFromState()getIconStyleComponent()getIconUIID()getPressedIcon()getRolloverIcon()getRolloverPressedIcon()getTextPosition()setDisabledIcon(Image)setFontIcon(Font, char, float)setGap(int)setIcon(Image)setIconUIID(String)setMaterialIcon(char, float)setPressedIcon(Image)setRolloverIcon(Image)setRolloverPressedIcon(Image)setTextPosition(int)")); index.put("com.codename1.ui.Sheet", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addBackListener(ActionListener)addCloseListener(ActionListener)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)back()back(int)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)findDropTargetAt(int, int)findFirstFocusable()finish(Object)flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getCommandsContainer()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getContentPane()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getParentSheet()getPosition()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTitle()getTitleComponent()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hideBackButton()invalidate()isAllowClose()isAlwaysTensile()isAncestorSheetOf(Sheet)isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isSwipeToDismissEnabled()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeBackListener(ActionListener)removeCloseListener(ActionListener)removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAllowClose(boolean)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPosition(String)setPosition(String, String)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setSwipeToDismissEnabled(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTitle(String)setTitleComponent(Component)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)show()show(int)showBackButton()showForResult()showForResult(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)findContainingSheet(Component)getCurrentSheet()isSheetVisibleAt(int, int)")); - } - - private static void fillMethodIndex21(Map index) { index.put("com.codename1.ui.SideMenuBar", splitMembers("accessibilityChanged()accessibilityChanged(int)actionPerformed(ActionEvent)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addCommand(Command)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()closeMenu()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)findCommandComponent(Command)findDropTargetAt(int, int)findFirstFocusable()flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBackCommand()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClearCommand()getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getCommand(int)getCommandBehavior()getCommandCount()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getDefaultCommand()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getMenuStyle()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getParentForm()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommand()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()handlesKeycode(int)hasFixedPreferredSize()hasFocus()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isMenuOpen()isMenuShowing()isMinimizeOnBack()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)openMenu(String)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeEmptySoftbuttons()removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBackCommand(Command)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setClearCommand(Command)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCommandUIID(Command, String)setComponentState(Object)setCursor(int)setDefaultCommand(Command)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setMenuCellRenderer(ListCellRenderer)setMinimizeOnBack(boolean)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommand(Command)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTransitions(Transition, Transition)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)showMenu()startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)closeCurrentMenu()closeCurrentMenu(Runnable)isShowing()")); index.put("com.codename1.ui.Slider", splitMembers("accessibilityChanged()accessibilityChanged(int)addActionListener(ActionListener)addContextMenuListener(ActionListener)addDataChangedListener(DataChangedListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)deinitialize()drop(Component, int, int)getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAlignment()getAllStyles()getAnimationManager()getBadgeStyleComponent()getBadgeText()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getFontIcon()getFontIconSize()getGap()getHeight()getIcon()getIconFont()getIconStyleComponent()getIconUIID()getIncrements()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getMask()getMaskName()getMaskedIcon()getMaterialIcon()getMaterialIconSize()getMaxAutoSize()getMaxValue()getMinAutoSize()getMinValue()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getProgress()getProgress(ActionEvent)getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getShiftMillimeters()getShiftMillimetersF()getShiftText()getSideGap()getSliderEmptySelectedStyle()getSliderEmptyUnselectedStyle()getSliderFullSelectedStyle()getSliderFullUnselectedStyle()getStringWidth(Font)getStyle()getTabIndex()getTensileLength()getText()getTextPosition()getTextSelectionSupport()getThumbImage()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVerticalAlignment()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()initComponent()isAlwaysTensile()isAutoSizeMode()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isEndsWith3Points()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isInfinite()isLegacyRenderer()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRenderPercentageOnTop()isRenderValueOnTop()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isShouldLocalize()isShowEvenIfBlank()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTextSelectionEnabled()isTickerEnabled()isTickerRunning()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVertical()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeActionListener(ActionListener)removeContextMenuListener(ActionListener)removeDataChangedListener(DataChangedListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlignment(int)setAlwaysTensile(boolean)setAutoSizeMode(boolean)setBadgeText(String)setBadgeUIID(String)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditable(boolean)setEditingDelegate(Editable)setEnabled(boolean)setEndsWith3Points(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontIcon(char)setFontIcon(Font, char)setFontIcon(Font, char, float)setGap(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIcon(Image)setIconUIID(String)setIgnorePointerEvents(boolean)setIncrements(int)setInfinite(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLegacyRenderer(boolean)setMask(Object)setMaskName(String)setMaterialIcon(char)setMaterialIcon(char, float)setMaxAutoSize(float)setMaxValue(int)setMinAutoSize(float)setMinValue(int)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setProgress(int)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRenderPercentageOnTop(boolean)setRenderValueOnTop(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShiftMillimeters(float)setShiftMillimeters(int)setShiftText(int)setShouldCalcPreferredSize(boolean)setShouldLocalize(boolean)setShowEvenIfBlank(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextPosition(int)setTextSelectionEnabled(boolean)setThumbImage(Image)setTickerEnabled(boolean)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVertical(boolean)setVerticalAlignment(int)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)shouldTickerStart()startEditingAsync()startTicker()startTicker(long, boolean)stopEditing(Runnable)stopTicker()stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)createInfinite()")); index.put("com.codename1.ui.Stroke", splitMembers("equals(Object)getCapStyle()getJoinStyle()getLineWidth()getMiterLimit()hashCode()setCapStyle(int)setJoinStyle(int)setLineWidth(float)setMiterLimit(float)setStroke(Stroke)toString()")); @@ -3509,6 +3726,9 @@ private static void fillMethodIndex21(Map index) { index.put("com.codename1.ui.UIFragment.DefaultComponentFactory", splitMembers("newComponent(Element)newConstraint(Container, Element, Component, Element)")); index.put("com.codename1.ui.URLImage", splitMembers("addActionListener(ActionListener)animate()applyMask(Object)applyMask(Object, int, int)applyMaskAutoScale(Object)asyncLock(Image)createMask()dispose()fetch()fill(int, int)fireChangedEvent()flipHorizontally(boolean)flipVertically(boolean)getGraphics()getHeight()getImage()getImageData()getImageName()getRGB()getRGB(int[])getRGBCached()getSVGDocument()getWidth()isAnimation()isDisposed()isLocked()isOpaque()isSVG()lock()mirror()modifyAlpha(byte)modifyAlpha(byte, int)modifyAlphaWithTranslucency(byte)removeActionListener(ActionListener)requiresDrawImage()rotate(int)rotate180Degrees(boolean)rotate270Degrees(boolean)rotate90Degrees(boolean)scale(int, int)scaled(int, int)scaledEncoded(int, int)scaledHeight(int)scaledLargerRatio(int, int)scaledSmallerRatio(int, int)scaledWidth(int)setImageName(String)subImage(int, int, int, int, boolean)toRGB(RGBImage, int, int, int, int, int, int)unlock()createCachedImage(String, String, Image, int)createMaskAdapter(Image)createMaskAdapter(Object)createToFileSystem(EncodedImage, String, String, ImageAdapter)createToStorage(EncodedImage, String, String)createToStorage(EncodedImage, String, String, ImageAdapter)createToStorage(EncodedImage, String, String, ImageAdapter, RequestDecorator)getDefaultRequestDecorator()getExceptionHandler()setDefaultBearerToken(String)setDefaultRequestDecorator(RequestDecorator)setExceptionHandler(ErrorCallback)")); index.put("com.codename1.ui.URLImage.ErrorCallback", splitMembers("onError(URLImage, Exception)")); + } + + private static void fillMethodIndex23(Map index) { index.put("com.codename1.ui.URLImage.ImageAdapter", splitMembers("adaptImage(EncodedImage, EncodedImage)isAsyncAdapter()")); index.put("com.codename1.ui.URLImage.RequestDecorator", splitMembers("decorate(ConnectionRequest)")); index.put("com.codename1.ui.VirtualInputDevice", splitMembers("")); @@ -3546,13 +3766,10 @@ private static void fillMethodIndex21(Map index) { index.put("com.codename1.ui.css.CSSThemeCompiler", splitMembers("compile(String, MutableResource, String)")); index.put("com.codename1.ui.css.CSSThemeCompiler.CSSSyntaxException", splitMembers("")); index.put("com.codename1.ui.editor.CodePureEditor", splitMembers("cmd(String, String)getView()query(String, String)")); - index.put("com.codename1.ui.editor.CodeView", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)deleteSurroundingText(int, int)drop(Component, int, int)finishComposing()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getConfig()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLanguage()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()inputFocusGained()inputFocusLost()insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCompletionEnabled(boolean)setComponentState(Object)setComposingText(String, int)setCursor(int)setDiagnostics(List)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLanguage(String)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setShowLineNumbers(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTabSize(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTheme(String)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)showCompletions(int, List)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); - } - - private static void fillMethodIndex22(Map index) { + index.put("com.codename1.ui.editor.CodeView", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)copySelection()createStyleAnimation(String, int)cutSelection()deleteBackward()deleteSurroundingText(int, int)drop(Component, int, int)finishComposing()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getConfig()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLanguage()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()inputFocusGained()inputFocusLost()insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pasteClipboard()performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setCompletionEnabled(boolean)setComponentState(Object)setComposingText(String, int)setCursor(int)setDiagnostics(List)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLanguage(String)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setProtectedRegionMarkers(String, String)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setShowLineNumbers(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTabSize(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTheme(String)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)showCompletions(int, List)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); index.put("com.codename1.ui.editor.EditorDocument", splitMembers("charAt(int)clamp(int)columnOfOffset(int)delete(int, int)getLineCount()getLineEnd(int)getLineStart(int)getLineText(int)getText()insert(int, String)length()lineOfOffset(int)setText(String)substring(int, int)normalizeText(String)")); index.put("com.codename1.ui.editor.EditorHost", splitMembers("editorChanged()fireEditorEvent(String, String)isTextInputSupported()startTextInput(TextInputClient, TextInputConfig)stopTextInput(Object)updateTextInputState(Object, TextInputState)")); - index.put("com.codename1.ui.editor.EditorView", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)deleteSurroundingText(int, int)drop(Component, int, int)finishComposing()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getConfig()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()inputFocusGained()inputFocusLost()insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setComposingText(String, int)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); + index.put("com.codename1.ui.editor.EditorView", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)copySelection()createStyleAnimation(String, int)cutSelection()deleteBackward()deleteSurroundingText(int, int)drop(Component, int, int)finishComposing()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getConfig()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()inputFocusGained()inputFocusLost()insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pasteClipboard()performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setComposingText(String, int)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); index.put("com.codename1.ui.editor.HtmlImporter", splitMembers("parse(String)")); index.put("com.codename1.ui.editor.HtmlImporter.Result", splitMembers("getBlocks()getImageSources()getLinks()getStyles()getText()hasBlockContent()")); index.put("com.codename1.ui.editor.HtmlSerializer", splitMembers("serialize(EditorDocument, InlineStyles, RichBlocks, List, List)")); @@ -3567,7 +3784,7 @@ private static void fillMethodIndex22(Map index) { index.put("com.codename1.ui.editor.RichRunPainter", splitMembers("fontFor(int, boolean, boolean)getBaseSizePx()paintRun(Graphics, String, TextStyle, Font, int, int, int)runFont(int, TextStyle)runPx(int, TextStyle)setBaseFont(Font)setBaseSizePx(int)setTextColor(int)headingScale(int)isHeading(int)sizeLevelScale(int)")); index.put("com.codename1.ui.editor.RichTextImporter", splitMembers("convert(String, RichTextFormat, RichTextFormat)fromHtml(String, RichTextFormat)parse(String, RichTextFormat)toHtml(String, RichTextFormat)")); index.put("com.codename1.ui.editor.RichTextSerializer", splitMembers("serialize(EditorDocument, InlineStyles, RichBlocks, List, List, RichTextFormat)")); - index.put("com.codename1.ui.editor.RichView", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)applyLink(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)createStyleAnimation(String, int)deleteSurroundingText(int, int)drop(Component, int, int)finishComposing()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBlocks()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getConfig()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getImageSources()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLinkRuns()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()importContent(String, List, List, List, List, List)indentBlocks()inputFocusGained()inputFocusLost()insertContent(String, List, List, List, List, List, boolean)insertImageObject(Image, String)insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)outdentBlocks()paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)queryState(String)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeFormat()removeLinkStyle()removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setAlign(int)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockFormat(String)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setComposingText(String, int)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setFontSizeLevel(int)setForeColor(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHighlight(int)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setList(int)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPlaceholder(String)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()toggleBold()toggleItalic()toggleStrike()toggleUnderline()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); + index.put("com.codename1.ui.editor.RichView", splitMembers("accessibilityChanged()accessibilityChanged(int)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()announceForAccessibility(String)applyLink(String)bindProperty(String, BindTarget)blocksSideSwipe()blur()clearClientProperties()commitText(String)contains(int, int)containsOrOwns(int, int)copySelection()createStyleAnimation(String, int)cutSelection()deleteBackward()deleteSurroundingText(int, int)drop(Component, int, int)finishComposing()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBlocks()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getCaretOffset()getCaretRect()getClientProperty(String)getCloudBoundProperty()getCloudDestinationProperty()getComponentForm()getComponentState()getConfig()getCursor()getDirtyRegion()getDisabledStyle()getDocument()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEditingState()getHeight()getImageSources()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLinkRuns()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSelectionEnd()getSelectionStart()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getText()getTextLength()getTextRange(int, int)getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUndoManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()hasSelection()importContent(String, List, List, List, List, List)indentBlocks()inputFocusGained()inputFocusLost()insertContent(String, List, List, List, List, List, boolean)insertImageObject(Image, String)insertText(String)isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditableState()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()keyPressed(int)keyReleased(int)keyRepeated(int)longPointerPress(int, int)moveCaret(int, boolean)offsetAtPoint(int, int)onEditorAction(int)onKeyCommand(int, int)outdentBlocks()paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pasteClipboard()performRedo()performUndo()pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)queryState(String)rectForOffset(int)refreshTheme()refreshTheme(boolean)remove()removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeFormat()removeLinkStyle()removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replaceRange(int, int, String)requestFocus()respondsToPointerEvents()scrollRectToVisible(int, int, int, int, Component)selectAll()selectionRects(int, int)setAccessibilityText(String)setAlign(int)setAlwaysTensile(boolean)setBackgroundColor(int)setBlockFormat(String)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setComposingText(String, int)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditableState(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setFontSizeDips(int)setFontSizeLevel(int)setForeColor(int)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHighlight(int)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setList(int)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPlaceholder(String)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setScrollAnimationSpeed(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setSelectCommandText(String)setSelectedStyle(Style)setSelectionColor(int)setSelectionRange(int, int)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setText(String)setTextColor(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()toggleBold()toggleItalic()toggleStrike()toggleUnderline()unbindProperty(String, BindTarget)visibleBoundsContains(int, int)")); index.put("com.codename1.ui.editor.SyntaxHighlightResult", splitMembers("")); index.put("com.codename1.ui.editor.SyntaxHighlighter", splitMembers("tokenize(String, int)")); index.put("com.codename1.ui.editor.SyntaxToken", splitMembers("")); @@ -3576,6 +3793,9 @@ private static void fillMethodIndex22(Map index) { index.put("com.codename1.ui.editor.Tokenizer", splitMembers("tokenize(String, int)")); index.put("com.codename1.ui.editor.UndoManager", splitMembers("breakRun()canRedo()canUndo()clear()record(int, String, String)redo(EditorDocument)undo(EditorDocument)")); index.put("com.codename1.ui.events.ActionEvent", splitMembers("consume()getActualComponent()getCommand()getComponent()getDraggedComponent()getDropTarget()getEventType()getKeyEvent()getPointerEvent()getProgress()getSource()getX()getY()isConsumed()isLongEvent()isPointerPressedDuringDrag()setPointerEvent(PointerEvent)setPointerPressedDuringDrag(boolean)")); + } + + private static void fillMethodIndex24(Map index) { index.put("com.codename1.ui.events.ActionEvent.Type", splitMembers("")); index.put("com.codename1.ui.events.ActionListener", splitMembers("actionPerformed(ActionEvent)")); index.put("com.codename1.ui.events.ActionSource", splitMembers("addActionListener(ActionListener)removeActionListener(ActionListener)")); @@ -3614,9 +3834,6 @@ private static void fillMethodIndex22(Map index) { index.put("com.codename1.ui.html.HTMLParser", splitMembers("addCharEntitiesRange(String[], int)addCharEntity(String, int)isCaseSensitive()setCaseSensitive(boolean)setIncludeWhitespacesBetweenTags(boolean)setParserCallback(ParserCallback)")); index.put("com.codename1.ui.html.HTMLUtils", splitMembers("convertCharEntity(String, boolean, Hashtable)convertHTMLCharEntity(String)convertXMLCharEntity(String)encodeString(String)")); index.put("com.codename1.ui.html.IOCallback", splitMembers("")); - } - - private static void fillMethodIndex23(Map index) { index.put("com.codename1.ui.layouts.BorderLayout", splitMembers("addLayoutComponent(Object, Component, Container)cloneConstraint(Object)defineLandscapeSwap(String, String)equals(Object)getCenter()getCenterBehavior()getComponentConstraint(Component)getEast()getLandscapeSwap(String)getNorth()getOverlay()getPreferredSize(Container)getSouth()getWest()hashCode()isAbsoluteCenter()isConstraintTracking()isOverlapSupported()isScaleEdges()layoutContainer(Container)obscuresPotential(Container)overridesTabIndices(Container)removeLayoutComponent(Component)setAbsoluteCenter(boolean)setCenterBehavior(int)setScaleEdges(boolean)toString()updateTabIndices(Container, int)absolute()center()center(Component)centerAbsolute(Component)centerAbsoluteEastWest(Component, Component, Component)centerCenter(Component)centerCenterEastWest(Component, Component, Component)centerEastWest(Component, Component, Component)centerTotalBelow(Component)centerTotalBelowEastWest(Component, Component, Component)east(Component)north(Component)south(Component)totalBelow()west(Component)")); index.put("com.codename1.ui.layouts.BoxLayout", splitMembers("addLayoutComponent(Object, Component, Container)cloneConstraint(Object)equals(Object)getAlign()getAxis()getComponentConstraint(Component)getPreferredSize(Container)hashCode()isConstraintTracking()isOverlapSupported()layoutContainer(Container)obscuresPotential(Container)overridesTabIndices(Container)removeLayoutComponent(Component)setAlign(int)toString()updateTabIndices(Container, int)encloseX(Component[]...)encloseXCenter(Component[]...)encloseXNoGrow(Component[]...)encloseXRight(Component[]...)encloseY(Component[]...)encloseYBottom(Component[]...)encloseYBottomLast(Component[]...)encloseYCenter(Component[]...)x()xCenter()xRight()y()yBottom()yCenter()yLast()")); index.put("com.codename1.ui.layouts.CoordinateLayout", splitMembers("addLayoutComponent(Object, Component, Container)cloneConstraint(Object)equals(Object)getComponentConstraint(Component)getPreferredSize(Container)hashCode()isConstraintTracking()isOverlapSupported()layoutContainer(Container)obscuresPotential(Container)overridesTabIndices(Container)removeLayoutComponent(Component)updateTabIndices(Container, int)")); @@ -3643,6 +3860,9 @@ private static void fillMethodIndex23(Map index) { index.put("com.codename1.ui.layouts.mig.LayoutCallback", splitMembers("correctBounds(ComponentWrapper)getPosition(ComponentWrapper)getSize(ComponentWrapper)")); index.put("com.codename1.ui.layouts.mig.LayoutUtil", splitMembers("getDesignTimeEmptySize()getGlobalDebugMillis()getSerializedObject(Object)getSizeSafe(int[], int)getVersion()isDesignTime(ContainerWrapper)isLeftToRight(LC, ContainerWrapper)setDesignTime(ContainerWrapper, boolean)setDesignTimeEmptySize(int)setGlobalDebugMillis(int)setSerializedObject(Object, Object)")); index.put("com.codename1.ui.layouts.mig.LinkHandler", splitMembers("clearBounds(Object, String)clearWeakReferencesNow()getValue(Object, String, int)setBounds(Object, String, int, int, int, int)")); + } + + private static void fillMethodIndex25(Map index) { index.put("com.codename1.ui.layouts.mig.MigLayout", splitMembers("addLayoutCallback(LayoutCallback)addLayoutComponent(Component, Object)addLayoutComponent(Object, Component, Container)cloneConstraint(Object)equals(Object)getColumnConstraints()getComponentConstraint(Component)getComponentConstraints(Component)getConstraintMap()getLayoutAlignmentX(Container)getLayoutAlignmentY(Container)getLayoutConstraints()getPreferredSize(Container)getRowConstraints()hashCode()invalidateLayout(Container)isConstraintTracking()isManagingComponent(Component)isOverlapSupported()layoutContainer(Container)maximumLayoutSize(Container)minimumLayoutSize(Container)obscuresPotential(Container)overridesTabIndices(Container)preferredLayoutSize(Container)removeLayoutCallback(LayoutCallback)removeLayoutComponent(Component)setColumnConstraints(Object)setComponentConstraints(Component, Object)setConstraintMap(Map)setLayoutConstraints(Object)setRowConstraints(Object)updateTabIndices(Container, int)findType(Class, Component)")); index.put("com.codename1.ui.layouts.mig.PlatformDefaults", splitMembers("invalidate()getButtonOrder()getCurrentPlatform()getDefaultDPI()getDefaultHorizontalUnit()getDefaultRowAlignmentBaseline()getDefaultVerticalUnit()getDefaultVisualPadding(String)getDialogInsets(int)getGapProvider()getGridGapX()getGridGapY()getHorizontalScaleFactor()getLabelAlignPercentage()getLogicalPixelBase()getMinimumButtonWidth()getModCount()getPanelInsets(int)getPlatform()getPlatformDPI(int)getUnitValueX(String)getUnitValueY(String)getVerticalScaleFactor()setButtonOrder(String)setDefaultDPI(Integer)setDefaultHorizontalUnit(int)setDefaultRowAlignmentBaseline(boolean)setDefaultVerticalUnit(int)setDefaultVisualPadding(String, int[])setDialogInsets(UnitValue, UnitValue, UnitValue, UnitValue)setGapProvider(InCellGapProvider)setGridCellGap(UnitValue, UnitValue)setHorizontalScaleFactor(Float)setIndentGap(UnitValue, UnitValue)setLogicalPixelBase(int)setMinimumButtonWidth(UnitValue)setPanelInsets(UnitValue, UnitValue, UnitValue, UnitValue)setParagraphGap(UnitValue, UnitValue)setPlatform(int)setRelatedGap(UnitValue, UnitValue)setUnitValue(String[], UnitValue, UnitValue)setUnrelatedGap(UnitValue, UnitValue)setVerticalScaleFactor(Float)")); index.put("com.codename1.ui.layouts.mig.UnitConverter", splitMembers("convertToPixels(float, String, boolean, float, ContainerWrapper, ComponentWrapper)")); @@ -3681,9 +3901,6 @@ private static void fillMethodIndex23(Map index) { index.put("com.codename1.ui.plaf.StyleParser.StyleInfo", splitMembers("getAlignment()getAlignmentAsString()getBgColor()getBgImage()getBgType()getBgTypeAsString()getBorder()getFgColor()getFont()getMargin()getOpacity()getPadding()getTextDecoration()getTextDecorationAsString()getTransparency()setAlignment(int)setAlignment(String)setBgColor(String)setBgImage(String)setBgType(Integer)setBgType(String)setBorder(String)setFgColor(String)setFont(String)setFontName(String)setFontSize(String)setMargin(String)setOpacity(String)setPadding(String)setTransparency(String)toStyleString()")); index.put("com.codename1.ui.plaf.UIManager", splitMembers("addThemeProps(Hashtable)addThemeRefreshListener(ActionListener)getBundle()getComponentCustomStyle(String, String)getComponentSelectedStyle(String)getComponentStyle(String)getIconUIIDFor(String)getLookAndFeel()getResourceBundle()getThemeConstant(String, int)getThemeConstant(String, String)getThemeImageConstant(String)getThemeMaskConstant(String)getThemeName()isThemeConstant(String)isThemeConstant(String, boolean)isUseLargerTextScale()localize(String, String)parseComponentCustomStyle(Resources, String, String, String, String[]...)parseComponentSelectedStyle(Resources, String, String, String[]...)parseComponentStyle(Resources, String, String, String[]...)refreshTheme()removeThemeRefreshListener(ActionListener)setBundle(Map)setComponentSelectedStyle(String, Style)setComponentStyle(String, Style)setComponentStyle(String, Style, String)setLookAndFeel(LookAndFeel)setResourceBundle(Hashtable)setThemeProps(Hashtable)setUseLargerTextScale(boolean)wasThemeInstalled()zoomFonts(float)createInstance()getInstance()initFirstTheme(String)initNamedTheme(String, String)")); index.put("com.codename1.ui.scene.Bounds", splitMembers("getDepth()getHeight()getMinX()getMinY()getMinZ()getWidth()setDepth(double)setHeight(double)setMinX(double)setMinY(double)setMinZ(double)setWidth(double)")); - } - - private static void fillMethodIndex24(Map index) { index.put("com.codename1.ui.scene.Camera", splitMembers("getTransform()")); index.put("com.codename1.ui.scene.Node", splitMembers("add(Node)addTags(String[]...)contains(int, int)findNodesWithTag(String)getBoundsInScene(Rectangle2D)getChildAt(int)getChildCount()getChildNodes()getLocalToParentTransform()getLocalToSceneTransform()getLocalToScreenTransform()getRenderer()getScene()getStyle()hasChildren()hasTag(String)isNeedsLayout()remove(Node)removeAll()removeTags(String[]...)render(Graphics)renderChildren(Graphics)setNeedsLayout(boolean)setRenderAsImage(boolean)setRenderer(NodePainter)setStyle(Style)")); index.put("com.codename1.ui.scene.NodePainter", splitMembers("paint(Graphics, Rectangle, Node)")); @@ -3710,6 +3927,9 @@ private static void fillMethodIndex24(Map index) { index.put("com.codename1.ui.tree.Tree", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLeafListener(ActionListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()collapsePath(Object[]...)contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)expandPath(Object[]...)expandPath(boolean, Object[]...)findDropTargetAt(int, int)findFirstFocusable()findNodeComponent(Object)findNodeComponent(Object, Component)flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getModel()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getParentComponent(Component)getParentNode(Component)getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedItem()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTooltip()getTreeState()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isMultilineMode()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshNode(Component)refreshTheme()refreshTheme(boolean)remove()removeAll()removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLeafListener(ActionListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setModel(TreeModel)setMultilineMode(boolean)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTraversable(boolean)setTreeState(TreeState)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)setFolderIcon(Image)setFolderOpenIcon(Image)setNodeIcon(Image)")); index.put("com.codename1.ui.tree.Tree.TreeState", splitMembers("")); index.put("com.codename1.ui.tree.TreeModel", splitMembers("getChildren(Object)isLeaf(Object)")); + } + + private static void fillMethodIndex26(Map index) { index.put("com.codename1.ui.util.Effects", splitMembers("dropshadow(Image, int, float)dropshadow(Image, int, float, int, int)gaussianBlurImage(Image, float)growShrink(Component, int)isGaussianBlurSupported()reflectionImage(Image)reflectionImage(Image, float, int)reflectionImage(Image, float, int, int)squareShadow(int, int, int, float)verticalPerspective(Image, float, float, float)")); index.put("com.codename1.ui.util.EmbeddedContainer", splitMembers("accessibilityChanged()accessibilityChanged(int)add(Component)add(Image)add(String)add(Object, Component)add(Object, String)add(Object, Image)addAll(Component[]...)addComponent(Component)addComponent(int, Component)addComponent(int, Object, Component)addContextMenuListener(ActionListener)addDragFinishedListener(ActionListener)addDragOverListener(ActionListener)addDropListener(ActionListener)addFocusListener(FocusListener)addLongPressListener(ActionListener)addMouseWheelListener(ActionListener)addPointerDraggedListener(ActionListener)addPointerPressedListener(ActionListener)addPointerReleasedListener(ActionListener)addPullToRefresh(Runnable)addScrollListener(ScrollListener)addStateChangeListener(ActionListener)addStylusListener(ActionListener)animate()animateHierarchy(int)animateHierarchyAndWait(int)animateHierarchyFade(int, int)animateHierarchyFadeAndWait(int, int)animateLayout(int)animateLayoutAndWait(int)animateLayoutFade(int, int)animateLayoutFadeAndWait(int, int)animateUnlayout(int, int, Runnable)animateUnlayoutAndWait(int, int)announceForAccessibility(String)applyRTL(boolean)bindProperty(String, BindTarget)blocksSideSwipe()clearClientProperties()contains(Component)contains(int, int)containsOrOwns(int, int)createAnimateHierarchy(int)createAnimateHierarchyFade(int, int)createAnimateLayout(int)createAnimateLayoutFade(int, int)createAnimateLayoutFadeAndWait(int, int)createAnimateUnlayout(int, int, Runnable)createReplaceTransition(Component, Component, Transition)createStyleAnimation(String, int)drop(Component, int, int)findDropTargetAt(int, int)findFirstFocusable()flushReplace()forceRevalidate()getAbsoluteX()getAbsoluteY()getAccessibilityNode()getAccessibilityText()getAllStyles()getAnimationManager()getBaseline(int, int)getBaselineResizeBehavior()getBindablePropertyNames()getBindablePropertyTypes()getBottomGap()getBoundPropertyValue(String)getBounds(Rectangle)getChildrenAsList(boolean)getClientProperty(String)getClosestComponentTo(int, int)getCloudBoundProperty()getCloudDestinationProperty()getComponentAt(int)getComponentAt(int, int)getComponentCount()getComponentForm()getComponentIndex(Component)getComponentState()getCursor()getDirtyRegion()getDisabledStyle()getDragTransparency()getDraggedx()getDraggedy()getEditingDelegate()getEmbed()getHeight()getInlineAllStyles()getInlineDisabledStyles()getInlinePressedStyles()getInlineSelectedStyles()getInlineStylesTheme()getInlineUnselectedStyles()getInnerHeight()getInnerPreferredH()getInnerPreferredW()getInnerWidth()getInnerX()getInnerY()getLabelForComponent()getLayout()getLayoutHeight()getLayoutWidth()getLeadComponent()getLeadParent()getName()getNativeOverlay()getNextFocusDown()getNextFocusLeft()getNextFocusRight()getNextFocusUp()getOuterHeight()getOuterPreferredH()getOuterPreferredW()getOuterWidth()getOuterX()getOuterY()getOwner()getParent()getPreferredH()getPreferredSize()getPreferredSizeStr()getPreferredTabIndex()getPreferredW()getPressedStyle()getPropertyNames()getPropertyTypeNames()getPropertyTypes()getPropertyValue(String)getResponderAt(int, int)getSafeAreaRoot()getSameHeight()getSameWidth()getScrollAnimationSpeed()getScrollDimension()getScrollIncrement()getScrollOpacity()getScrollOpacityChangeSpeed()getScrollX()getScrollY()getScrollable()getSelectCommandText()getSelectedRect()getSelectedStyle()getSemantics()getSideGap()getStyle()getTabIndex()getTensileLength()getTextSelectionSupport()getTooltip()getUIID()getUIManager()getUnselectedStyle()getVisibleBounds(Rectangle)getWidth()getX()getY()growShrink(int)handlesInput()hasFixedPreferredSize()hasFocus()invalidate()isAlwaysTensile()isBlockLead()isCellRenderer()isChildOf(Container)isDraggable()isDropTarget()isEditable()isEditing()isEnabled()isFlatten()isFocusable()isGrabsPointerEvents()isHScrollThumbGrabbed()isHScrollThumbHover()isHidden()isHidden(boolean)isHideInLandscape()isHideInPortrait()isIgnorePointerEvents()isOpaque()isOwnedBy(Component)isPinchBlocksDragAndDrop()isRTL()isRippleEffect()isSafeArea()isSafeAreaRoot()isScrollVisible()isScrollableX()isScrollableY()isSmoothScrolling()isSnapToGrid()isSurface()isTactileTouch()isTensileDragEnabled()isTraversable()isVScrollThumbGrabbed()isVScrollThumbHover()isVisible()iterator()iterator(boolean)keyPressed(int)keyReleased(int)keyRepeated(int)layoutContainer()longPointerPress(int, int)morph(Component, Component, int, Runnable)morphAndWait(Component, Component, int)paint(Graphics)paintBackgrounds(Graphics)paintComponent(Graphics)paintComponent(Graphics, boolean)paintComponentBackground(Graphics)paintIntersectingComponentsAbove(Graphics)paintLock(boolean)paintLockRelease()paintRippleOverlay(Graphics, int, int, int)paintShadows(Graphics, int, int)pointerDragged(int, int)pointerDragged(int[], int[])pointerHover(int[], int[])pointerHoverPressed(int[], int[])pointerHoverReleased(int[], int[])pointerPressed(int, int)pointerPressed(int[], int[])pointerReleased(int, int)pointerReleased(int[], int[])putClientProperty(String, Object)refreshTheme()refreshTheme(boolean)remove()removeAll()removeComponent(Component)removeContextMenuListener(ActionListener)removeDragFinishedListener(ActionListener)removeDragOverListener(ActionListener)removeDropListener(ActionListener)removeFocusListener(FocusListener)removeLongPressListener(ActionListener)removeMouseWheelListener(ActionListener)removePointerDraggedListener(ActionListener)removePointerPressedListener(ActionListener)removePointerReleasedListener(ActionListener)removeScrollListener(ScrollListener)removeStateChangeListener(ActionListener)removeStylusListener(ActionListener)repaint()repaint(int, int, int, int)replace(Component, Component, Transition)replace(Component, Component, Transition, Runnable, int)replaceAndWait(Component, Component, Transition)replaceAndWait(Component, Component, Transition, int)replaceAndWait(Component, Component, Transition, boolean)requestFocus()respondsToPointerEvents()revalidate()revalidateLater()revalidateWithAnimationSafety()scrollComponentToVisible(Component)scrollRectToVisible(int, int, int, int, Component)setAccessibilityText(String)setAlwaysTensile(boolean)setBlockLead(boolean)setBoundPropertyValue(String, Object)setCellRenderer(boolean)setCloudBoundProperty(String)setCloudDestinationProperty(String)setComponentState(Object)setCursor(int)setDirtyRegion(Rectangle)setDisabledStyle(Style)setDragTransparency(byte)setDraggable(boolean)setDropTarget(boolean)setEditingDelegate(Editable)setEmbed(String)setEnabled(boolean)setFlatten(boolean)setFocus(boolean)setFocusable(boolean)setGrabsPointerEvents(boolean)setHandlesInput(boolean)setHeight(int)setHidden(boolean)setHidden(boolean, boolean)setHideInLandscape(boolean)setHideInPortrait(boolean)setHorizontalScrollBounds(int, int, int, int, int, int, int, int)setIgnorePointerEvents(boolean)setInlineAllStyles(String)setInlineDisabledStyles(String)setInlinePressedStyles(String)setInlineSelectedStyles(String)setInlineStylesTheme(Resources)setInlineUnselectedStyles(String)setIsScrollVisible(boolean)setLabelForComponent(Label)setLayout(Layout)setLeadComponent(Component)setName(String)setNextFocusDown(Component)setNextFocusLeft(Component)setNextFocusRight(Component)setNextFocusUp(Component)setOpaque(boolean)setOwner(Component)setPinchBlocksDragAndDrop(boolean)setPreferredH(int)setPreferredSize(Dimension)setPreferredSizeStr(String)setPreferredTabIndex(int)setPreferredW(int)setPressedStyle(Style)setPropertyValue(String, Object)setPullToRefresh(Runnable)setRTL(boolean)setRippleEffect(boolean)setSafeArea(boolean)setSafeAreaRoot(boolean)setScrollAnimationSpeed(int)setScrollIncrement(int)setScrollOpacityChangeSpeed(int)setScrollSize(Dimension)setScrollVisible(boolean)setScrollable(boolean)setScrollableX(boolean)setScrollableY(boolean)setSelectCommandText(String)setSelectedStyle(Style)setShouldCalcPreferredSize(boolean)setSize(Dimension)setSmoothScrolling(boolean)setSnapToGrid(boolean)setTabIndex(int)setTactileTouch(boolean)setTensileDragEnabled(boolean)setTensileLength(int)setTooltip(String)setTraversable(boolean)setUIID(String)setUIID(String, String)setUIManager(UIManager)setUnselectedStyle(Style)setVerticalScrollBounds(int, int, int, int, int, int, int, int)setVisible(boolean)setWidth(int)setX(int)setY(int)startEditingAsync()stopEditing(Runnable)stripMarginAndPadding()styleChanged(String, Style)toImage()toString()unbindProperty(String, BindTarget)updateTabIndices(int)visibleBoundsContains(int, int)")); index.put("com.codename1.ui.util.EventDispatcher", splitMembers("addListener(Object)fireActionEvent(ActionEvent)fireBindTargetChange(Component, String, Object, Object)fireDataChangeEvent(int, int)fireFocus(Component)fireScrollEvent(int, int, int, int)fireSelectionEvent(int, int)fireStyleChangeEvent(String, Style)getListenerCollection()getListenerVector()hasListeners()isBlocking()removeListener(Object)setBlocking(boolean)setFireStyleEventsOnNonEDT(boolean)")); @@ -3748,9 +3968,6 @@ private static void fillMethodIndex24(Map index) { index.put("com.codename1.util.EasyThread.ErrorListener", splitMembers("")); index.put("com.codename1.util.FailureCallback", splitMembers("")); index.put("com.codename1.util.LazyValue", splitMembers("")); - } - - private static void fillMethodIndex25(Map index) { index.put("com.codename1.util.MathUtil", splitMembers("")); index.put("com.codename1.util.OnComplete", splitMembers("")); index.put("com.codename1.util.RunnableWithResult", splitMembers("")); @@ -3777,6 +3994,9 @@ private static void fillMethodIndex25(Map index) { index.put("com.codename1.util.regex.StringReader", splitMembers("")); index.put("com.codename1.vr.HeadTracker", splitMembers("")); index.put("com.codename1.vr.Media360View", splitMembers("")); + } + + private static void fillMethodIndex27(Map index) { index.put("com.codename1.vr.OrientationFilter", splitMembers("")); index.put("com.codename1.vr.TextureSource", splitMembers("")); index.put("com.codename1.vr.VRCameraRig", splitMembers("")); @@ -3785,6 +4005,7 @@ private static void fillMethodIndex25(Map index) { index.put("com.codename1.vr.VRSettings", splitMembers("")); index.put("com.codename1.vr.VRView", splitMembers("")); index.put("com.codename1.wearable.WearableConnection", splitMembers("")); + index.put("com.codename1.wearable.WearableConnection.DroppedDeliveryHandler", splitMembers("")); index.put("com.codename1.wearable.WearableDataListener", splitMembers("")); index.put("com.codename1.wearable.WearableMessage", splitMembers("")); index.put("com.codename1.wearable.WearableMessageListener", splitMembers("")); @@ -3815,9 +4036,6 @@ private static void fillMethodIndex25(Map index) { index.put("java.io.FileNotFoundException", splitMembers("")); index.put("java.io.Flushable", splitMembers("")); index.put("java.io.IOException", splitMembers("")); - } - - private static void fillMethodIndex26(Map index) { index.put("java.io.InputStream", splitMembers("")); index.put("java.io.InputStreamReader", splitMembers("")); index.put("java.io.InterruptedIOException", splitMembers("")); @@ -3843,6 +4061,9 @@ private static void fillMethodIndex26(Map index) { index.put("java.lang.Character", splitMembers("")); index.put("java.lang.Class", splitMembers("")); index.put("java.lang.ClassCastException", splitMembers("")); + } + + private static void fillMethodIndex28(Map index) { index.put("java.lang.ClassLoader", splitMembers("")); index.put("java.lang.ClassNotFoundException", splitMembers("")); index.put("java.lang.CloneNotSupportedException", splitMembers("")); @@ -3882,9 +4103,6 @@ private static void fillMethodIndex26(Map index) { index.put("java.lang.SafeVarargs", splitMembers("")); index.put("java.lang.SecurityException", splitMembers("")); index.put("java.lang.Short", splitMembers("")); - } - - private static void fillMethodIndex27(Map index) { index.put("java.lang.StackTraceElement", splitMembers("")); index.put("java.lang.String", splitMembers("")); index.put("java.lang.StringBuffer", splitMembers("")); @@ -3910,6 +4128,9 @@ private static void fillMethodIndex27(Map index) { index.put("java.text.DateFormat", splitMembers("")); index.put("java.text.DateFormatSymbols", splitMembers("")); index.put("java.text.Format", splitMembers("")); + } + + private static void fillMethodIndex29(Map index) { index.put("java.text.ParseException", splitMembers("")); index.put("java.text.SimpleDateFormat", splitMembers("")); index.put("java.time.Clock", splitMembers("")); @@ -3949,9 +4170,6 @@ private static void fillMethodIndex27(Map index) { index.put("java.util.Dictionary", splitMembers("")); index.put("java.util.EmptyStackException", splitMembers("")); index.put("java.util.Enumeration", splitMembers("")); - } - - private static void fillMethodIndex28(Map index) { index.put("java.util.EventListener", splitMembers("")); index.put("java.util.HashMap", splitMembers("")); index.put("java.util.HashSet", splitMembers("")); @@ -3977,6 +4195,9 @@ private static void fillMethodIndex28(Map index) { index.put("java.util.Random", splitMembers("")); index.put("java.util.RandomAccess", splitMembers("")); index.put("java.util.Set", splitMembers("")); + } + + private static void fillMethodIndex30(Map index) { index.put("java.util.SortedMap", splitMembers("")); index.put("java.util.SortedSet", splitMembers("")); index.put("java.util.Stack", splitMembers("")); @@ -4037,6 +4258,8 @@ private static Map buildFieldIndex() { fillFieldIndex26(index); fillFieldIndex27(index); fillFieldIndex28(index); + fillFieldIndex29(index); + fillFieldIndex30(index); return index; } @@ -4122,24 +4345,31 @@ private static void fillFieldIndex1(Map index) { index.put("com.codename1.ai.language.Translator", splitMembers("")); index.put("com.codename1.ai.language.Translator.Session", splitMembers("")); index.put("com.codename1.ai.vision.Barcode", splitMembers("")); + index.put("com.codename1.ai.vision.BarcodeFormat", splitMembers("")); index.put("com.codename1.ai.vision.BarcodeScanner", splitMembers("")); + index.put("com.codename1.ai.vision.CodeScanner", splitMembers("")); + index.put("com.codename1.ai.vision.CodeScannerOptions", splitMembers("")); index.put("com.codename1.ai.vision.DocumentScanResult", splitMembers("")); index.put("com.codename1.ai.vision.DocumentScanner", splitMembers("")); index.put("com.codename1.ai.vision.Face", splitMembers("")); index.put("com.codename1.ai.vision.FaceDetector", splitMembers("")); + index.put("com.codename1.ai.vision.FaceLandmarks", splitMembers("")); index.put("com.codename1.ai.vision.ImageLabel", splitMembers("")); index.put("com.codename1.ai.vision.ImageLabeler", splitMembers("")); index.put("com.codename1.ai.vision.Pose", splitMembers("")); index.put("com.codename1.ai.vision.Pose.Landmark", splitMembers("")); index.put("com.codename1.ai.vision.PoseDetector", splitMembers("")); + index.put("com.codename1.ai.vision.PoseLandmarks", splitMembers("")); index.put("com.codename1.ai.vision.SegmentationMask", splitMembers("")); index.put("com.codename1.ai.vision.SelfieSegmenter", splitMembers("")); index.put("com.codename1.ai.vision.TextRecognitionResult", splitMembers("")); index.put("com.codename1.ai.vision.TextRecognitionResult.TextBlock", splitMembers("")); index.put("com.codename1.ai.vision.TextRecognizer", splitMembers("")); + index.put("com.codename1.ai.vision.TextScript", splitMembers("")); index.put("com.codename1.ai.vision.VisionAnalyzer", splitMembers("")); index.put("com.codename1.ai.vision.VisionBackend", splitMembers("")); index.put("com.codename1.ai.vision.VisionBackends", splitMembers("")); + index.put("com.codename1.ai.vision.VisionCameraView", splitMembers("")); index.put("com.codename1.ai.vision.VisionException", splitMembers("")); index.put("com.codename1.ai.vision.VisionFeature", splitMembers("")); index.put("com.codename1.ai.vision.VisionImage", splitMembers("")); @@ -4165,16 +4395,17 @@ private static void fillFieldIndex1(Map index) { index.put("com.codename1.analytics.ConsentMode", splitMembers("")); index.put("com.codename1.analytics.FirebaseAnalyticsProvider", splitMembers("")); index.put("com.codename1.analytics.FirebaseAnalyticsProvider.Bridge", splitMembers("")); + } + + private static void fillFieldIndex2(Map index) { index.put("com.codename1.analytics.GoogleAnalyticsProvider", splitMembers("")); index.put("com.codename1.analytics.LegacyAnalyticsProviderAdapter", splitMembers("")); index.put("com.codename1.analytics.LoggingAnalyticsProvider", splitMembers("")); index.put("com.codename1.analytics.MatomoAnalyticsProvider", splitMembers("")); + index.put("com.codename1.annotations.AppIntent", splitMembers("")); index.put("com.codename1.annotations.Async", splitMembers("")); index.put("com.codename1.annotations.Async.Execute", splitMembers("")); index.put("com.codename1.annotations.Async.Schedule", splitMembers("")); - } - - private static void fillFieldIndex2(Map index) { index.put("com.codename1.annotations.Bind", splitMembers("")); index.put("com.codename1.annotations.Bindable", splitMembers("")); index.put("com.codename1.annotations.Column", splitMembers("")); @@ -4184,9 +4415,17 @@ private static void fillFieldIndex2(Map index) { index.put("com.codename1.annotations.DisableNullChecksAndArrayBoundsChecks", splitMembers("")); index.put("com.codename1.annotations.Email", splitMembers("")); index.put("com.codename1.annotations.Entity", splitMembers("")); + index.put("com.codename1.annotations.EntityId", splitMembers("")); + index.put("com.codename1.annotations.EntityImage", splitMembers("")); + index.put("com.codename1.annotations.EntityQuery", splitMembers("")); + index.put("com.codename1.annotations.EntityQuery.Kind", splitMembers("")); + index.put("com.codename1.annotations.EntitySubtitle", splitMembers("")); + index.put("com.codename1.annotations.EntityTitle", splitMembers("")); index.put("com.codename1.annotations.ExistIn", splitMembers("")); index.put("com.codename1.annotations.Fused", splitMembers("")); index.put("com.codename1.annotations.Id", splitMembers("")); + index.put("com.codename1.annotations.IntentEntity", splitMembers("")); + index.put("com.codename1.annotations.IntentParam", splitMembers("")); index.put("com.codename1.annotations.JsonIgnore", splitMembers("")); index.put("com.codename1.annotations.JsonProperty", splitMembers("")); index.put("com.codename1.annotations.Length", splitMembers("")); @@ -4203,9 +4442,29 @@ private static void fillFieldIndex2(Map index) { index.put("com.codename1.annotations.XmlElement", splitMembers("")); index.put("com.codename1.annotations.XmlRoot", splitMembers("")); index.put("com.codename1.annotations.XmlTransient", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Android", splitMembers("")); + index.put("com.codename1.annotations.buildhints.AndroidThemeMode", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Build", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Desktop", splitMembers("")); + index.put("com.codename1.annotations.buildhints.DesktopTitleBar", splitMembers("")); + index.put("com.codename1.annotations.buildhints.HardenControlFlow", splitMembers("")); + index.put("com.codename1.annotations.buildhints.HardenLevel", splitMembers("")); + index.put("com.codename1.annotations.buildhints.HardenStrings", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Hardening", splitMembers("")); + index.put("com.codename1.annotations.buildhints.InstallLocation", splitMembers("")); + index.put("com.codename1.annotations.buildhints.Ios", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosDependencyManager", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosPrivacy", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosProjectType", splitMembers("")); + index.put("com.codename1.annotations.buildhints.IosThemeMode", splitMembers("")); + index.put("com.codename1.annotations.buildhints.NativeThemeMode", splitMembers("")); + index.put("com.codename1.annotations.buildhints.OnDeviceDebug", splitMembers("")); index.put("com.codename1.annotations.graphql.GraphQLClient", splitMembers("")); index.put("com.codename1.annotations.graphql.Mutation", splitMembers("")); index.put("com.codename1.annotations.graphql.Query", splitMembers("")); + } + + private static void fillFieldIndex3(Map index) { index.put("com.codename1.annotations.graphql.Subscription", splitMembers("")); index.put("com.codename1.annotations.graphql.Var", splitMembers("")); index.put("com.codename1.annotations.grpc.GrpcClient", splitMembers("")); @@ -4239,9 +4498,6 @@ private static void fillFieldIndex2(Map index) { index.put("com.codename1.ar.ARHitResult.Type", splitMembers("")); index.put("com.codename1.ar.ARImageAnchor", splitMembers("")); index.put("com.codename1.ar.ARLightEstimate", splitMembers("")); - } - - private static void fillFieldIndex3(Map index) { index.put("com.codename1.ar.ARModel", splitMembers("")); index.put("com.codename1.ar.ARNode", splitMembers("")); index.put("com.codename1.ar.ARPlane", splitMembers("")); @@ -4273,6 +4529,9 @@ private static void fillFieldIndex3(Map index) { index.put("com.codename1.binding.Binding", splitMembers("")); index.put("com.codename1.binding.NotifiableBinding", splitMembers("")); index.put("com.codename1.bluetooth.AdapterState", splitMembers("")); + } + + private static void fillFieldIndex4(Map index) { index.put("com.codename1.bluetooth.AdapterStateListener", splitMembers("")); index.put("com.codename1.bluetooth.Bluetooth", splitMembers("")); index.put("com.codename1.bluetooth.BluetoothDevice", splitMembers("")); @@ -4306,9 +4565,6 @@ private static void fillFieldIndex3(Map index) { index.put("com.codename1.bluetooth.le.L2capServer", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanFilter", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanListener", splitMembers("")); - } - - private static void fillFieldIndex4(Map index) { index.put("com.codename1.bluetooth.le.ScanMode", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanResult", splitMembers("")); index.put("com.codename1.bluetooth.le.ScanSettings", splitMembers("")); @@ -4340,6 +4596,9 @@ private static void fillFieldIndex4(Map index) { index.put("com.codename1.calendar.CalendarCache", splitMembers("")); index.put("com.codename1.calendar.CalendarCapabilities", splitMembers("")); index.put("com.codename1.calendar.CalendarCapability", splitMembers("")); + } + + private static void fillFieldIndex5(Map index) { index.put("com.codename1.calendar.CalendarChange", splitMembers("")); index.put("com.codename1.calendar.CalendarChange.ChangeType", splitMembers("")); index.put("com.codename1.calendar.CalendarChange.EntityType", splitMembers("")); @@ -4373,9 +4632,6 @@ private static void fillFieldIndex4(Map index) { index.put("com.codename1.calendar.CalendarTokenProvider", splitMembers("")); index.put("com.codename1.calendar.DefaultCalendarHttpTransport", splitMembers("")); index.put("com.codename1.calendar.FreeBusyInterval", splitMembers("")); - } - - private static void fillFieldIndex5(Map index) { index.put("com.codename1.calendar.GoogleCalendarSource", splitMembers("")); index.put("com.codename1.calendar.ICalendarCodec", splitMembers("")); index.put("com.codename1.calendar.LocalCalendarSource", splitMembers("")); @@ -4407,6 +4663,9 @@ private static void fillFieldIndex5(Map index) { index.put("com.codename1.car.CarActionListener", splitMembers("")); index.put("com.codename1.car.CarActionStrip", splitMembers("")); index.put("com.codename1.car.CarApplication", splitMembers("")); + } + + private static void fillFieldIndex6(Map index) { index.put("com.codename1.car.CarColor", splitMembers("")); index.put("com.codename1.car.CarConnectionListener", splitMembers("")); index.put("com.codename1.car.CarContext", splitMembers("")); @@ -4440,9 +4699,6 @@ private static void fillFieldIndex5(Map index) { index.put("com.codename1.charts.models.Point", splitMembers("")); index.put("com.codename1.charts.models.RangeCategorySeries", splitMembers("")); index.put("com.codename1.charts.models.SeriesSelection", splitMembers("")); - } - - private static void fillFieldIndex6(Map index) { index.put("com.codename1.charts.models.TimeSeries", splitMembers("")); index.put("com.codename1.charts.models.XYMultipleSeriesDataset", splitMembers("")); index.put("com.codename1.charts.models.XYSeries", splitMembers("")); @@ -4474,6 +4730,9 @@ private static void fillFieldIndex6(Map index) { index.put("com.codename1.charts.views.CubicLineChart", splitMembers("")); index.put("com.codename1.charts.views.DialChart", splitMembers("")); index.put("com.codename1.charts.views.DoughnutChart", splitMembers("")); + } + + private static void fillFieldIndex7(Map index) { index.put("com.codename1.charts.views.LineChart", splitMembers("")); index.put("com.codename1.charts.views.PieChart", splitMembers("")); index.put("com.codename1.charts.views.PieMapper", splitMembers("")); @@ -4507,9 +4766,6 @@ private static void fillFieldIndex6(Map index) { index.put("com.codename1.components.FileTreeModel", splitMembers("")); index.put("com.codename1.components.FloatingActionButton", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSTATE_DEFAULTSTATE_PRESSEDSTATE_ROLLOVERSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.components.FloatingHint", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); - } - - private static void fillFieldIndex7(Map index) { index.put("com.codename1.components.ImageViewer", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORIMAGE_FILLIMAGE_FITLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.components.InfiniteProgress", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.components.InfiniteScrollAdapter", splitMembers("")); @@ -4541,13 +4797,19 @@ private static void fillFieldIndex7(Map index) { index.put("com.codename1.components.ToastBar", splitMembers("")); index.put("com.codename1.components.WebBrowser", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.contacts.Address", splitMembers("")); + } + + private static void fillFieldIndex8(Map index) { index.put("com.codename1.contacts.Contact", splitMembers("")); index.put("com.codename1.contacts.ContactsManager", splitMembers("")); index.put("com.codename1.contacts.ContactsModel", splitMembers("")); index.put("com.codename1.crash.CrashProtection", splitMembers("")); index.put("com.codename1.crash.PiiScrubber", splitMembers("")); index.put("com.codename1.db.Cursor", splitMembers("")); + index.put("com.codename1.db.CursorExt", splitMembers("")); index.put("com.codename1.db.Database", splitMembers("")); + index.put("com.codename1.db.DatabaseConfig", splitMembers("")); + index.put("com.codename1.db.DatabaseEncryptionException", splitMembers("")); index.put("com.codename1.db.Row", splitMembers("")); index.put("com.codename1.db.RowExt", splitMembers("")); index.put("com.codename1.db.ThreadSafeDatabase", splitMembers("")); @@ -4574,9 +4836,6 @@ private static void fillFieldIndex7(Map index) { index.put("com.codename1.gaming.VirtualButton", splitMembers("")); index.put("com.codename1.gaming.VirtualJoystick", splitMembers("")); index.put("com.codename1.gaming.VoiceListener", splitMembers("")); - } - - private static void fillFieldIndex8(Map index) { index.put("com.codename1.gaming.level.AssetCatalog", splitMembers("")); index.put("com.codename1.gaming.level.AssetDef", splitMembers("")); index.put("com.codename1.gaming.level.AssetDef.Kind", splitMembers("")); @@ -4605,6 +4864,9 @@ private static void fillFieldIndex8(Map index) { index.put("com.codename1.gaming.level.TileLayer", splitMembers("")); index.put("com.codename1.gaming.physics.BodyType", splitMembers("")); index.put("com.codename1.gaming.physics.ContactListener", splitMembers("")); + } + + private static void fillFieldIndex9(Map index) { index.put("com.codename1.gaming.physics.PhysicsBody", splitMembers("")); index.put("com.codename1.gaming.physics.PhysicsContact", splitMembers("")); index.put("com.codename1.gaming.physics.PhysicsJoint", splitMembers("")); @@ -4641,9 +4903,6 @@ private static void fillFieldIndex8(Map index) { index.put("com.codename1.gaming.physics.box2d.collision.TimeOfImpact.TOIOutput", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.TimeOfImpact.TOIOutputState", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.WorldManifold", splitMembers("")); - } - - private static void fillFieldIndex9(Map index) { index.put("com.codename1.gaming.physics.box2d.collision.broadphase.BroadPhase", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.broadphase.BroadPhaseStrategy", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.collision.broadphase.DynamicTree", splitMembers("")); @@ -4672,6 +4931,9 @@ private static void fillFieldIndex9(Map index) { index.put("com.codename1.gaming.physics.box2d.common.Vec3", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.Body", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.BodyDef", splitMembers("")); + } + + private static void fillFieldIndex10(Map index) { index.put("com.codename1.gaming.physics.box2d.dynamics.BodyType", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.ContactManager", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.Filter", splitMembers("")); @@ -4708,9 +4970,6 @@ private static void fillFieldIndex9(Map index) { index.put("com.codename1.gaming.physics.box2d.dynamics.joints.FrictionJoint", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.FrictionJointDef", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.GearJoint", splitMembers("")); - } - - private static void fillFieldIndex10(Map index) { index.put("com.codename1.gaming.physics.box2d.dynamics.joints.GearJointDef", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.Jacobian", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.dynamics.joints.Joint", splitMembers("")); @@ -4739,6 +4998,9 @@ private static void fillFieldIndex10(Map index) { index.put("com.codename1.gaming.physics.box2d.pooling.arrays.IntArray", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.arrays.Vec2Array", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.normal.CircleStack", splitMembers("")); + } + + private static void fillFieldIndex11(Map index) { index.put("com.codename1.gaming.physics.box2d.pooling.normal.DefaultWorldPool", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.normal.MutableStack", splitMembers("")); index.put("com.codename1.gaming.physics.box2d.pooling.normal.OrderedStack", splitMembers("")); @@ -4775,9 +5037,6 @@ private static void fillFieldIndex10(Map index) { index.put("com.codename1.health.AggregateResult", splitMembers("")); index.put("com.codename1.health.BloodPressureSample", splitMembers("")); index.put("com.codename1.health.CategorySample", splitMembers("")); - } - - private static void fillFieldIndex11(Map index) { index.put("com.codename1.health.Health", splitMembers("")); index.put("com.codename1.health.HealthAccess", splitMembers("")); index.put("com.codename1.health.HealthAggregationStyle", splitMembers("")); @@ -4806,6 +5065,9 @@ private static void fillFieldIndex11(Map index) { index.put("com.codename1.health.HealthUnitDimension", splitMembers("")); index.put("com.codename1.health.HealthWriteResult", splitMembers("")); index.put("com.codename1.health.QuantitySample", splitMembers("")); + } + + private static void fillFieldIndex12(Map index) { index.put("com.codename1.health.RecordingMethod", splitMembers("")); index.put("com.codename1.health.SamplePage", splitMembers("")); index.put("com.codename1.health.SampleQuery", splitMembers("")); @@ -4842,9 +5104,6 @@ private static void fillFieldIndex11(Map index) { index.put("com.codename1.health.sensors.TemperatureMeasurement", splitMembers("")); index.put("com.codename1.health.sensors.WeightMeasurement", splitMembers("")); index.put("com.codename1.health.workout.WorkoutConfiguration", splitMembers("")); - } - - private static void fillFieldIndex12(Map index) { index.put("com.codename1.health.workout.WorkoutEvent", splitMembers("")); index.put("com.codename1.health.workout.WorkoutEvent.Kind", splitMembers("")); index.put("com.codename1.health.workout.WorkoutLocationType", splitMembers("")); @@ -4852,6 +5111,73 @@ private static void fillFieldIndex12(Map index) { index.put("com.codename1.health.workout.WorkoutSession", splitMembers("")); index.put("com.codename1.health.workout.WorkoutSessionListener", splitMembers("")); index.put("com.codename1.health.workout.WorkoutSessionState", splitMembers("")); + index.put("com.codename1.home.Accessory", splitMembers("")); + index.put("com.codename1.home.AccessoryCategory", splitMembers("")); + index.put("com.codename1.home.AccessoryService", splitMembers("")); + index.put("com.codename1.home.AirQualityLevel", splitMembers("")); + index.put("com.codename1.home.AlarmState", splitMembers("")); + index.put("com.codename1.home.ChargingState", splitMembers("")); + index.put("com.codename1.home.DoorState", splitMembers("")); + index.put("com.codename1.home.FanMode", splitMembers("")); + index.put("com.codename1.home.HeatingCoolingMode", splitMembers("")); + index.put("com.codename1.home.HomeAuthorizationStatus", splitMembers("")); + index.put("com.codename1.home.HomeAvailability", splitMembers("")); + index.put("com.codename1.home.HomeBackend", splitMembers("")); + index.put("com.codename1.home.HomeChangeListener", splitMembers("")); + index.put("com.codename1.home.HomeConfigurationException", splitMembers("")); + index.put("com.codename1.home.HomeError", splitMembers("")); + index.put("com.codename1.home.HomeException", splitMembers("")); + index.put("com.codename1.home.HomeRoom", splitMembers("")); + index.put("com.codename1.home.HomeStructure", splitMembers("")); + index.put("com.codename1.home.HomeStructureEvent", splitMembers("")); + index.put("com.codename1.home.HomeStructureListener", splitMembers("")); + index.put("com.codename1.home.HomeZone", splitMembers("")); + } + + private static void fillFieldIndex13(Map index) { + index.put("com.codename1.home.LockState", splitMembers("")); + index.put("com.codename1.home.PositionState", splitMembers("")); + index.put("com.codename1.home.Scene", splitMembers("")); + index.put("com.codename1.home.SceneAction", splitMembers("")); + index.put("com.codename1.home.SceneType", splitMembers("")); + index.put("com.codename1.home.ServiceType", splitMembers("")); + index.put("com.codename1.home.SmartHome", splitMembers("")); + index.put("com.codename1.home.StructureChangeKind", splitMembers("")); + index.put("com.codename1.home.SubscriptionRequest", splitMembers("")); + index.put("com.codename1.home.Trait", splitMembers("")); + index.put("com.codename1.home.TraitChangeBatch", splitMembers("")); + index.put("com.codename1.home.TraitConstraint", splitMembers("")); + index.put("com.codename1.home.TraitReadRequest", splitMembers("")); + index.put("com.codename1.home.TraitReading", splitMembers("")); + index.put("com.codename1.home.TraitSubscription", splitMembers("")); + index.put("com.codename1.home.TraitUnit", splitMembers("")); + index.put("com.codename1.home.TraitUnitDimension", splitMembers("")); + index.put("com.codename1.home.TraitValue", splitMembers("")); + index.put("com.codename1.home.TraitValueKind", splitMembers("")); + index.put("com.codename1.home.TraitWrite", splitMembers("")); + index.put("com.codename1.home.TraitWriteResult", splitMembers("")); + index.put("com.codename1.home.commissioning.Commissioner", splitMembers("")); + index.put("com.codename1.home.commissioning.CommissioningRequest", splitMembers("")); + index.put("com.codename1.home.commissioning.CommissioningResult", splitMembers("")); + index.put("com.codename1.home.commissioning.CommissioningStyle", splitMembers("")); + index.put("com.codename1.home.commissioning.SetupPayload", splitMembers("")); + index.put("com.codename1.home.spi.HomeBridge", splitMembers("")); + index.put("com.codename1.intents.AppEntity", splitMembers("")); + index.put("com.codename1.intents.DynamicIntent", splitMembers("")); + index.put("com.codename1.intents.EntitySelectionHandler", splitMembers("")); + index.put("com.codename1.intents.Exposure", splitMembers("")); + index.put("com.codename1.intents.IntentCompletion", splitMembers("")); + index.put("com.codename1.intents.IntentContext", splitMembers("")); + index.put("com.codename1.intents.IntentDates", splitMembers("")); + index.put("com.codename1.intents.IntentDeclaration", splitMembers("")); + index.put("com.codename1.intents.IntentDispatcher", splitMembers("")); + index.put("com.codename1.intents.IntentParameterInfo", splitMembers("")); + index.put("com.codename1.intents.IntentParameterType", splitMembers("")); + index.put("com.codename1.intents.IntentResult", splitMembers("")); + index.put("com.codename1.intents.IntentSerializer", splitMembers("")); + index.put("com.codename1.intents.IntentSource", splitMembers("")); + index.put("com.codename1.intents.Intents", splitMembers("")); + index.put("com.codename1.intents.spi.IntentBridge", splitMembers("")); index.put("com.codename1.io.AccessToken", splitMembers("")); index.put("com.codename1.io.BufferedInputStream", splitMembers("")); index.put("com.codename1.io.BufferedOutputStream", splitMembers("")); @@ -4873,6 +5199,9 @@ private static void fillFieldIndex12(Map index) { index.put("com.codename1.io.JSONParser", splitMembers("")); index.put("com.codename1.io.JSONParser.RawJson", splitMembers("")); index.put("com.codename1.io.JSONWriter", splitMembers("")); + } + + private static void fillFieldIndex14(Map index) { index.put("com.codename1.io.JSONWriter.ArrayBuilder", splitMembers("")); index.put("com.codename1.io.JSONWriter.ObjectBuilder", splitMembers("")); index.put("com.codename1.io.Log", splitMembers("")); @@ -4909,9 +5238,6 @@ private static void fillFieldIndex12(Map index) { index.put("com.codename1.io.bonjour.BonjourService", splitMembers("")); index.put("com.codename1.io.bonjour.BonjourServiceListener", splitMembers("")); index.put("com.codename1.io.graphql.GraphQL", splitMembers("")); - } - - private static void fillFieldIndex13(Map index) { index.put("com.codename1.io.graphql.GraphQLClients", splitMembers("")); index.put("com.codename1.io.graphql.GraphQLClients.Factory", splitMembers("")); index.put("com.codename1.io.graphql.GraphQLError", splitMembers("")); @@ -4940,6 +5266,9 @@ private static void fillFieldIndex13(Map index) { index.put("com.codename1.io.gzip.GZIPHeader", splitMembers("")); index.put("com.codename1.io.gzip.GZIPInputStream", splitMembers("")); index.put("com.codename1.io.gzip.GZIPOutputStream", splitMembers("")); + } + + private static void fillFieldIndex15(Map index) { index.put("com.codename1.io.gzip.Inflater", splitMembers("")); index.put("com.codename1.io.gzip.InflaterInputStream", splitMembers("")); index.put("com.codename1.io.gzip.JZlib", splitMembers("")); @@ -4976,9 +5305,6 @@ private static void fillFieldIndex13(Map index) { index.put("com.codename1.io.usb.UsbDeviceListener", splitMembers("")); index.put("com.codename1.io.usb.UsbPlatform", splitMembers("")); index.put("com.codename1.io.webauthn.PublicKeyCredential", splitMembers("")); - } - - private static void fillFieldIndex14(Map index) { index.put("com.codename1.io.webauthn.PublicKeyCredentialCreationOptions", splitMembers("")); index.put("com.codename1.io.webauthn.PublicKeyCredentialCreationOptions.Builder", splitMembers("")); index.put("com.codename1.io.webauthn.PublicKeyCredentialRequestOptions", splitMembers("")); @@ -5007,6 +5333,9 @@ private static void fillFieldIndex14(Map index) { index.put("com.codename1.l10n.ParseException", splitMembers("")); index.put("com.codename1.l10n.SimpleDateFormat", splitMembers("")); index.put("com.codename1.location.Geofence", splitMembers("")); + } + + private static void fillFieldIndex16(Map index) { index.put("com.codename1.location.GeofenceListener", splitMembers("")); index.put("com.codename1.location.GeofenceManager", splitMembers("")); index.put("com.codename1.location.GeofenceManager.Listener", splitMembers("")); @@ -5043,9 +5372,6 @@ private static void fillFieldIndex14(Map index) { index.put("com.codename1.maps.layers.AbstractLayer", splitMembers("")); index.put("com.codename1.maps.layers.ArrowLinesLayer", splitMembers("")); index.put("com.codename1.maps.layers.Layer", splitMembers("")); - } - - private static void fillFieldIndex15(Map index) { index.put("com.codename1.maps.layers.LinesLayer", splitMembers("")); index.put("com.codename1.maps.layers.PointLayer", splitMembers("")); index.put("com.codename1.maps.layers.PointsLayer", splitMembers("")); @@ -5074,6 +5400,9 @@ private static void fillFieldIndex15(Map index) { index.put("com.codename1.maps.vector.StyleLayer", splitMembers("")); index.put("com.codename1.maps.vector.TileCallback", splitMembers("")); index.put("com.codename1.maps.vector.TileSource", splitMembers("")); + } + + private static void fillFieldIndex17(Map index) { index.put("com.codename1.maps.vector.VectorFeature", splitMembers("")); index.put("com.codename1.maps.vector.VectorLayer", splitMembers("")); index.put("com.codename1.maps.vector.VectorMapEngine", splitMembers("")); @@ -5110,9 +5439,6 @@ private static void fillFieldIndex15(Map index) { index.put("com.codename1.media.SpeechRecognizer", splitMembers("")); index.put("com.codename1.media.TextToSpeech", splitMembers("")); index.put("com.codename1.media.TimedRecognitionCallback", splitMembers("")); - } - - private static void fillFieldIndex16(Map index) { index.put("com.codename1.media.Transcriber", splitMembers("")); index.put("com.codename1.media.TranscriptionRequest", splitMembers("")); index.put("com.codename1.media.TranscriptionResult", splitMembers("")); @@ -5141,6 +5467,9 @@ private static void fillFieldIndex16(Map index) { index.put("com.codename1.nfc.NfcError", splitMembers("")); index.put("com.codename1.nfc.NfcException", splitMembers("")); index.put("com.codename1.nfc.NfcF", splitMembers("")); + } + + private static void fillFieldIndex18(Map index) { index.put("com.codename1.nfc.NfcListener", splitMembers("")); index.put("com.codename1.nfc.NfcReadOptions", splitMembers("")); index.put("com.codename1.nfc.NfcV", splitMembers("")); @@ -5177,9 +5506,6 @@ private static void fillFieldIndex16(Map index) { index.put("com.codename1.plugin.event.OpenGalleryEvent", splitMembers("")); index.put("com.codename1.plugin.event.PluginEvent", splitMembers("")); index.put("com.codename1.printing.PrintResult", splitMembers("")); - } - - private static void fillFieldIndex17(Map index) { index.put("com.codename1.printing.PrintResultListener", splitMembers("")); index.put("com.codename1.printing.Printer", splitMembers("")); index.put("com.codename1.processing.Result", splitMembers("")); @@ -5208,6 +5534,9 @@ private static void fillFieldIndex17(Map index) { index.put("com.codename1.properties.UiBinding", splitMembers("")); index.put("com.codename1.properties.UiBinding.BooleanConverter", splitMembers("")); index.put("com.codename1.properties.UiBinding.BoundTableModel", splitMembers("")); + } + + private static void fillFieldIndex19(Map index) { index.put("com.codename1.properties.UiBinding.CheckBoxRadioSelectionAdapter", splitMembers("")); index.put("com.codename1.properties.UiBinding.ComponentAdapter", splitMembers("")); index.put("com.codename1.properties.UiBinding.DateConverter", splitMembers("")); @@ -5244,9 +5573,6 @@ private static void fillFieldIndex17(Map index) { index.put("com.codename1.router.PopGuard", splitMembers("")); index.put("com.codename1.router.PopReason", splitMembers("")); index.put("com.codename1.router.RouteDispatcher", splitMembers("")); - } - - private static void fillFieldIndex18(Map index) { index.put("com.codename1.security.AuthenticationOptions", splitMembers("")); index.put("com.codename1.security.Base32", splitMembers("")); index.put("com.codename1.security.BiometricError", splitMembers("")); @@ -5270,9 +5596,14 @@ private static void fillFieldIndex18(Map index) { index.put("com.codename1.security.SecureRandom", splitMembers("")); index.put("com.codename1.security.SecureStorage", splitMembers("")); index.put("com.codename1.security.Signature", splitMembers("")); + index.put("com.codename1.security.TapjackingPolicy", splitMembers("")); + index.put("com.codename1.security.hardening.Hardening", splitMembers("")); index.put("com.codename1.security.shield.AppShield", splitMembers("")); index.put("com.codename1.security.shield.FailureMode", splitMembers("")); index.put("com.codename1.security.shield.HostPolicy", splitMembers("")); + } + + private static void fillFieldIndex20(Map index) { index.put("com.codename1.security.shield.PinSet", splitMembers("")); index.put("com.codename1.security.shield.ShieldConfig", splitMembers("")); index.put("com.codename1.security.shield.ShieldException", splitMembers("")); @@ -5311,9 +5642,6 @@ private static void fillFieldIndex18(Map index) { index.put("com.codename1.social.Login", splitMembers("")); index.put("com.codename1.social.LoginCallback", splitMembers("")); index.put("com.codename1.social.MicrosoftConnect", splitMembers("")); - } - - private static void fillFieldIndex19(Map index) { index.put("com.codename1.surfaces.LiveActivity", splitMembers("")); index.put("com.codename1.surfaces.LiveActivityDescriptor", splitMembers("")); index.put("com.codename1.surfaces.SurfaceActionEvent", splitMembers("")); @@ -5340,6 +5668,9 @@ private static void fillFieldIndex19(Map index) { index.put("com.codename1.surfaces.WidgetKind", splitMembers("")); index.put("com.codename1.surfaces.WidgetSize", splitMembers("")); index.put("com.codename1.surfaces.WidgetTimeline", splitMembers("")); + } + + private static void fillFieldIndex21(Map index) { index.put("com.codename1.surfaces.WidgetTimeline.Entry", splitMembers("")); index.put("com.codename1.surfaces.spi.SurfaceBridge", splitMembers("")); index.put("com.codename1.system.CrashReport", splitMembers("")); @@ -5378,9 +5709,6 @@ private static void fillFieldIndex19(Map index) { index.put("com.codename1.ui.CheckBox", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSTATE_DEFAULTSTATE_PRESSEDSTATE_ROLLOVERSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.ui.ClipboardContent", splitMembers("MIME_ASCIIDOCMIME_FILEMIME_GIFMIME_HTMLMIME_JPEGMIME_MARKDOWNMIME_PNGMIME_RTFMIME_TEXT")); index.put("com.codename1.ui.CodeCompletion", splitMembers("")); - } - - private static void fillFieldIndex20(Map index) { index.put("com.codename1.ui.CodeCompletionProvider", splitMembers("")); index.put("com.codename1.ui.CodeDiagnostic", splitMembers("ERRORINFOWARNING")); index.put("com.codename1.ui.CodeEditor", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); @@ -5407,6 +5735,9 @@ private static void fillFieldIndex20(Map index) { index.put("com.codename1.ui.EditField", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORKEY_BACKSPACEKEY_COPYKEY_CUTKEY_DELETEKEY_DOWNKEY_ENDKEY_ESCAPEKEY_HOMEKEY_LEFTKEY_PAGE_DOWNKEY_PAGE_UPKEY_PASTEKEY_REDOKEY_RIGHTKEY_SELECT_ALLKEY_TABKEY_UNDOKEY_UPLEFTMOD_ALTMOD_CTRLMOD_SHIFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.ui.Editable", splitMembers("")); index.put("com.codename1.ui.EncodedImage", splitMembers("")); + } + + private static void fillFieldIndex22(Map index) { index.put("com.codename1.ui.Font", splitMembers("BASELINEBOTTOMCENTERCENTER_BEHAVIOR_CENTERCENTER_BEHAVIOR_CENTER_ABSOLUTECENTER_BEHAVIOR_SCALECENTER_BEHAVIOR_TOTAL_BELOWDENSITY_2HDDENSITY_4KDENSITY_560DENSITY_HDDENSITY_HIGHDENSITY_LOWDENSITY_MEDIUMDENSITY_VERY_HIGHDENSITY_VERY_LOWEASTFACE_MONOSPACEFACE_PROPORTIONALFACE_SYSTEMGALLERY_ALLGALLERY_ALL_MULTIGALLERY_IMAGEGALLERY_IMAGE_MULTIGALLERY_VIDEOGALLERY_VIDEO_MULTILEFTNATIVE_ITALIC_BLACKNATIVE_ITALIC_BOLDNATIVE_ITALIC_LIGHTNATIVE_ITALIC_REGULARNATIVE_ITALIC_THINNATIVE_MAIN_BLACKNATIVE_MAIN_BOLDNATIVE_MAIN_LIGHTNATIVE_MAIN_REGULARNATIVE_MAIN_THINNORTHPICKER_TYPE_CALENDARPICKER_TYPE_DATEPICKER_TYPE_DATE_AND_TIMEPICKER_TYPE_DURATIONPICKER_TYPE_DURATION_HOURSPICKER_TYPE_DURATION_MINUTESPICKER_TYPE_STRINGSPICKER_TYPE_TIMERIGHTSIZE_LARGESIZE_MEDIUMSIZE_SMALLSMS_BOTHSMS_INTERACTIVESMS_NOT_SUPPORTEDSMS_SEAMLESSSOUTHSTYLE_BOLDSTYLE_ITALICSTYLE_PLAINSTYLE_UNDERLINEDTOPWEST")); index.put("com.codename1.ui.FontImage", splitMembers("MATERIAL_10KMATERIAL_10MPMATERIAL_11MPMATERIAL_123MATERIAL_12MPMATERIAL_13MPMATERIAL_14MPMATERIAL_15MPMATERIAL_16MPMATERIAL_17MPMATERIAL_18MPMATERIAL_18_UP_RATINGMATERIAL_19MPMATERIAL_1KMATERIAL_1K_PLUSMATERIAL_1X_MOBILEDATAMATERIAL_20MPMATERIAL_21MPMATERIAL_22MPMATERIAL_23MPMATERIAL_24MPMATERIAL_2KMATERIAL_2K_PLUSMATERIAL_2MPMATERIAL_30FPSMATERIAL_30FPS_SELECTMATERIAL_360MATERIAL_3D_ROTATIONMATERIAL_3G_MOBILEDATAMATERIAL_3KMATERIAL_3K_PLUSMATERIAL_3MPMATERIAL_3PMATERIAL_4G_MOBILEDATAMATERIAL_4G_PLUS_MOBILEDATAMATERIAL_4KMATERIAL_4K_PLUSMATERIAL_4MPMATERIAL_5GMATERIAL_5KMATERIAL_5K_PLUSMATERIAL_5MPMATERIAL_60FPSMATERIAL_60FPS_SELECTMATERIAL_6KMATERIAL_6K_PLUSMATERIAL_6MPMATERIAL_6_FT_APARTMATERIAL_7KMATERIAL_7K_PLUSMATERIAL_7MPMATERIAL_8KMATERIAL_8K_PLUSMATERIAL_8MPMATERIAL_9KMATERIAL_9K_PLUSMATERIAL_9MPMATERIAL_ABCMATERIAL_ACCESSIBILITYMATERIAL_ACCESSIBILITY_NEWMATERIAL_ACCESSIBLEMATERIAL_ACCESSIBLE_FORWARDMATERIAL_ACCESS_ALARMMATERIAL_ACCESS_ALARMSMATERIAL_ACCESS_TIMEMATERIAL_ACCESS_TIME_FILLEDMATERIAL_ACCOUNT_BALANCEMATERIAL_ACCOUNT_BALANCE_WALLETMATERIAL_ACCOUNT_BOXMATERIAL_ACCOUNT_CIRCLEMATERIAL_ACCOUNT_TREEMATERIAL_AC_UNITMATERIAL_ADBMATERIAL_ADDMATERIAL_ADDCHARTMATERIAL_ADD_ALARMMATERIAL_ADD_ALERTMATERIAL_ADD_A_PHOTOMATERIAL_ADD_BOXMATERIAL_ADD_BUSINESSMATERIAL_ADD_CALLMATERIAL_ADD_CARDMATERIAL_ADD_CHARTMATERIAL_ADD_CIRCLEMATERIAL_ADD_CIRCLE_OUTLINEMATERIAL_ADD_COMMENTMATERIAL_ADD_HOMEMATERIAL_ADD_HOME_WORKMATERIAL_ADD_IC_CALLMATERIAL_ADD_LINKMATERIAL_ADD_LOCATIONMATERIAL_ADD_LOCATION_ALTMATERIAL_ADD_MODERATORMATERIAL_ADD_PHOTO_ALTERNATEMATERIAL_ADD_REACTIONMATERIAL_ADD_ROADMATERIAL_ADD_SHOPPING_CARTMATERIAL_ADD_TASKMATERIAL_ADD_TO_DRIVEMATERIAL_ADD_TO_HOME_SCREENMATERIAL_ADD_TO_PHOTOSMATERIAL_ADD_TO_QUEUEMATERIAL_ADF_SCANNERMATERIAL_ADJUSTMATERIAL_ADMIN_PANEL_SETTINGSMATERIAL_ADOBEMATERIAL_ADS_CLICKMATERIAL_AD_UNITSMATERIAL_AGRICULTUREMATERIAL_AIRMATERIAL_AIRLINESMATERIAL_AIRLINE_SEAT_FLATMATERIAL_AIRLINE_SEAT_FLAT_ANGLEDMATERIAL_AIRLINE_SEAT_INDIVIDUAL_SUITEMATERIAL_AIRLINE_SEAT_LEGROOM_EXTRAMATERIAL_AIRLINE_SEAT_LEGROOM_NORMALMATERIAL_AIRLINE_SEAT_LEGROOM_REDUCEDMATERIAL_AIRLINE_SEAT_RECLINE_EXTRAMATERIAL_AIRLINE_SEAT_RECLINE_NORMALMATERIAL_AIRLINE_STOPSMATERIAL_AIRPLANEMODE_ACTIVEMATERIAL_AIRPLANEMODE_INACTIVEMATERIAL_AIRPLANEMODE_OFFMATERIAL_AIRPLANEMODE_ONMATERIAL_AIRPLANE_TICKETMATERIAL_AIRPLAYMATERIAL_AIRPORT_SHUTTLEMATERIAL_ALARMMATERIAL_ALARM_ADDMATERIAL_ALARM_OFFMATERIAL_ALARM_ONMATERIAL_ALBUMMATERIAL_ALIGN_HORIZONTAL_CENTERMATERIAL_ALIGN_HORIZONTAL_LEFTMATERIAL_ALIGN_HORIZONTAL_RIGHTMATERIAL_ALIGN_VERTICAL_BOTTOMMATERIAL_ALIGN_VERTICAL_CENTERMATERIAL_ALIGN_VERTICAL_TOPMATERIAL_ALL_INBOXMATERIAL_ALL_INCLUSIVEMATERIAL_ALL_OUTMATERIAL_ALTERNATE_EMAILMATERIAL_ALT_ROUTEMATERIAL_AMP_STORIESMATERIAL_ANALYTICSMATERIAL_ANCHORMATERIAL_ANDROIDMATERIAL_ANIMATIONMATERIAL_ANNOUNCEMENTMATERIAL_AODMATERIAL_APARTMENTMATERIAL_APIMATERIAL_APPLEMATERIAL_APPROVALMATERIAL_APPSMATERIAL_APPS_OUTAGEMATERIAL_APP_BLOCKINGMATERIAL_APP_REGISTRATIONMATERIAL_APP_SETTINGS_ALTMATERIAL_APP_SHORTCUTMATERIAL_ARCHITECTUREMATERIAL_ARCHIVEMATERIAL_AREA_CHARTMATERIAL_ARROW_BACKMATERIAL_ARROW_BACK_IOSMATERIAL_ARROW_BACK_IOS_NEWMATERIAL_ARROW_CIRCLE_DOWNMATERIAL_ARROW_CIRCLE_LEFTMATERIAL_ARROW_CIRCLE_RIGHTMATERIAL_ARROW_CIRCLE_UPMATERIAL_ARROW_DOWNWARDMATERIAL_ARROW_DROP_DOWNMATERIAL_ARROW_DROP_DOWN_CIRCLEMATERIAL_ARROW_DROP_UPMATERIAL_ARROW_FORWARDMATERIAL_ARROW_FORWARD_IOSMATERIAL_ARROW_LEFTMATERIAL_ARROW_OUTWARDMATERIAL_ARROW_RIGHTMATERIAL_ARROW_RIGHT_ALTMATERIAL_ARROW_UPWARDMATERIAL_ARTICLEMATERIAL_ART_TRACKMATERIAL_ASPECT_RATIOMATERIAL_ASSESSMENTMATERIAL_ASSIGNMENTMATERIAL_ASSIGNMENT_ADDMATERIAL_ASSIGNMENT_INDMATERIAL_ASSIGNMENT_LATEMATERIAL_ASSIGNMENT_RETURNMATERIAL_ASSIGNMENT_RETURNEDMATERIAL_ASSIGNMENT_TURNED_INMATERIAL_ASSISTANTMATERIAL_ASSISTANT_DIRECTIONMATERIAL_ASSISTANT_NAVIGATIONMATERIAL_ASSISTANT_PHOTOMATERIAL_ASSIST_WALKERMATERIAL_ASSURED_WORKLOADMATERIAL_ATMMATERIAL_ATTACHMENTMATERIAL_ATTACH_EMAILMATERIAL_ATTACH_FILEMATERIAL_ATTACH_MONEYMATERIAL_ATTRACTIONSMATERIAL_ATTRIBUTIONMATERIAL_AUDIOTRACKMATERIAL_AUDIO_FILEMATERIAL_AUTOFPS_SELECTMATERIAL_AUTORENEWMATERIAL_AUTO_AWESOMEMATERIAL_AUTO_AWESOME_MOSAICMATERIAL_AUTO_AWESOME_MOTIONMATERIAL_AUTO_DELETEMATERIAL_AUTO_FIX_HIGHMATERIAL_AUTO_FIX_NORMALMATERIAL_AUTO_FIX_OFFMATERIAL_AUTO_GRAPHMATERIAL_AUTO_MODEMATERIAL_AUTO_STORIESMATERIAL_AV_TIMERMATERIAL_BABY_CHANGING_STATIONMATERIAL_BACKPACKMATERIAL_BACKSPACEMATERIAL_BACKUPMATERIAL_BACKUP_TABLEMATERIAL_BACK_HANDMATERIAL_BADGEMATERIAL_BAKERY_DININGMATERIAL_BALANCEMATERIAL_BALCONYMATERIAL_BALLOTMATERIAL_BARCODE_READERMATERIAL_BAR_CHARTMATERIAL_BATCH_PREDICTIONMATERIAL_BATHROOMMATERIAL_BATHTUBMATERIAL_BATTERY_0_BARMATERIAL_BATTERY_1_BARMATERIAL_BATTERY_2_BARMATERIAL_BATTERY_3_BARMATERIAL_BATTERY_4_BARMATERIAL_BATTERY_5_BARMATERIAL_BATTERY_6_BARMATERIAL_BATTERY_ALERTMATERIAL_BATTERY_CHARGING_FULLMATERIAL_BATTERY_FULLMATERIAL_BATTERY_SAVERMATERIAL_BATTERY_STDMATERIAL_BATTERY_UNKNOWNMATERIAL_BEACH_ACCESSMATERIAL_BEDMATERIAL_BEDROOM_BABYMATERIAL_BEDROOM_CHILDMATERIAL_BEDROOM_PARENTMATERIAL_BEDTIMEMATERIAL_BEDTIME_OFFMATERIAL_BEENHEREMATERIAL_BENTOMATERIAL_BIKE_SCOOTERMATERIAL_BIOTECHMATERIAL_BLENDERMATERIAL_BLINDMATERIAL_BLINDSMATERIAL_BLINDS_CLOSEDMATERIAL_BLOCKMATERIAL_BLOCK_FLIPPEDMATERIAL_BLOODTYPEMATERIAL_BLUETOOTHMATERIAL_BLUETOOTH_AUDIOMATERIAL_BLUETOOTH_CONNECTEDMATERIAL_BLUETOOTH_DISABLEDMATERIAL_BLUETOOTH_DRIVEMATERIAL_BLUETOOTH_SEARCHINGMATERIAL_BLUR_CIRCULARMATERIAL_BLUR_LINEARMATERIAL_BLUR_OFFMATERIAL_BLUR_ONMATERIAL_BOLTMATERIAL_BOOKMATERIAL_BOOKMARKMATERIAL_BOOKMARKSMATERIAL_BOOKMARK_ADDMATERIAL_BOOKMARK_ADDEDMATERIAL_BOOKMARK_BORDERMATERIAL_BOOKMARK_OUTLINEMATERIAL_BOOKMARK_REMOVEMATERIAL_BOOK_ONLINEMATERIAL_BORDER_ALLMATERIAL_BORDER_BOTTOMMATERIAL_BORDER_CLEARMATERIAL_BORDER_COLORMATERIAL_BORDER_HORIZONTALMATERIAL_BORDER_INNERMATERIAL_BORDER_LEFTMATERIAL_BORDER_OUTERMATERIAL_BORDER_RIGHTMATERIAL_BORDER_STYLEMATERIAL_BORDER_TOPMATERIAL_BORDER_VERTICALMATERIAL_BOYMATERIAL_BRANDING_WATERMARKMATERIAL_BREAKFAST_DININGMATERIAL_BRIGHTNESS_1MATERIAL_BRIGHTNESS_2MATERIAL_BRIGHTNESS_3MATERIAL_BRIGHTNESS_4MATERIAL_BRIGHTNESS_5MATERIAL_BRIGHTNESS_6MATERIAL_BRIGHTNESS_7MATERIAL_BRIGHTNESS_AUTOMATERIAL_BRIGHTNESS_HIGHMATERIAL_BRIGHTNESS_LOWMATERIAL_BRIGHTNESS_MEDIUMMATERIAL_BROADCAST_ON_HOMEMATERIAL_BROADCAST_ON_PERSONALMATERIAL_BROKEN_IMAGEMATERIAL_BROWSER_NOT_SUPPORTEDMATERIAL_BROWSER_UPDATEDMATERIAL_BROWSE_GALLERYMATERIAL_BRUNCH_DININGMATERIAL_BRUSHMATERIAL_BUBBLE_CHARTMATERIAL_BUG_REPORTMATERIAL_BUILDMATERIAL_BUILD_CIRCLEMATERIAL_BUNGALOWMATERIAL_BURST_MODEMATERIAL_BUSINESSMATERIAL_BUSINESS_CENTERMATERIAL_BUS_ALERTMATERIAL_CABINMATERIAL_CABLEMATERIAL_CACHEDMATERIAL_CAKEMATERIAL_CALCULATEMATERIAL_CALENDAR_MONTHMATERIAL_CALENDAR_TODAYMATERIAL_CALENDAR_VIEW_DAYMATERIAL_CALENDAR_VIEW_MONTHMATERIAL_CALENDAR_VIEW_WEEKMATERIAL_CALLMATERIAL_CALL_ENDMATERIAL_CALL_MADEMATERIAL_CALL_MERGEMATERIAL_CALL_MISSEDMATERIAL_CALL_MISSED_OUTGOINGMATERIAL_CALL_RECEIVEDMATERIAL_CALL_SPLITMATERIAL_CALL_TO_ACTIONMATERIAL_CAMERAMATERIAL_CAMERASWITCHMATERIAL_CAMERA_ALTMATERIAL_CAMERA_ENHANCEMATERIAL_CAMERA_FRONTMATERIAL_CAMERA_INDOORMATERIAL_CAMERA_OUTDOORMATERIAL_CAMERA_REARMATERIAL_CAMERA_ROLLMATERIAL_CAMPAIGNMATERIAL_CANCELMATERIAL_CANCEL_PRESENTATIONMATERIAL_CANCEL_SCHEDULE_SENDMATERIAL_CANDLESTICK_CHARTMATERIAL_CARD_GIFTCARDMATERIAL_CARD_MEMBERSHIPMATERIAL_CARD_TRAVELMATERIAL_CARPENTERMATERIAL_CAR_CRASHMATERIAL_CAR_RENTALMATERIAL_CAR_REPAIRMATERIAL_CASESMATERIAL_CASINOMATERIAL_CASTMATERIAL_CASTLEMATERIAL_CAST_CONNECTEDMATERIAL_CAST_FOR_EDUCATIONMATERIAL_CATCHING_POKEMONMATERIAL_CATEGORYMATERIAL_CELEBRATIONMATERIAL_CELL_TOWERMATERIAL_CELL_WIFIMATERIAL_CENTER_FOCUS_STRONGMATERIAL_CENTER_FOCUS_WEAKMATERIAL_CHAIRMATERIAL_CHAIR_ALTMATERIAL_CHALETMATERIAL_CHANGE_CIRCLEMATERIAL_CHANGE_HISTORYMATERIAL_CHARGING_STATIONMATERIAL_CHATMATERIAL_CHAT_BUBBLEMATERIAL_CHAT_BUBBLE_OUTLINEMATERIAL_CHECKMATERIAL_CHECKLISTMATERIAL_CHECKLIST_RTLMATERIAL_CHECKROOMMATERIAL_CHECK_BOXMATERIAL_CHECK_BOX_OUTLINE_BLANKMATERIAL_CHECK_CIRCLEMATERIAL_CHECK_CIRCLE_OUTLINEMATERIAL_CHEVRON_LEFTMATERIAL_CHEVRON_RIGHTMATERIAL_CHILD_CAREMATERIAL_CHILD_FRIENDLYMATERIAL_CHROME_READER_MODEMATERIAL_CHURCHMATERIAL_CIRCLEMATERIAL_CIRCLE_NOTIFICATIONSMATERIAL_CLASSMATERIAL_CLEANING_SERVICESMATERIAL_CLEAN_HANDSMATERIAL_CLEARMATERIAL_CLEAR_ALLMATERIAL_CLOSEMATERIAL_CLOSED_CAPTIONMATERIAL_CLOSED_CAPTION_DISABLEDMATERIAL_CLOSED_CAPTION_OFFMATERIAL_CLOSE_FULLSCREENMATERIAL_CLOUDMATERIAL_CLOUDY_SNOWINGMATERIAL_CLOUD_CIRCLEMATERIAL_CLOUD_DONEMATERIAL_CLOUD_DOWNLOADMATERIAL_CLOUD_OFFMATERIAL_CLOUD_QUEUEMATERIAL_CLOUD_SYNCMATERIAL_CLOUD_UPLOADMATERIAL_CO2MATERIAL_CODEMATERIAL_CODE_OFFMATERIAL_COFFEEMATERIAL_COFFEE_MAKERMATERIAL_COLLECTIONSMATERIAL_COLLECTIONS_BOOKMARKMATERIAL_COLORIZEMATERIAL_COLOR_LENSMATERIAL_COMMENTMATERIAL_COMMENTS_DISABLEDMATERIAL_COMMENT_BANKMATERIAL_COMMITMATERIAL_COMMUTEMATERIAL_COMPAREMATERIAL_COMPARE_ARROWSMATERIAL_COMPASS_CALIBRATIONMATERIAL_COMPOSTMATERIAL_COMPRESSMATERIAL_COMPUTERMATERIAL_CONFIRMATION_NUMMATERIAL_CONFIRMATION_NUMBERMATERIAL_CONNECTED_TVMATERIAL_CONNECTING_AIRPORTSMATERIAL_CONNECT_WITHOUT_CONTACTMATERIAL_CONSTRUCTIONMATERIAL_CONTACTLESSMATERIAL_CONTACTSMATERIAL_CONTACT_EMERGENCYMATERIAL_CONTACT_MAILMATERIAL_CONTACT_PAGEMATERIAL_CONTACT_PHONEMATERIAL_CONTACT_SUPPORTMATERIAL_CONTENT_COPYMATERIAL_CONTENT_CUTMATERIAL_CONTENT_PASTEMATERIAL_CONTENT_PASTE_GOMATERIAL_CONTENT_PASTE_OFFMATERIAL_CONTENT_PASTE_SEARCHMATERIAL_CONTRASTMATERIAL_CONTROL_CAMERAMATERIAL_CONTROL_POINTMATERIAL_CONTROL_POINT_DUPLICATEMATERIAL_CONVEYOR_BELTMATERIAL_COOKIEMATERIAL_COPYRIGHTMATERIAL_COPY_ALLMATERIAL_CORONAVIRUSMATERIAL_CORPORATE_FAREMATERIAL_COTTAGEMATERIAL_COUNTERTOPSMATERIAL_CO_PRESENTMATERIAL_CREATEMATERIAL_CREATE_NEW_FOLDERMATERIAL_CREDIT_CARDMATERIAL_CREDIT_CARD_OFFMATERIAL_CREDIT_SCOREMATERIAL_CRIBMATERIAL_CRISIS_ALERTMATERIAL_CROPMATERIAL_CROP_16_9MATERIAL_CROP_3_2MATERIAL_CROP_5_4MATERIAL_CROP_7_5MATERIAL_CROP_DINMATERIAL_CROP_FREEMATERIAL_CROP_LANDSCAPEMATERIAL_CROP_ORIGINALMATERIAL_CROP_PORTRAITMATERIAL_CROP_ROTATEMATERIAL_CROP_SQUAREMATERIAL_CRUELTY_FREEMATERIAL_CSSMATERIAL_CURRENCY_BITCOINMATERIAL_CURRENCY_EXCHANGEMATERIAL_CURRENCY_FRANCMATERIAL_CURRENCY_LIRAMATERIAL_CURRENCY_POUNDMATERIAL_CURRENCY_RUBLEMATERIAL_CURRENCY_RUPEEMATERIAL_CURRENCY_YENMATERIAL_CURRENCY_YUANMATERIAL_CURTAINSMATERIAL_CURTAINS_CLOSEDMATERIAL_CYCLONEMATERIAL_DANGEROUSMATERIAL_DARK_MODEMATERIAL_DASHBOARDMATERIAL_DASHBOARD_CUSTOMIZEMATERIAL_DATASETMATERIAL_DATASET_LINKEDMATERIAL_DATA_ARRAYMATERIAL_DATA_EXPLORATIONMATERIAL_DATA_OBJECTMATERIAL_DATA_SAVER_OFFMATERIAL_DATA_SAVER_ONMATERIAL_DATA_THRESHOLDINGMATERIAL_DATA_USAGEMATERIAL_DATE_RANGEMATERIAL_DEBLURMATERIAL_DECKMATERIAL_DEHAZEMATERIAL_DELETEMATERIAL_DELETE_FOREVERMATERIAL_DELETE_OUTLINEMATERIAL_DELETE_SWEEPMATERIAL_DELIVERY_DININGMATERIAL_DENSITY_LARGEMATERIAL_DENSITY_MEDIUMMATERIAL_DENSITY_SMALLMATERIAL_DEPARTURE_BOARDMATERIAL_DESCRIPTIONMATERIAL_DESELECTMATERIAL_DESIGN_SERVICESMATERIAL_DESKMATERIAL_DESKTOP_ACCESS_DISABLEDMATERIAL_DESKTOP_MACMATERIAL_DESKTOP_WINDOWSMATERIAL_DETAILSMATERIAL_DEVELOPER_BOARDMATERIAL_DEVELOPER_BOARD_OFFMATERIAL_DEVELOPER_MODEMATERIAL_DEVICESMATERIAL_DEVICES_FOLDMATERIAL_DEVICES_OTHERMATERIAL_DEVICE_HUBMATERIAL_DEVICE_THERMOSTATMATERIAL_DEVICE_UNKNOWNMATERIAL_DEW_POINTMATERIAL_DIALER_SIPMATERIAL_DIALPADMATERIAL_DIAMONDMATERIAL_DIFFERENCEMATERIAL_DININGMATERIAL_DINNER_DININGMATERIAL_DIRECTIONSMATERIAL_DIRECTIONS_BIKEMATERIAL_DIRECTIONS_BOATMATERIAL_DIRECTIONS_BOAT_FILLEDMATERIAL_DIRECTIONS_BUSMATERIAL_DIRECTIONS_BUS_FILLEDMATERIAL_DIRECTIONS_CARMATERIAL_DIRECTIONS_CAR_FILLEDMATERIAL_DIRECTIONS_FERRYMATERIAL_DIRECTIONS_OFFMATERIAL_DIRECTIONS_RAILWAYMATERIAL_DIRECTIONS_RAILWAY_FILLEDMATERIAL_DIRECTIONS_RUNMATERIAL_DIRECTIONS_SUBWAYMATERIAL_DIRECTIONS_SUBWAY_FILLEDMATERIAL_DIRECTIONS_TRAINMATERIAL_DIRECTIONS_TRANSITMATERIAL_DIRECTIONS_TRANSIT_FILLEDMATERIAL_DIRECTIONS_WALKMATERIAL_DIRTY_LENSMATERIAL_DISABLED_BY_DEFAULTMATERIAL_DISABLED_VISIBLEMATERIAL_DISCORDMATERIAL_DISCOUNTMATERIAL_DISC_FULLMATERIAL_DISPLAY_SETTINGSMATERIAL_DIVERSITY_1MATERIAL_DIVERSITY_2MATERIAL_DIVERSITY_3MATERIAL_DND_FORWARDSLASHMATERIAL_DNSMATERIAL_DOCKMATERIAL_DOCUMENT_SCANNERMATERIAL_DOMAINMATERIAL_DOMAIN_ADDMATERIAL_DOMAIN_DISABLEDMATERIAL_DOMAIN_VERIFICATIONMATERIAL_DONEMATERIAL_DONE_ALLMATERIAL_DONE_OUTLINEMATERIAL_DONUT_LARGEMATERIAL_DONUT_SMALLMATERIAL_DOORBELLMATERIAL_DOOR_BACKMATERIAL_DOOR_FRONTMATERIAL_DOOR_SLIDINGMATERIAL_DOUBLE_ARROWMATERIAL_DOWNHILL_SKIINGMATERIAL_DOWNLOADMATERIAL_DOWNLOADINGMATERIAL_DOWNLOAD_DONEMATERIAL_DOWNLOAD_FOR_OFFLINEMATERIAL_DO_DISTURBMATERIAL_DO_DISTURB_ALTMATERIAL_DO_DISTURB_OFFMATERIAL_DO_DISTURB_ONMATERIAL_DO_NOT_DISTURBMATERIAL_DO_NOT_DISTURB_ALTMATERIAL_DO_NOT_DISTURB_OFFMATERIAL_DO_NOT_DISTURB_ONMATERIAL_DO_NOT_DISTURB_ON_TOTAL_SILENCEMATERIAL_DO_NOT_STEPMATERIAL_DO_NOT_TOUCHMATERIAL_DRAFTSMATERIAL_DRAG_HANDLEMATERIAL_DRAG_INDICATORMATERIAL_DRAWMATERIAL_DRIVE_ETAMATERIAL_DRIVE_FILE_MOVEMATERIAL_DRIVE_FILE_MOVE_OUTLINEMATERIAL_DRIVE_FILE_MOVE_RTLMATERIAL_DRIVE_FILE_RENAME_OUTLINEMATERIAL_DRIVE_FOLDER_UPLOADMATERIAL_DRYMATERIAL_DRY_CLEANINGMATERIAL_DUOMATERIAL_DVRMATERIAL_DYNAMIC_FEEDMATERIAL_DYNAMIC_FORMMATERIAL_EARBUDSMATERIAL_EARBUDS_BATTERYMATERIAL_EASTMATERIAL_ECOMATERIAL_EDGESENSOR_HIGHMATERIAL_EDGESENSOR_LOWMATERIAL_EDITMATERIAL_EDIT_ATTRIBUTESMATERIAL_EDIT_CALENDARMATERIAL_EDIT_DOCUMENTMATERIAL_EDIT_LOCATIONMATERIAL_EDIT_LOCATION_ALTMATERIAL_EDIT_NOTEMATERIAL_EDIT_NOTIFICATIONSMATERIAL_EDIT_OFFMATERIAL_EDIT_ROADMATERIAL_EDIT_SQUAREMATERIAL_EGGMATERIAL_EGG_ALTMATERIAL_EJECTMATERIAL_ELDERLYMATERIAL_ELDERLY_WOMANMATERIAL_ELECTRICAL_SERVICESMATERIAL_ELECTRIC_BIKEMATERIAL_ELECTRIC_BOLTMATERIAL_ELECTRIC_CARMATERIAL_ELECTRIC_METERMATERIAL_ELECTRIC_MOPEDMATERIAL_ELECTRIC_RICKSHAWMATERIAL_ELECTRIC_SCOOTERMATERIAL_ELEVATORMATERIAL_EMAILMATERIAL_EMERGENCYMATERIAL_EMERGENCY_RECORDINGMATERIAL_EMERGENCY_SHAREMATERIAL_EMOJI_EMOTIONSMATERIAL_EMOJI_EVENTSMATERIAL_EMOJI_FLAGSMATERIAL_EMOJI_FOOD_BEVERAGEMATERIAL_EMOJI_NATUREMATERIAL_EMOJI_OBJECTSMATERIAL_EMOJI_PEOPLEMATERIAL_EMOJI_SYMBOLSMATERIAL_EMOJI_TRANSPORTATIONMATERIAL_ENERGY_SAVINGS_LEAFMATERIAL_ENGINEERINGMATERIAL_ENHANCED_ENCRYPTIONMATERIAL_ENHANCE_PHOTO_TRANSLATEMATERIAL_EQUALIZERMATERIAL_ERRORMATERIAL_ERROR_OUTLINEMATERIAL_ESCALATORMATERIAL_ESCALATOR_WARNINGMATERIAL_EUROMATERIAL_EURO_SYMBOLMATERIAL_EVENTMATERIAL_EVENT_AVAILABLEMATERIAL_EVENT_BUSYMATERIAL_EVENT_NOTEMATERIAL_EVENT_REPEATMATERIAL_EVENT_SEATMATERIAL_EV_STATIONMATERIAL_EXIT_TO_APPMATERIAL_EXPANDMATERIAL_EXPAND_CIRCLE_DOWNMATERIAL_EXPAND_LESSMATERIAL_EXPAND_MOREMATERIAL_EXPLICITMATERIAL_EXPLOREMATERIAL_EXPLORE_OFFMATERIAL_EXPOSUREMATERIAL_EXPOSURE_MINUS_1MATERIAL_EXPOSURE_MINUS_2MATERIAL_EXPOSURE_NEG_1MATERIAL_EXPOSURE_NEG_2MATERIAL_EXPOSURE_PLUS_1MATERIAL_EXPOSURE_PLUS_2MATERIAL_EXPOSURE_ZEROMATERIAL_EXTENSIONMATERIAL_EXTENSION_OFFMATERIAL_E_MOBILEDATAMATERIAL_FACEMATERIAL_FACEBOOKMATERIAL_FACE_2MATERIAL_FACE_3MATERIAL_FACE_4MATERIAL_FACE_5MATERIAL_FACE_6MATERIAL_FACE_RETOUCHING_NATURALMATERIAL_FACE_RETOUCHING_OFFMATERIAL_FACTORYMATERIAL_FACT_CHECKMATERIAL_FAMILY_RESTROOMMATERIAL_FASTFOODMATERIAL_FAST_FORWARDMATERIAL_FAST_REWINDMATERIAL_FAVORITEMATERIAL_FAVORITE_BORDERMATERIAL_FAVORITE_OUTLINEMATERIAL_FAXMATERIAL_FEATURED_PLAY_LISTMATERIAL_FEATURED_VIDEOMATERIAL_FEEDMATERIAL_FEEDBACKMATERIAL_FEMALEMATERIAL_FENCEMATERIAL_FESTIVALMATERIAL_FIBER_DVRMATERIAL_FIBER_MANUAL_RECORDMATERIAL_FIBER_NEWMATERIAL_FIBER_PINMATERIAL_FIBER_SMART_RECORDMATERIAL_FILE_COPYMATERIAL_FILE_DOWNLOADMATERIAL_FILE_DOWNLOAD_DONEMATERIAL_FILE_DOWNLOAD_OFFMATERIAL_FILE_OPENMATERIAL_FILE_PRESENTMATERIAL_FILE_UPLOADMATERIAL_FILE_UPLOAD_OFFMATERIAL_FILTERMATERIAL_FILTER_1MATERIAL_FILTER_2MATERIAL_FILTER_3MATERIAL_FILTER_4MATERIAL_FILTER_5MATERIAL_FILTER_6MATERIAL_FILTER_7MATERIAL_FILTER_8MATERIAL_FILTER_9MATERIAL_FILTER_9_PLUSMATERIAL_FILTER_ALTMATERIAL_FILTER_ALT_OFFMATERIAL_FILTER_B_AND_WMATERIAL_FILTER_CENTER_FOCUSMATERIAL_FILTER_DRAMAMATERIAL_FILTER_FRAMESMATERIAL_FILTER_HDRMATERIAL_FILTER_LISTMATERIAL_FILTER_LIST_ALTMATERIAL_FILTER_LIST_OFFMATERIAL_FILTER_NONEMATERIAL_FILTER_TILT_SHIFTMATERIAL_FILTER_VINTAGEMATERIAL_FIND_IN_PAGEMATERIAL_FIND_REPLACEMATERIAL_FINGERPRINTMATERIAL_FIREPLACEMATERIAL_FIRE_EXTINGUISHERMATERIAL_FIRE_HYDRANTMATERIAL_FIRE_HYDRANT_ALTMATERIAL_FIRE_TRUCKMATERIAL_FIRST_PAGEMATERIAL_FITBITMATERIAL_FITNESS_CENTERMATERIAL_FIT_SCREENMATERIAL_FLAGMATERIAL_FLAG_CIRCLEMATERIAL_FLAKYMATERIAL_FLAREMATERIAL_FLASHLIGHT_OFFMATERIAL_FLASHLIGHT_ONMATERIAL_FLASH_AUTOMATERIAL_FLASH_OFFMATERIAL_FLASH_ONMATERIAL_FLATWAREMATERIAL_FLIGHTMATERIAL_FLIGHT_CLASSMATERIAL_FLIGHT_LANDMATERIAL_FLIGHT_TAKEOFFMATERIAL_FLIPMATERIAL_FLIP_CAMERA_ANDROIDMATERIAL_FLIP_CAMERA_IOSMATERIAL_FLIP_TO_BACKMATERIAL_FLIP_TO_FRONTMATERIAL_FLOODMATERIAL_FLOURESCENTMATERIAL_FLUORESCENTMATERIAL_FLUTTER_DASHMATERIAL_FMD_BADMATERIAL_FMD_GOODMATERIAL_FOGGYMATERIAL_FOLDERMATERIAL_FOLDER_COPYMATERIAL_FOLDER_DELETEMATERIAL_FOLDER_OFFMATERIAL_FOLDER_OPENMATERIAL_FOLDER_SHAREDMATERIAL_FOLDER_SPECIALMATERIAL_FOLDER_ZIPMATERIAL_FOLLOW_THE_SIGNSMATERIAL_FONT_DOWNLOADMATERIAL_FONT_DOWNLOAD_OFFMATERIAL_FOOD_BANKMATERIAL_FORESTMATERIAL_FORKLIFTMATERIAL_FORK_LEFTMATERIAL_FORK_RIGHTMATERIAL_FORMAT_ALIGN_CENTERMATERIAL_FORMAT_ALIGN_JUSTIFYMATERIAL_FORMAT_ALIGN_LEFTMATERIAL_FORMAT_ALIGN_RIGHTMATERIAL_FORMAT_BOLDMATERIAL_FORMAT_CLEARMATERIAL_FORMAT_COLOR_FILLMATERIAL_FORMAT_COLOR_RESETMATERIAL_FORMAT_COLOR_TEXTMATERIAL_FORMAT_INDENT_DECREASEMATERIAL_FORMAT_INDENT_INCREASEMATERIAL_FORMAT_ITALICMATERIAL_FORMAT_LINE_SPACINGMATERIAL_FORMAT_LIST_BULLETEDMATERIAL_FORMAT_LIST_BULLETED_ADDMATERIAL_FORMAT_LIST_NUMBEREDMATERIAL_FORMAT_LIST_NUMBERED_RTLMATERIAL_FORMAT_OVERLINEMATERIAL_FORMAT_PAINTMATERIAL_FORMAT_QUOTEMATERIAL_FORMAT_SHAPESMATERIAL_FORMAT_SIZEMATERIAL_FORMAT_STRIKETHROUGHMATERIAL_FORMAT_TEXTDIRECTION_L_TO_RMATERIAL_FORMAT_TEXTDIRECTION_R_TO_LMATERIAL_FORMAT_UNDERLINEMATERIAL_FORMAT_UNDERLINEDMATERIAL_FORTMATERIAL_FORUMMATERIAL_FORWARDMATERIAL_FORWARD_10MATERIAL_FORWARD_30MATERIAL_FORWARD_5MATERIAL_FORWARD_TO_INBOXMATERIAL_FOUNDATIONMATERIAL_FREE_BREAKFASTMATERIAL_FREE_CANCELLATIONMATERIAL_FRONT_HANDMATERIAL_FRONT_LOADERMATERIAL_FULLSCREENMATERIAL_FULLSCREEN_EXITMATERIAL_FUNCTIONSMATERIAL_GAMEPADMATERIAL_GAMESMATERIAL_GARAGEMATERIAL_GAS_METERMATERIAL_GAVELMATERIAL_GENERATING_TOKENSMATERIAL_GESTUREMATERIAL_GET_APPMATERIAL_GIFMATERIAL_GIF_BOXMATERIAL_GIRLMATERIAL_GITEMATERIAL_GOLF_COURSEMATERIAL_GPP_BADMATERIAL_GPP_GOODMATERIAL_GPP_MAYBEMATERIAL_GPS_FIXEDMATERIAL_GPS_NOT_FIXEDMATERIAL_GPS_OFFMATERIAL_GRADEMATERIAL_GRADIENTMATERIAL_GRADINGMATERIAL_GRAINMATERIAL_GRAPHIC_EQMATERIAL_GRASSMATERIAL_GRID_3X3MATERIAL_GRID_4X4MATERIAL_GRID_GOLDENRATIOMATERIAL_GRID_OFFMATERIAL_GRID_ONMATERIAL_GRID_VIEWMATERIAL_GROUPMATERIAL_GROUPSMATERIAL_GROUPS_2MATERIAL_GROUPS_3MATERIAL_GROUP_ADDMATERIAL_GROUP_OFFMATERIAL_GROUP_REMOVEMATERIAL_GROUP_WORKMATERIAL_G_MOBILEDATAMATERIAL_G_TRANSLATEMATERIAL_HAILMATERIAL_HANDSHAKEMATERIAL_HANDYMANMATERIAL_HARDWAREMATERIAL_HDMATERIAL_HDR_AUTOMATERIAL_HDR_AUTO_SELECTMATERIAL_HDR_ENHANCED_SELECTMATERIAL_HDR_OFFMATERIAL_HDR_OFF_SELECTMATERIAL_HDR_ONMATERIAL_HDR_ON_SELECTMATERIAL_HDR_PLUSMATERIAL_HDR_STRONGMATERIAL_HDR_WEAKMATERIAL_HEADPHONESMATERIAL_HEADPHONES_BATTERYMATERIAL_HEADSETMATERIAL_HEADSET_MICMATERIAL_HEADSET_OFFMATERIAL_HEALINGMATERIAL_HEALTH_AND_SAFETYMATERIAL_HEARINGMATERIAL_HEARING_DISABLEDMATERIAL_HEART_BROKENMATERIAL_HEAT_PUMPMATERIAL_HEIGHTMATERIAL_HELPMATERIAL_HELP_CENTERMATERIAL_HELP_OUTLINEMATERIAL_HEVCMATERIAL_HEXAGONMATERIAL_HIDE_IMAGEMATERIAL_HIDE_SOURCEMATERIAL_HIGHLIGHTMATERIAL_HIGHLIGHT_ALTMATERIAL_HIGHLIGHT_OFFMATERIAL_HIGHLIGHT_REMOVEMATERIAL_HIGH_QUALITYMATERIAL_HIKINGMATERIAL_HISTORYMATERIAL_HISTORY_EDUMATERIAL_HISTORY_TOGGLE_OFFMATERIAL_HIVEMATERIAL_HLSMATERIAL_HLS_OFFMATERIAL_HOLIDAY_VILLAGEMATERIAL_HOMEMATERIAL_HOME_FILLEDMATERIAL_HOME_MAXMATERIAL_HOME_MINIMATERIAL_HOME_REPAIR_SERVICEMATERIAL_HOME_WORKMATERIAL_HORIZONTAL_DISTRIBUTEMATERIAL_HORIZONTAL_RULEMATERIAL_HORIZONTAL_SPLITMATERIAL_HOTELMATERIAL_HOTEL_CLASSMATERIAL_HOT_TUBMATERIAL_HOURGLASS_BOTTOMMATERIAL_HOURGLASS_DISABLEDMATERIAL_HOURGLASS_EMPTYMATERIAL_HOURGLASS_FULLMATERIAL_HOURGLASS_TOPMATERIAL_HOUSEMATERIAL_HOUSEBOATMATERIAL_HOUSE_SIDINGMATERIAL_HOW_TO_REGMATERIAL_HOW_TO_VOTEMATERIAL_HTMLMATERIAL_HTTPMATERIAL_HTTPSMATERIAL_HUBMATERIAL_HVACMATERIAL_H_MOBILEDATAMATERIAL_H_PLUS_MOBILEDATAMATERIAL_ICECREAMMATERIAL_ICE_SKATINGMATERIAL_IMAGEMATERIAL_IMAGESEARCH_ROLLERMATERIAL_IMAGE_ASPECT_RATIOMATERIAL_IMAGE_NOT_SUPPORTEDMATERIAL_IMAGE_SEARCHMATERIAL_IMPORTANT_DEVICESMATERIAL_IMPORT_CONTACTSMATERIAL_IMPORT_EXPORTMATERIAL_INBOXMATERIAL_INCOMPLETE_CIRCLEMATERIAL_INDETERMINATE_CHECK_BOXMATERIAL_INFOMATERIAL_INFO_OUTLINEMATERIAL_INPUTMATERIAL_INSERT_CHARTMATERIAL_INSERT_CHART_OUTLINEDMATERIAL_INSERT_COMMENTMATERIAL_INSERT_DRIVE_FILEMATERIAL_INSERT_EMOTICONMATERIAL_INSERT_INVITATIONMATERIAL_INSERT_LINKMATERIAL_INSERT_PAGE_BREAKMATERIAL_INSERT_PHOTOMATERIAL_INSIGHTSMATERIAL_INSTALL_DESKTOPMATERIAL_INSTALL_MOBILEMATERIAL_INTEGRATION_INSTRUCTIONSMATERIAL_INTERESTSMATERIAL_INTERPRETER_MODEMATERIAL_INVENTORYMATERIAL_INVENTORY_2MATERIAL_INVERT_COLORSMATERIAL_INVERT_COLORS_OFFMATERIAL_INVERT_COLORS_ONMATERIAL_IOS_SHAREMATERIAL_IRONMATERIAL_ISOMATERIAL_JAVASCRIPTMATERIAL_JOIN_FULLMATERIAL_JOIN_INNERMATERIAL_JOIN_LEFTMATERIAL_JOIN_RIGHTMATERIAL_KAYAKINGMATERIAL_KEBAB_DININGMATERIAL_KEYMATERIAL_KEYBOARDMATERIAL_KEYBOARD_ALTMATERIAL_KEYBOARD_ARROW_DOWNMATERIAL_KEYBOARD_ARROW_LEFTMATERIAL_KEYBOARD_ARROW_RIGHTMATERIAL_KEYBOARD_ARROW_UPMATERIAL_KEYBOARD_BACKSPACEMATERIAL_KEYBOARD_CAPSLOCKMATERIAL_KEYBOARD_COMMANDMATERIAL_KEYBOARD_COMMAND_KEYMATERIAL_KEYBOARD_CONTROLMATERIAL_KEYBOARD_CONTROL_KEYMATERIAL_KEYBOARD_DOUBLE_ARROW_DOWNMATERIAL_KEYBOARD_DOUBLE_ARROW_LEFTMATERIAL_KEYBOARD_DOUBLE_ARROW_RIGHTMATERIAL_KEYBOARD_DOUBLE_ARROW_UPMATERIAL_KEYBOARD_HIDEMATERIAL_KEYBOARD_OPTIONMATERIAL_KEYBOARD_OPTION_KEYMATERIAL_KEYBOARD_RETURNMATERIAL_KEYBOARD_TABMATERIAL_KEYBOARD_VOICEMATERIAL_KEY_OFFMATERIAL_KING_BEDMATERIAL_KITCHENMATERIAL_KITESURFINGMATERIAL_LABELMATERIAL_LABEL_IMPORTANTMATERIAL_LABEL_IMPORTANT_OUTLINEMATERIAL_LABEL_OFFMATERIAL_LABEL_OUTLINEMATERIAL_LANMATERIAL_LANDSCAPEMATERIAL_LANDSLIDEMATERIAL_LANGUAGEMATERIAL_LAPTOPMATERIAL_LAPTOP_CHROMEBOOKMATERIAL_LAPTOP_MACMATERIAL_LAPTOP_WINDOWSMATERIAL_LAST_PAGEMATERIAL_LAUNCHMATERIAL_LAYERSMATERIAL_LAYERS_CLEARMATERIAL_LEADERBOARDMATERIAL_LEAK_ADDMATERIAL_LEAK_REMOVEMATERIAL_LEAVE_BAGS_AT_HOMEMATERIAL_LEGEND_TOGGLEMATERIAL_LENSMATERIAL_LENS_BLURMATERIAL_LIBRARY_ADDMATERIAL_LIBRARY_ADD_CHECKMATERIAL_LIBRARY_BOOKSMATERIAL_LIBRARY_MUSICMATERIAL_LIGHTMATERIAL_LIGHTBULBMATERIAL_LIGHTBULB_CIRCLEMATERIAL_LIGHTBULB_OUTLINEMATERIAL_LIGHT_MODEMATERIAL_LINEAR_SCALEMATERIAL_LINE_AXISMATERIAL_LINE_STYLEMATERIAL_LINE_WEIGHTMATERIAL_LINKMATERIAL_LINKED_CAMERAMATERIAL_LINK_OFFMATERIAL_LIQUORMATERIAL_LISTMATERIAL_LIST_ALTMATERIAL_LIVE_HELPMATERIAL_LIVE_TVMATERIAL_LIVINGMATERIAL_LOCAL_ACTIVITYMATERIAL_LOCAL_AIRPORTMATERIAL_LOCAL_ATMMATERIAL_LOCAL_ATTRACTIONMATERIAL_LOCAL_BARMATERIAL_LOCAL_CAFEMATERIAL_LOCAL_CAR_WASHMATERIAL_LOCAL_CONVENIENCE_STOREMATERIAL_LOCAL_DININGMATERIAL_LOCAL_DRINKMATERIAL_LOCAL_FIRE_DEPARTMENTMATERIAL_LOCAL_FLORISTMATERIAL_LOCAL_GAS_STATIONMATERIAL_LOCAL_GROCERY_STOREMATERIAL_LOCAL_HOSPITALMATERIAL_LOCAL_HOTELMATERIAL_LOCAL_LAUNDRY_SERVICEMATERIAL_LOCAL_LIBRARYMATERIAL_LOCAL_MALLMATERIAL_LOCAL_MOVIESMATERIAL_LOCAL_OFFERMATERIAL_LOCAL_PARKINGMATERIAL_LOCAL_PHARMACYMATERIAL_LOCAL_PHONEMATERIAL_LOCAL_PIZZAMATERIAL_LOCAL_PLAYMATERIAL_LOCAL_POLICEMATERIAL_LOCAL_POST_OFFICEMATERIAL_LOCAL_PRINTSHOPMATERIAL_LOCAL_PRINT_SHOPMATERIAL_LOCAL_RESTAURANTMATERIAL_LOCAL_SEEMATERIAL_LOCAL_SHIPPINGMATERIAL_LOCAL_TAXIMATERIAL_LOCATION_CITYMATERIAL_LOCATION_DISABLEDMATERIAL_LOCATION_HISTORYMATERIAL_LOCATION_OFFMATERIAL_LOCATION_ONMATERIAL_LOCATION_PINMATERIAL_LOCATION_SEARCHINGMATERIAL_LOCKMATERIAL_LOCK_CLOCKMATERIAL_LOCK_OPENMATERIAL_LOCK_OUTLINEMATERIAL_LOCK_PERSONMATERIAL_LOCK_RESETMATERIAL_LOGINMATERIAL_LOGOUTMATERIAL_LOGO_DEVMATERIAL_LOOKSMATERIAL_LOOKS_3MATERIAL_LOOKS_4MATERIAL_LOOKS_5MATERIAL_LOOKS_6MATERIAL_LOOKS_ONEMATERIAL_LOOKS_TWOMATERIAL_LOOPMATERIAL_LOUPEMATERIAL_LOW_PRIORITYMATERIAL_LOYALTYMATERIAL_LTE_MOBILEDATAMATERIAL_LTE_PLUS_MOBILEDATAMATERIAL_LUGGAGEMATERIAL_LUNCH_DININGMATERIAL_LYRICSMATERIAL_MACRO_OFFMATERIAL_MAILMATERIAL_MAIL_LOCKMATERIAL_MAIL_OUTLINEMATERIAL_MALEMATERIAL_MANMATERIAL_MANAGE_ACCOUNTSMATERIAL_MANAGE_HISTORYMATERIAL_MANAGE_SEARCHMATERIAL_MAN_2MATERIAL_MAN_3MATERIAL_MAN_4MATERIAL_MAPMATERIAL_MAPS_HOME_WORKMATERIAL_MAPS_UGCMATERIAL_MARGINMATERIAL_MARKUNREADMATERIAL_MARKUNREAD_MAILBOXMATERIAL_MARK_AS_UNREADMATERIAL_MARK_CHAT_READMATERIAL_MARK_CHAT_UNREADMATERIAL_MARK_EMAIL_READMATERIAL_MARK_EMAIL_UNREADMATERIAL_MARK_UNREAD_CHAT_ALTMATERIAL_MASKSMATERIAL_MAXIMIZEMATERIAL_MEDIATIONMATERIAL_MEDIA_BLUETOOTH_OFFMATERIAL_MEDIA_BLUETOOTH_ONMATERIAL_MEDICAL_INFORMATIONMATERIAL_MEDICAL_SERVICESMATERIAL_MEDICATIONMATERIAL_MEDICATION_LIQUIDMATERIAL_MEETING_ROOMMATERIAL_MEMORYMATERIAL_MENUMATERIAL_MENU_BOOKMATERIAL_MENU_OPENMATERIAL_MERGEMATERIAL_MERGE_TYPEMATERIAL_MESSAGEMATERIAL_MESSENGERMATERIAL_MESSENGER_OUTLINEMATERIAL_MICMATERIAL_MICROWAVEMATERIAL_MIC_EXTERNAL_OFFMATERIAL_MIC_EXTERNAL_ONMATERIAL_MIC_NONEMATERIAL_MIC_OFFMATERIAL_MILITARY_TECHMATERIAL_MINIMIZEMATERIAL_MINOR_CRASHMATERIAL_MISCELLANEOUS_SERVICESMATERIAL_MISSED_VIDEO_CALLMATERIAL_MMSMATERIAL_MOBILEDATA_OFFMATERIAL_MOBILE_FRIENDLYMATERIAL_MOBILE_OFFMATERIAL_MOBILE_SCREEN_SHAREMATERIAL_MODEMATERIAL_MODEL_TRAININGMATERIAL_MODE_COMMENTMATERIAL_MODE_EDITMATERIAL_MODE_EDIT_OUTLINEMATERIAL_MODE_FAN_OFFMATERIAL_MODE_NIGHTMATERIAL_MODE_OF_TRAVELMATERIAL_MODE_STANDBYMATERIAL_MONETIZATION_ONMATERIAL_MONEYMATERIAL_MONEY_OFFMATERIAL_MONEY_OFF_CSREDMATERIAL_MONITORMATERIAL_MONITOR_HEARTMATERIAL_MONITOR_WEIGHTMATERIAL_MONOCHROME_PHOTOSMATERIAL_MOODMATERIAL_MOOD_BADMATERIAL_MOPEDMATERIAL_MOREMATERIAL_MORE_HORIZMATERIAL_MORE_TIMEMATERIAL_MORE_VERTMATERIAL_MOSQUEMATERIAL_MOTION_PHOTOS_AUTOMATERIAL_MOTION_PHOTOS_OFFMATERIAL_MOTION_PHOTOS_ONMATERIAL_MOTION_PHOTOS_PAUSEMATERIAL_MOTION_PHOTOS_PAUSEDMATERIAL_MOTORCYCLEMATERIAL_MOUSEMATERIAL_MOVE_DOWNMATERIAL_MOVE_TO_INBOXMATERIAL_MOVE_UPMATERIAL_MOVIEMATERIAL_MOVIE_CREATIONMATERIAL_MOVIE_EDITMATERIAL_MOVIE_FILTERMATERIAL_MOVINGMATERIAL_MPMATERIAL_MULTILINE_CHARTMATERIAL_MULTIPLE_STOPMATERIAL_MULTITRACK_AUDIOMATERIAL_MUSEUMMATERIAL_MUSIC_NOTEMATERIAL_MUSIC_OFFMATERIAL_MUSIC_VIDEOMATERIAL_MY_LIBRARY_ADDMATERIAL_MY_LIBRARY_BOOKSMATERIAL_MY_LIBRARY_MUSICMATERIAL_MY_LOCATIONMATERIAL_NATMATERIAL_NATUREMATERIAL_NATURE_PEOPLEMATERIAL_NAVIGATE_BEFOREMATERIAL_NAVIGATE_NEXTMATERIAL_NAVIGATIONMATERIAL_NEARBY_ERRORMATERIAL_NEARBY_OFFMATERIAL_NEAR_MEMATERIAL_NEAR_ME_DISABLEDMATERIAL_NEST_CAM_WIRED_STANDMATERIAL_NETWORK_CELLMATERIAL_NETWORK_CHECKMATERIAL_NETWORK_LOCKEDMATERIAL_NETWORK_PINGMATERIAL_NETWORK_WIFIMATERIAL_NETWORK_WIFI_1_BARMATERIAL_NETWORK_WIFI_2_BARMATERIAL_NETWORK_WIFI_3_BARMATERIAL_NEWSPAPERMATERIAL_NEW_LABELMATERIAL_NEW_RELEASESMATERIAL_NEXT_PLANMATERIAL_NEXT_WEEKMATERIAL_NFCMATERIAL_NIGHTLIFEMATERIAL_NIGHTLIGHTMATERIAL_NIGHTLIGHT_ROUNDMATERIAL_NIGHTS_STAYMATERIAL_NIGHT_SHELTERMATERIAL_NOISE_AWAREMATERIAL_NOISE_CONTROL_OFFMATERIAL_NORDIC_WALKINGMATERIAL_NORTHMATERIAL_NORTH_EASTMATERIAL_NORTH_WESTMATERIAL_NOTEMATERIAL_NOTESMATERIAL_NOTE_ADDMATERIAL_NOTE_ALTMATERIAL_NOTIFICATIONSMATERIAL_NOTIFICATIONS_ACTIVEMATERIAL_NOTIFICATIONS_NONEMATERIAL_NOTIFICATIONS_OFFMATERIAL_NOTIFICATIONS_ONMATERIAL_NOTIFICATIONS_PAUSEDMATERIAL_NOTIFICATION_ADDMATERIAL_NOTIFICATION_IMPORTANTMATERIAL_NOT_ACCESSIBLEMATERIAL_NOT_INTERESTEDMATERIAL_NOT_LISTED_LOCATIONMATERIAL_NOT_STARTEDMATERIAL_NOW_WALLPAPERMATERIAL_NOW_WIDGETSMATERIAL_NO_ACCOUNTSMATERIAL_NO_ADULT_CONTENTMATERIAL_NO_BACKPACKMATERIAL_NO_CELLMATERIAL_NO_CRASHMATERIAL_NO_DRINKSMATERIAL_NO_ENCRYPTIONMATERIAL_NO_ENCRYPTION_GMAILERRORREDMATERIAL_NO_FLASHMATERIAL_NO_FOODMATERIAL_NO_LUGGAGEMATERIAL_NO_MEALSMATERIAL_NO_MEALS_OULINEMATERIAL_NO_MEETING_ROOMMATERIAL_NO_PHOTOGRAPHYMATERIAL_NO_SIMMATERIAL_NO_STROLLERMATERIAL_NO_TRANSFERMATERIAL_NUMBERSMATERIAL_OFFLINE_BOLTMATERIAL_OFFLINE_PINMATERIAL_OFFLINE_SHAREMATERIAL_OIL_BARRELMATERIAL_ONDEMAND_VIDEOMATERIAL_ONLINE_PREDICTIONMATERIAL_ON_DEVICE_TRAININGMATERIAL_OPACITYMATERIAL_OPEN_IN_BROWSERMATERIAL_OPEN_IN_FULLMATERIAL_OPEN_IN_NEWMATERIAL_OPEN_IN_NEW_OFFMATERIAL_OPEN_WITHMATERIAL_OTHER_HOUSESMATERIAL_OUTBONDMATERIAL_OUTBOUNDMATERIAL_OUTBOXMATERIAL_OUTDOOR_GRILLMATERIAL_OUTGOING_MAILMATERIAL_OUTLETMATERIAL_OUTLINED_FLAGMATERIAL_OUTPUTMATERIAL_PADDINGMATERIAL_PAGESMATERIAL_PAGEVIEWMATERIAL_PAIDMATERIAL_PALETTEMATERIAL_PALLETMATERIAL_PANORAMAMATERIAL_PANORAMA_FISHEYEMATERIAL_PANORAMA_FISH_EYEMATERIAL_PANORAMA_HORIZONTALMATERIAL_PANORAMA_HORIZONTAL_SELECTMATERIAL_PANORAMA_PHOTOSPHEREMATERIAL_PANORAMA_PHOTOSPHERE_SELECTMATERIAL_PANORAMA_VERTICALMATERIAL_PANORAMA_VERTICAL_SELECTMATERIAL_PANORAMA_WIDE_ANGLEMATERIAL_PANORAMA_WIDE_ANGLE_SELECTMATERIAL_PAN_TOOLMATERIAL_PAN_TOOL_ALTMATERIAL_PARAGLIDINGMATERIAL_PARKMATERIAL_PARTY_MODEMATERIAL_PASSWORDMATERIAL_PATTERNMATERIAL_PAUSEMATERIAL_PAUSE_CIRCLEMATERIAL_PAUSE_CIRCLE_FILLEDMATERIAL_PAUSE_CIRCLE_OUTLINEMATERIAL_PAUSE_PRESENTATIONMATERIAL_PAYMENTMATERIAL_PAYMENTSMATERIAL_PAYPALMATERIAL_PEDAL_BIKEMATERIAL_PENDINGMATERIAL_PENDING_ACTIONSMATERIAL_PENTAGONMATERIAL_PEOPLEMATERIAL_PEOPLE_ALTMATERIAL_PEOPLE_OUTLINEMATERIAL_PERCENTMATERIAL_PERM_CAMERA_MICMATERIAL_PERM_CONTACT_CALMATERIAL_PERM_CONTACT_CALENDARMATERIAL_PERM_DATA_SETTINGMATERIAL_PERM_DEVICE_INFOMATERIAL_PERM_DEVICE_INFORMATIONMATERIAL_PERM_IDENTITYMATERIAL_PERM_MEDIAMATERIAL_PERM_PHONE_MSGMATERIAL_PERM_SCAN_WIFIMATERIAL_PERSONMATERIAL_PERSONAL_INJURYMATERIAL_PERSONAL_VIDEOMATERIAL_PERSON_2MATERIAL_PERSON_3MATERIAL_PERSON_4MATERIAL_PERSON_ADDMATERIAL_PERSON_ADD_ALTMATERIAL_PERSON_ADD_ALT_1MATERIAL_PERSON_ADD_DISABLEDMATERIAL_PERSON_OFFMATERIAL_PERSON_OUTLINEMATERIAL_PERSON_PINMATERIAL_PERSON_PIN_CIRCLEMATERIAL_PERSON_REMOVEMATERIAL_PERSON_REMOVE_ALT_1MATERIAL_PERSON_SEARCHMATERIAL_PEST_CONTROLMATERIAL_PEST_CONTROL_RODENTMATERIAL_PETSMATERIAL_PHISHINGMATERIAL_PHONEMATERIAL_PHONELINKMATERIAL_PHONELINK_ERASEMATERIAL_PHONELINK_LOCKMATERIAL_PHONELINK_OFFMATERIAL_PHONELINK_RINGMATERIAL_PHONELINK_SETUPMATERIAL_PHONE_ANDROIDMATERIAL_PHONE_BLUETOOTH_SPEAKERMATERIAL_PHONE_CALLBACKMATERIAL_PHONE_DISABLEDMATERIAL_PHONE_ENABLEDMATERIAL_PHONE_FORWARDEDMATERIAL_PHONE_IN_TALKMATERIAL_PHONE_IPHONEMATERIAL_PHONE_LOCKEDMATERIAL_PHONE_MISSEDMATERIAL_PHONE_PAUSEDMATERIAL_PHOTOMATERIAL_PHOTO_ALBUMMATERIAL_PHOTO_CAMERAMATERIAL_PHOTO_CAMERA_BACKMATERIAL_PHOTO_CAMERA_FRONTMATERIAL_PHOTO_FILTERMATERIAL_PHOTO_LIBRARYMATERIAL_PHOTO_SIZE_SELECT_ACTUALMATERIAL_PHOTO_SIZE_SELECT_LARGEMATERIAL_PHOTO_SIZE_SELECT_SMALLMATERIAL_PHPMATERIAL_PIANOMATERIAL_PIANO_OFFMATERIAL_PICTURE_AS_PDFMATERIAL_PICTURE_IN_PICTUREMATERIAL_PICTURE_IN_PICTURE_ALTMATERIAL_PIE_CHARTMATERIAL_PIE_CHART_OUTLINEMATERIAL_PIE_CHART_OUTLINEDMATERIAL_PINMATERIAL_PINCHMATERIAL_PIN_DROPMATERIAL_PIN_ENDMATERIAL_PIN_INVOKEMATERIAL_PIVOT_TABLE_CHARTMATERIAL_PIXMATERIAL_PLACEMATERIAL_PLAGIARISMMATERIAL_PLAYLIST_ADDMATERIAL_PLAYLIST_ADD_CHECKMATERIAL_PLAYLIST_ADD_CHECK_CIRCLEMATERIAL_PLAYLIST_ADD_CIRCLEMATERIAL_PLAYLIST_PLAYMATERIAL_PLAYLIST_REMOVEMATERIAL_PLAY_ARROWMATERIAL_PLAY_CIRCLEMATERIAL_PLAY_CIRCLE_FILLMATERIAL_PLAY_CIRCLE_FILLEDMATERIAL_PLAY_CIRCLE_OUTLINEMATERIAL_PLAY_DISABLEDMATERIAL_PLAY_FOR_WORKMATERIAL_PLAY_LESSONMATERIAL_PLUMBINGMATERIAL_PLUS_ONEMATERIAL_PODCASTSMATERIAL_POINT_OF_SALEMATERIAL_POLICYMATERIAL_POLLMATERIAL_POLYLINEMATERIAL_POLYMERMATERIAL_POOLMATERIAL_PORTABLE_WIFI_OFFMATERIAL_PORTRAITMATERIAL_POST_ADDMATERIAL_POWERMATERIAL_POWER_INPUTMATERIAL_POWER_OFFMATERIAL_POWER_SETTINGS_NEWMATERIAL_PRECISION_MANUFACTURINGMATERIAL_PREGNANT_WOMANMATERIAL_PRESENT_TO_ALLMATERIAL_PREVIEWMATERIAL_PRICE_CHANGEMATERIAL_PRICE_CHECKMATERIAL_PRINTMATERIAL_PRINT_DISABLEDMATERIAL_PRIORITY_HIGHMATERIAL_PRIVACY_TIPMATERIAL_PRIVATE_CONNECTIVITYMATERIAL_PRODUCTION_QUANTITY_LIMITSMATERIAL_PROPANEMATERIAL_PROPANE_TANKMATERIAL_PSYCHOLOGYMATERIAL_PSYCHOLOGY_ALTMATERIAL_PUBLICMATERIAL_PUBLIC_OFFMATERIAL_PUBLISHMATERIAL_PUBLISHED_WITH_CHANGESMATERIAL_PUNCH_CLOCKMATERIAL_PUSH_PINMATERIAL_QR_CODEMATERIAL_QR_CODE_2MATERIAL_QR_CODE_SCANNERMATERIAL_QUERY_BUILDERMATERIAL_QUERY_STATSMATERIAL_QUESTION_ANSWERMATERIAL_QUESTION_MARKMATERIAL_QUEUEMATERIAL_QUEUE_MUSICMATERIAL_QUEUE_PLAY_NEXTMATERIAL_QUICKREPLYMATERIAL_QUICK_CONTACTS_DIALERMATERIAL_QUICK_CONTACTS_MAILMATERIAL_QUIZMATERIAL_QUORAMATERIAL_RADARMATERIAL_RADIOMATERIAL_RADIO_BUTTON_CHECKEDMATERIAL_RADIO_BUTTON_OFFMATERIAL_RADIO_BUTTON_ONMATERIAL_RADIO_BUTTON_UNCHECKEDMATERIAL_RAILWAY_ALERTMATERIAL_RAMEN_DININGMATERIAL_RAMP_LEFTMATERIAL_RAMP_RIGHTMATERIAL_RATE_REVIEWMATERIAL_RAW_OFFMATERIAL_RAW_ONMATERIAL_READ_MOREMATERIAL_REAL_ESTATE_AGENTMATERIAL_REBASE_EDITMATERIAL_RECEIPTMATERIAL_RECEIPT_LONGMATERIAL_RECENT_ACTORSMATERIAL_RECOMMENDMATERIAL_RECORD_VOICE_OVERMATERIAL_RECTANGLEMATERIAL_RECYCLINGMATERIAL_REDDITMATERIAL_REDEEMMATERIAL_REDOMATERIAL_REDUCE_CAPACITYMATERIAL_REFRESHMATERIAL_REMEMBER_MEMATERIAL_REMOVEMATERIAL_REMOVE_CIRCLEMATERIAL_REMOVE_CIRCLE_OUTLINEMATERIAL_REMOVE_DONEMATERIAL_REMOVE_FROM_QUEUEMATERIAL_REMOVE_MODERATORMATERIAL_REMOVE_RED_EYEMATERIAL_REMOVE_ROADMATERIAL_REMOVE_SHOPPING_CARTMATERIAL_REORDERMATERIAL_REPARTITIONMATERIAL_REPEATMATERIAL_REPEAT_ONMATERIAL_REPEAT_ONEMATERIAL_REPEAT_ONE_ONMATERIAL_REPLAYMATERIAL_REPLAY_10MATERIAL_REPLAY_30MATERIAL_REPLAY_5MATERIAL_REPLAY_CIRCLE_FILLEDMATERIAL_REPLYMATERIAL_REPLY_ALLMATERIAL_REPORTMATERIAL_REPORT_GMAILERRORREDMATERIAL_REPORT_OFFMATERIAL_REPORT_PROBLEMMATERIAL_REQUEST_PAGEMATERIAL_REQUEST_QUOTEMATERIAL_RESET_TVMATERIAL_RESTART_ALTMATERIAL_RESTAURANTMATERIAL_RESTAURANT_MENUMATERIAL_RESTOREMATERIAL_RESTORE_FROM_TRASHMATERIAL_RESTORE_PAGEMATERIAL_REVIEWSMATERIAL_RICE_BOWLMATERIAL_RING_VOLUMEMATERIAL_ROCKETMATERIAL_ROCKET_LAUNCHMATERIAL_ROLLER_SHADESMATERIAL_ROLLER_SHADES_CLOSEDMATERIAL_ROLLER_SKATINGMATERIAL_ROOFINGMATERIAL_ROOMMATERIAL_ROOM_PREFERENCESMATERIAL_ROOM_SERVICEMATERIAL_ROTATE_90_DEGREES_CCWMATERIAL_ROTATE_90_DEGREES_CWMATERIAL_ROTATE_LEFTMATERIAL_ROTATE_RIGHTMATERIAL_ROUNDABOUT_LEFTMATERIAL_ROUNDABOUT_RIGHTMATERIAL_ROUNDED_CORNERMATERIAL_ROUTEMATERIAL_ROUTERMATERIAL_ROWINGMATERIAL_RSS_FEEDMATERIAL_RSVPMATERIAL_RTTMATERIAL_RULEMATERIAL_RULE_FOLDERMATERIAL_RUNNING_WITH_ERRORSMATERIAL_RUN_CIRCLEMATERIAL_RV_HOOKUPMATERIAL_R_MOBILEDATAMATERIAL_SAFETY_CHECKMATERIAL_SAFETY_DIVIDERMATERIAL_SAILINGMATERIAL_SANITIZERMATERIAL_SATELLITEMATERIAL_SATELLITE_ALTMATERIAL_SAVEMATERIAL_SAVED_SEARCHMATERIAL_SAVE_ALTMATERIAL_SAVE_ASMATERIAL_SAVINGSMATERIAL_SCALEMATERIAL_SCANNERMATERIAL_SCATTER_PLOTMATERIAL_SCHEDULEMATERIAL_SCHEDULE_SENDMATERIAL_SCHEMAMATERIAL_SCHOOLMATERIAL_SCIENCEMATERIAL_SCOREMATERIAL_SCOREBOARDMATERIAL_SCREENSHOTMATERIAL_SCREENSHOT_MONITORMATERIAL_SCREEN_LOCK_LANDSCAPEMATERIAL_SCREEN_LOCK_PORTRAITMATERIAL_SCREEN_LOCK_ROTATIONMATERIAL_SCREEN_ROTATIONMATERIAL_SCREEN_ROTATION_ALTMATERIAL_SCREEN_SEARCH_DESKTOPMATERIAL_SCREEN_SHAREMATERIAL_SCUBA_DIVINGMATERIAL_SDMATERIAL_SD_CARDMATERIAL_SD_CARD_ALERTMATERIAL_SD_STORAGEMATERIAL_SEARCHMATERIAL_SEARCH_OFFMATERIAL_SECURITYMATERIAL_SECURITY_UPDATEMATERIAL_SECURITY_UPDATE_GOODMATERIAL_SECURITY_UPDATE_WARNINGMATERIAL_SEGMENTMATERIAL_SELECT_ALLMATERIAL_SELF_IMPROVEMENTMATERIAL_SELLMATERIAL_SENDMATERIAL_SEND_AND_ARCHIVEMATERIAL_SEND_TIME_EXTENSIONMATERIAL_SEND_TO_MOBILEMATERIAL_SENSORSMATERIAL_SENSORS_OFFMATERIAL_SENSOR_DOORMATERIAL_SENSOR_OCCUPIEDMATERIAL_SENSOR_WINDOWMATERIAL_SENTIMENT_DISSATISFIEDMATERIAL_SENTIMENT_NEUTRALMATERIAL_SENTIMENT_SATISFIEDMATERIAL_SENTIMENT_SATISFIED_ALTMATERIAL_SENTIMENT_VERY_DISSATISFIEDMATERIAL_SENTIMENT_VERY_SATISFIEDMATERIAL_SETTINGSMATERIAL_SETTINGS_ACCESSIBILITYMATERIAL_SETTINGS_APPLICATIONSMATERIAL_SETTINGS_BACKUP_RESTOREMATERIAL_SETTINGS_BLUETOOTHMATERIAL_SETTINGS_BRIGHTNESSMATERIAL_SETTINGS_CELLMATERIAL_SETTINGS_DISPLAYMATERIAL_SETTINGS_ETHERNETMATERIAL_SETTINGS_INPUT_ANTENNAMATERIAL_SETTINGS_INPUT_COMPONENTMATERIAL_SETTINGS_INPUT_COMPOSITEMATERIAL_SETTINGS_INPUT_HDMIMATERIAL_SETTINGS_INPUT_SVIDEOMATERIAL_SETTINGS_OVERSCANMATERIAL_SETTINGS_PHONEMATERIAL_SETTINGS_POWERMATERIAL_SETTINGS_REMOTEMATERIAL_SETTINGS_SUGGESTMATERIAL_SETTINGS_SYSTEM_DAYDREAMMATERIAL_SETTINGS_VOICEMATERIAL_SET_MEALMATERIAL_SEVERE_COLDMATERIAL_SHAPE_LINEMATERIAL_SHAREMATERIAL_SHARE_ARRIVAL_TIMEMATERIAL_SHARE_LOCATIONMATERIAL_SHELVESMATERIAL_SHIELDMATERIAL_SHIELD_MOONMATERIAL_SHOPMATERIAL_SHOPIFYMATERIAL_SHOPPING_BAGMATERIAL_SHOPPING_BASKETMATERIAL_SHOPPING_CARTMATERIAL_SHOPPING_CART_CHECKOUTMATERIAL_SHOP_2MATERIAL_SHOP_TWOMATERIAL_SHORTCUTMATERIAL_SHORT_TEXTMATERIAL_SHOWERMATERIAL_SHOW_CHARTMATERIAL_SHUFFLEMATERIAL_SHUFFLE_ONMATERIAL_SHUTTER_SPEEDMATERIAL_SICKMATERIAL_SIGNAL_CELLULAR_0_BARMATERIAL_SIGNAL_CELLULAR_4_BARMATERIAL_SIGNAL_CELLULAR_ALTMATERIAL_SIGNAL_CELLULAR_ALT_1_BARMATERIAL_SIGNAL_CELLULAR_ALT_2_BARMATERIAL_SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_0_BARMATERIAL_SIGNAL_CELLULAR_CONNECTED_NO_INTERNET_4_BARMATERIAL_SIGNAL_CELLULAR_NODATAMATERIAL_SIGNAL_CELLULAR_NO_SIMMATERIAL_SIGNAL_CELLULAR_NULLMATERIAL_SIGNAL_CELLULAR_OFFMATERIAL_SIGNAL_WIFI_0_BARMATERIAL_SIGNAL_WIFI_4_BARMATERIAL_SIGNAL_WIFI_4_BAR_LOCKMATERIAL_SIGNAL_WIFI_BADMATERIAL_SIGNAL_WIFI_CONNECTED_NO_INTERNET_4MATERIAL_SIGNAL_WIFI_OFFMATERIAL_SIGNAL_WIFI_STATUSBAR_4_BARMATERIAL_SIGNAL_WIFI_STATUSBAR_CONNECTED_NO_INTERNET_4MATERIAL_SIGNAL_WIFI_STATUSBAR_NULLMATERIAL_SIGNPOSTMATERIAL_SIGN_LANGUAGEMATERIAL_SIM_CARDMATERIAL_SIM_CARD_ALERTMATERIAL_SIM_CARD_DOWNLOADMATERIAL_SINGLE_BEDMATERIAL_SIPMATERIAL_SKATEBOARDINGMATERIAL_SKIP_NEXTMATERIAL_SKIP_PREVIOUSMATERIAL_SLEDDINGMATERIAL_SLIDESHOWMATERIAL_SLOW_MOTION_VIDEOMATERIAL_SMARTPHONEMATERIAL_SMART_BUTTONMATERIAL_SMART_DISPLAYMATERIAL_SMART_SCREENMATERIAL_SMART_TOYMATERIAL_SMOKE_FREEMATERIAL_SMOKING_ROOMSMATERIAL_SMSMATERIAL_SMS_FAILEDMATERIAL_SNAPCHATMATERIAL_SNIPPET_FOLDERMATERIAL_SNOOZEMATERIAL_SNOWBOARDINGMATERIAL_SNOWINGMATERIAL_SNOWMOBILEMATERIAL_SNOWSHOEINGMATERIAL_SOAPMATERIAL_SOCIAL_DISTANCEMATERIAL_SOLAR_POWERMATERIAL_SORTMATERIAL_SORT_BY_ALPHAMATERIAL_SOSMATERIAL_SOUP_KITCHENMATERIAL_SOURCEMATERIAL_SOUTHMATERIAL_SOUTH_AMERICAMATERIAL_SOUTH_EASTMATERIAL_SOUTH_WESTMATERIAL_SPAMATERIAL_SPACE_BARMATERIAL_SPACE_DASHBOARDMATERIAL_SPATIAL_AUDIOMATERIAL_SPATIAL_AUDIO_OFFMATERIAL_SPATIAL_TRACKINGMATERIAL_SPEAKERMATERIAL_SPEAKER_GROUPMATERIAL_SPEAKER_NOTESMATERIAL_SPEAKER_NOTES_OFFMATERIAL_SPEAKER_PHONEMATERIAL_SPEEDMATERIAL_SPELLCHECKMATERIAL_SPLITSCREENMATERIAL_SPOKEMATERIAL_SPORTSMATERIAL_SPORTS_BARMATERIAL_SPORTS_BASEBALLMATERIAL_SPORTS_BASKETBALLMATERIAL_SPORTS_CRICKETMATERIAL_SPORTS_ESPORTSMATERIAL_SPORTS_FOOTBALLMATERIAL_SPORTS_GOLFMATERIAL_SPORTS_GYMNASTICSMATERIAL_SPORTS_HANDBALLMATERIAL_SPORTS_HOCKEYMATERIAL_SPORTS_KABADDIMATERIAL_SPORTS_MARTIAL_ARTSMATERIAL_SPORTS_MMAMATERIAL_SPORTS_MOTORSPORTSMATERIAL_SPORTS_RUGBYMATERIAL_SPORTS_SCOREMATERIAL_SPORTS_SOCCERMATERIAL_SPORTS_TENNISMATERIAL_SPORTS_VOLLEYBALLMATERIAL_SQUAREMATERIAL_SQUARE_FOOTMATERIAL_SSID_CHARTMATERIAL_STACKED_BAR_CHARTMATERIAL_STACKED_LINE_CHARTMATERIAL_STADIUMMATERIAL_STAIRSMATERIAL_STARMATERIAL_STARSMATERIAL_STARTMATERIAL_STAR_BORDERMATERIAL_STAR_BORDER_PURPLE500MATERIAL_STAR_HALFMATERIAL_STAR_OUTLINEMATERIAL_STAR_PURPLE500MATERIAL_STAR_RATEMATERIAL_STAY_CURRENT_LANDSCAPEMATERIAL_STAY_CURRENT_PORTRAITMATERIAL_STAY_PRIMARY_LANDSCAPEMATERIAL_STAY_PRIMARY_PORTRAITMATERIAL_STICKY_NOTE_2MATERIAL_STOPMATERIAL_STOP_CIRCLEMATERIAL_STOP_SCREEN_SHAREMATERIAL_STORAGEMATERIAL_STOREMATERIAL_STOREFRONTMATERIAL_STORE_MALL_DIRECTORYMATERIAL_STORMMATERIAL_STRAIGHTMATERIAL_STRAIGHTENMATERIAL_STREAMMATERIAL_STREETVIEWMATERIAL_STRIKETHROUGH_SMATERIAL_STROLLERMATERIAL_STYLEMATERIAL_SUBDIRECTORY_ARROW_LEFTMATERIAL_SUBDIRECTORY_ARROW_RIGHTMATERIAL_SUBJECTMATERIAL_SUBSCRIPTMATERIAL_SUBSCRIPTIONSMATERIAL_SUBTITLESMATERIAL_SUBTITLES_OFFMATERIAL_SUBWAYMATERIAL_SUMMARIZEMATERIAL_SUNNYMATERIAL_SUNNY_SNOWINGMATERIAL_SUPERSCRIPTMATERIAL_SUPERVISED_USER_CIRCLEMATERIAL_SUPERVISOR_ACCOUNTMATERIAL_SUPPORTMATERIAL_SUPPORT_AGENTMATERIAL_SURFINGMATERIAL_SURROUND_SOUNDMATERIAL_SWAP_CALLSMATERIAL_SWAP_HORIZMATERIAL_SWAP_HORIZONTAL_CIRCLEMATERIAL_SWAP_VERTMATERIAL_SWAP_VERTICAL_CIRCLEMATERIAL_SWAP_VERT_CIRCLEMATERIAL_SWIPEMATERIAL_SWIPE_DOWNMATERIAL_SWIPE_DOWN_ALTMATERIAL_SWIPE_LEFTMATERIAL_SWIPE_LEFT_ALTMATERIAL_SWIPE_RIGHTMATERIAL_SWIPE_RIGHT_ALTMATERIAL_SWIPE_UPMATERIAL_SWIPE_UP_ALTMATERIAL_SWIPE_VERTICALMATERIAL_SWITCH_ACCESS_SHORTCUTMATERIAL_SWITCH_ACCESS_SHORTCUT_ADDMATERIAL_SWITCH_ACCOUNTMATERIAL_SWITCH_CAMERAMATERIAL_SWITCH_LEFTMATERIAL_SWITCH_RIGHTMATERIAL_SWITCH_VIDEOMATERIAL_SYNAGOGUEMATERIAL_SYNCMATERIAL_SYNC_ALTMATERIAL_SYNC_DISABLEDMATERIAL_SYNC_LOCKMATERIAL_SYNC_PROBLEMMATERIAL_SYSTEM_SECURITY_UPDATEMATERIAL_SYSTEM_SECURITY_UPDATE_GOODMATERIAL_SYSTEM_SECURITY_UPDATE_WARNINGMATERIAL_SYSTEM_UPDATEMATERIAL_SYSTEM_UPDATE_ALTMATERIAL_SYSTEM_UPDATE_TVMATERIAL_TABMATERIAL_TABLETMATERIAL_TABLET_ANDROIDMATERIAL_TABLET_MACMATERIAL_TABLE_BARMATERIAL_TABLE_CHARTMATERIAL_TABLE_RESTAURANTMATERIAL_TABLE_ROWSMATERIAL_TABLE_VIEWMATERIAL_TAB_UNSELECTEDMATERIAL_TAGMATERIAL_TAG_FACESMATERIAL_TAKEOUT_DININGMATERIAL_TAPASMATERIAL_TAP_AND_PLAYMATERIAL_TASKMATERIAL_TASK_ALTMATERIAL_TAXI_ALERTMATERIAL_TELEGRAMMATERIAL_TEMPLE_BUDDHISTMATERIAL_TEMPLE_HINDUMATERIAL_TERMINALMATERIAL_TERRAINMATERIAL_TEXTSMSMATERIAL_TEXTUREMATERIAL_TEXT_DECREASEMATERIAL_TEXT_FIELDSMATERIAL_TEXT_FORMATMATERIAL_TEXT_INCREASEMATERIAL_TEXT_ROTATE_UPMATERIAL_TEXT_ROTATE_VERTICALMATERIAL_TEXT_ROTATION_ANGLEDOWNMATERIAL_TEXT_ROTATION_ANGLEUPMATERIAL_TEXT_ROTATION_DOWNMATERIAL_TEXT_ROTATION_NONEMATERIAL_TEXT_SNIPPETMATERIAL_THEATERSMATERIAL_THEATER_COMEDYMATERIAL_THERMOSTATMATERIAL_THERMOSTAT_AUTOMATERIAL_THUMBS_UP_DOWNMATERIAL_THUMB_DOWNMATERIAL_THUMB_DOWN_ALTMATERIAL_THUMB_DOWN_OFF_ALTMATERIAL_THUMB_UPMATERIAL_THUMB_UP_ALTMATERIAL_THUMB_UP_OFF_ALTMATERIAL_THUNDERSTORMMATERIAL_TIKTOKMATERIAL_TIMELAPSEMATERIAL_TIMELINEMATERIAL_TIMERMATERIAL_TIMER_10MATERIAL_TIMER_10_SELECTMATERIAL_TIMER_3MATERIAL_TIMER_3_SELECTMATERIAL_TIMER_OFFMATERIAL_TIME_TO_LEAVEMATERIAL_TIPS_AND_UPDATESMATERIAL_TIRE_REPAIRMATERIAL_TITLEMATERIAL_TOCMATERIAL_TODAYMATERIAL_TOGGLE_OFFMATERIAL_TOGGLE_ONMATERIAL_TOKENMATERIAL_TOLLMATERIAL_TONALITYMATERIAL_TOPICMATERIAL_TORNADOMATERIAL_TOUCH_APPMATERIAL_TOURMATERIAL_TOYSMATERIAL_TRACK_CHANGESMATERIAL_TRAFFICMATERIAL_TRAINMATERIAL_TRAMMATERIAL_TRANSCRIBEMATERIAL_TRANSFER_WITHIN_A_STATIONMATERIAL_TRANSFORMMATERIAL_TRANSGENDERMATERIAL_TRANSIT_ENTEREXITMATERIAL_TRANSLATEMATERIAL_TRAVEL_EXPLOREMATERIAL_TRENDING_DOWNMATERIAL_TRENDING_FLATMATERIAL_TRENDING_NEUTRALMATERIAL_TRENDING_UPMATERIAL_TRIP_ORIGINMATERIAL_TROLLEYMATERIAL_TROUBLESHOOTMATERIAL_TRYMATERIAL_TSUNAMIMATERIAL_TTYMATERIAL_TUNEMATERIAL_TUNGSTENMATERIAL_TURNED_INMATERIAL_TURNED_IN_NOTMATERIAL_TURN_LEFTMATERIAL_TURN_RIGHTMATERIAL_TURN_SHARP_LEFTMATERIAL_TURN_SHARP_RIGHTMATERIAL_TURN_SLIGHT_LEFTMATERIAL_TURN_SLIGHT_RIGHTMATERIAL_TVMATERIAL_TV_OFFMATERIAL_TWO_WHEELERMATERIAL_TYPE_SPECIMENMATERIAL_UMBRELLAMATERIAL_UNARCHIVEMATERIAL_UNDOMATERIAL_UNFOLD_LESSMATERIAL_UNFOLD_LESS_DOUBLEMATERIAL_UNFOLD_MOREMATERIAL_UNFOLD_MORE_DOUBLEMATERIAL_UNPUBLISHEDMATERIAL_UNSUBSCRIBEMATERIAL_UPCOMINGMATERIAL_UPDATEMATERIAL_UPDATE_DISABLEDMATERIAL_UPGRADEMATERIAL_UPLOADMATERIAL_UPLOAD_FILEMATERIAL_USBMATERIAL_USB_OFFMATERIAL_U_TURN_LEFTMATERIAL_U_TURN_RIGHTMATERIAL_VACCINESMATERIAL_VAPE_FREEMATERIAL_VAPING_ROOMSMATERIAL_VERIFIEDMATERIAL_VERIFIED_USERMATERIAL_VERTICAL_ALIGN_BOTTOMMATERIAL_VERTICAL_ALIGN_CENTERMATERIAL_VERTICAL_ALIGN_TOPMATERIAL_VERTICAL_DISTRIBUTEMATERIAL_VERTICAL_SHADESMATERIAL_VERTICAL_SHADES_CLOSEDMATERIAL_VERTICAL_SPLITMATERIAL_VIBRATIONMATERIAL_VIDEOCAMMATERIAL_VIDEOCAM_OFFMATERIAL_VIDEOGAME_ASSETMATERIAL_VIDEOGAME_ASSET_OFFMATERIAL_VIDEO_CALLMATERIAL_VIDEO_CAMERA_BACKMATERIAL_VIDEO_CAMERA_FRONTMATERIAL_VIDEO_CHATMATERIAL_VIDEO_COLLECTIONMATERIAL_VIDEO_FILEMATERIAL_VIDEO_LABELMATERIAL_VIDEO_LIBRARYMATERIAL_VIDEO_SETTINGSMATERIAL_VIDEO_STABLEMATERIAL_VIEW_AGENDAMATERIAL_VIEW_ARRAYMATERIAL_VIEW_CAROUSELMATERIAL_VIEW_COLUMNMATERIAL_VIEW_COMFORTABLEMATERIAL_VIEW_COMFYMATERIAL_VIEW_COMFY_ALTMATERIAL_VIEW_COMPACTMATERIAL_VIEW_COMPACT_ALTMATERIAL_VIEW_COZYMATERIAL_VIEW_DAYMATERIAL_VIEW_HEADLINEMATERIAL_VIEW_IN_ARMATERIAL_VIEW_KANBANMATERIAL_VIEW_LISTMATERIAL_VIEW_MODULEMATERIAL_VIEW_QUILTMATERIAL_VIEW_SIDEBARMATERIAL_VIEW_STREAMMATERIAL_VIEW_TIMELINEMATERIAL_VIEW_WEEKMATERIAL_VIGNETTEMATERIAL_VILLAMATERIAL_VISIBILITYMATERIAL_VISIBILITY_OFFMATERIAL_VOICEMAILMATERIAL_VOICE_CHATMATERIAL_VOICE_OVER_OFFMATERIAL_VOLCANOMATERIAL_VOLUME_DOWNMATERIAL_VOLUME_DOWN_ALTMATERIAL_VOLUME_MUTEMATERIAL_VOLUME_OFFMATERIAL_VOLUME_UPMATERIAL_VOLUNTEER_ACTIVISMMATERIAL_VPN_KEYMATERIAL_VPN_KEY_OFFMATERIAL_VPN_LOCKMATERIAL_VRPANOMATERIAL_WALLETMATERIAL_WALLET_GIFTCARDMATERIAL_WALLET_MEMBERSHIPMATERIAL_WALLET_TRAVELMATERIAL_WALLPAPERMATERIAL_WAREHOUSEMATERIAL_WARNINGMATERIAL_WARNING_AMBERMATERIAL_WASHMATERIAL_WATCHMATERIAL_WATCH_LATERMATERIAL_WATCH_OFFMATERIAL_WATERMATERIAL_WATERFALL_CHARTMATERIAL_WATER_DAMAGEMATERIAL_WATER_DROPMATERIAL_WAVESMATERIAL_WAVING_HANDMATERIAL_WB_AUTOMATERIAL_WB_CLOUDYMATERIAL_WB_INCANDESCENTMATERIAL_WB_IRIDESCENTMATERIAL_WB_SHADEMATERIAL_WB_SUNNYMATERIAL_WB_TWIGHLIGHTMATERIAL_WB_TWILIGHTMATERIAL_WCMATERIAL_WEBMATERIAL_WEBHOOKMATERIAL_WEB_ASSETMATERIAL_WEB_ASSET_OFFMATERIAL_WEB_STORIESMATERIAL_WECHATMATERIAL_WEEKENDMATERIAL_WESTMATERIAL_WHATSHOTMATERIAL_WHEELCHAIR_PICKUPMATERIAL_WHERE_TO_VOTEMATERIAL_WIDGETSMATERIAL_WIDTH_FULLMATERIAL_WIDTH_NORMALMATERIAL_WIDTH_WIDEMATERIAL_WIFIMATERIAL_WIFI_1_BARMATERIAL_WIFI_2_BARMATERIAL_WIFI_CALLINGMATERIAL_WIFI_CALLING_3MATERIAL_WIFI_CHANNELMATERIAL_WIFI_FINDMATERIAL_WIFI_LOCKMATERIAL_WIFI_OFFMATERIAL_WIFI_PASSWORDMATERIAL_WIFI_PROTECTED_SETUPMATERIAL_WIFI_TETHERINGMATERIAL_WIFI_TETHERING_ERRORMATERIAL_WIFI_TETHERING_ERROR_ROUNDEDMATERIAL_WIFI_TETHERING_OFFMATERIAL_WINDOWMATERIAL_WIND_POWERMATERIAL_WINE_BARMATERIAL_WOMANMATERIAL_WOMAN_2MATERIAL_WOO_COMMERCEMATERIAL_WORDPRESSMATERIAL_WORKMATERIAL_WORKSPACESMATERIAL_WORKSPACES_FILLEDMATERIAL_WORKSPACES_OUTLINEMATERIAL_WORKSPACE_PREMIUMMATERIAL_WORK_HISTORYMATERIAL_WORK_OFFMATERIAL_WORK_OUTLINEMATERIAL_WRAP_TEXTMATERIAL_WRONG_LOCATIONMATERIAL_WYSIWYGMATERIAL_YARDMATERIAL_YOUTUBE_SEARCHED_FORMATERIAL_ZOOM_INMATERIAL_ZOOM_IN_MAPMATERIAL_ZOOM_OUTMATERIAL_ZOOM_OUT_MAP")); index.put("com.codename1.ui.Form", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); @@ -5445,9 +5776,6 @@ private static void fillFieldIndex20(Map index) { index.put("com.codename1.ui.RichTextFormat", splitMembers("ASCIIDOCHTMLMARKDOWNPLAIN_TEXTRTF")); index.put("com.codename1.ui.SelectableIconHolder", splitMembers("")); index.put("com.codename1.ui.Sheet", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); - } - - private static void fillFieldIndex21(Map index) { index.put("com.codename1.ui.SideMenuBar", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCOMMAND_ACTIONABLECOMMAND_PLACEMENT_KEYCOMMAND_PLACEMENT_VALUE_RIGHTCOMMAND_PLACEMENT_VALUE_TOPCOMMAND_SIDE_COMPONENTCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.ui.Slider", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.ui.Stroke", splitMembers("CAP_BUTTCAP_ROUNDCAP_SQUAREJOIN_BEVELJOIN_MITERJOIN_ROUND")); @@ -5474,6 +5802,9 @@ private static void fillFieldIndex21(Map index) { index.put("com.codename1.ui.UIFragment.DefaultComponentFactory", splitMembers("")); index.put("com.codename1.ui.URLImage", splitMembers("FLAG_RESIZE_FAILFLAG_RESIZE_SCALEFLAG_RESIZE_SCALE_TO_FILLRESIZE_FAILRESIZE_SCALERESIZE_SCALE_TO_FILL")); index.put("com.codename1.ui.URLImage.ErrorCallback", splitMembers("")); + } + + private static void fillFieldIndex23(Map index) { index.put("com.codename1.ui.URLImage.ImageAdapter", splitMembers("")); index.put("com.codename1.ui.URLImage.RequestDecorator", splitMembers("")); index.put("com.codename1.ui.VirtualInputDevice", splitMembers("")); @@ -5512,9 +5843,6 @@ private static void fillFieldIndex21(Map index) { index.put("com.codename1.ui.css.CSSThemeCompiler.CSSSyntaxException", splitMembers("")); index.put("com.codename1.ui.editor.CodePureEditor", splitMembers("")); index.put("com.codename1.ui.editor.CodeView", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORKEY_BACKSPACEKEY_COPYKEY_CUTKEY_DELETEKEY_DOWNKEY_ENDKEY_ESCAPEKEY_HOMEKEY_LEFTKEY_PAGE_DOWNKEY_PAGE_UPKEY_PASTEKEY_REDOKEY_RIGHTKEY_SELECT_ALLKEY_TABKEY_UNDOKEY_UPLEFTMOD_ALTMOD_CTRLMOD_SHIFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); - } - - private static void fillFieldIndex22(Map index) { index.put("com.codename1.ui.editor.EditorDocument", splitMembers("")); index.put("com.codename1.ui.editor.EditorHost", splitMembers("")); index.put("com.codename1.ui.editor.EditorView", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORKEY_BACKSPACEKEY_COPYKEY_CUTKEY_DELETEKEY_DOWNKEY_ENDKEY_ESCAPEKEY_HOMEKEY_LEFTKEY_PAGE_DOWNKEY_PAGE_UPKEY_PASTEKEY_REDOKEY_RIGHTKEY_SELECT_ALLKEY_TABKEY_UNDOKEY_UPLEFTMOD_ALTMOD_CTRLMOD_SHIFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); @@ -5541,6 +5869,9 @@ private static void fillFieldIndex22(Map index) { index.put("com.codename1.ui.editor.Tokenizer", splitMembers("COMMENTKEYWORDNUMBERPROPERTYSTATE_BLOCK_COMMENTSTATE_CSS_COMMENT_DECLARATIONSTATE_CSS_DECLARATIONSTATE_NORMALSTATE_TEMPLATESTATE_TRIPLE_DOUBLESTATE_TRIPLE_SINGLESTATE_XML_COMMENTSTRING")); index.put("com.codename1.ui.editor.UndoManager", splitMembers("")); index.put("com.codename1.ui.events.ActionEvent", splitMembers("")); + } + + private static void fillFieldIndex24(Map index) { index.put("com.codename1.ui.events.ActionEvent.Type", splitMembers("CalendarChangeCommandDataDoneDragFinishedEditExceptionIsGalleryTypeSupportedJavaScriptKeyPressKeyReleaseLogLongPointerPressOpenGalleryOrientationChangeOtherPointerPointerDragPointerPressedPointerReleasedPointerWheelPostureChangeProgressResponseShowSizeChangeSwipeTheme")); index.put("com.codename1.ui.events.ActionListener", splitMembers("")); index.put("com.codename1.ui.events.ActionSource", splitMembers("")); @@ -5579,9 +5910,6 @@ private static void fillFieldIndex22(Map index) { index.put("com.codename1.ui.html.HTMLParser", splitMembers("")); index.put("com.codename1.ui.html.HTMLUtils", splitMembers("")); index.put("com.codename1.ui.html.IOCallback", splitMembers("")); - } - - private static void fillFieldIndex23(Map index) { index.put("com.codename1.ui.layouts.BorderLayout", splitMembers("CENTERCENTER_BEHAVIOR_CENTERCENTER_BEHAVIOR_CENTER_ABSOLUTECENTER_BEHAVIOR_SCALECENTER_BEHAVIOR_TOTAL_BELLOWCENTER_BEHAVIOR_TOTAL_BELOWEASTNORTHOVERLAYSOUTHWEST")); index.put("com.codename1.ui.layouts.BoxLayout", splitMembers("X_AXISX_AXIS_NO_GROWY_AXISY_AXIS_BOTTOM_LAST")); index.put("com.codename1.ui.layouts.CoordinateLayout", splitMembers("")); @@ -5608,6 +5936,9 @@ private static void fillFieldIndex23(Map index) { index.put("com.codename1.ui.layouts.mig.LayoutCallback", splitMembers("")); index.put("com.codename1.ui.layouts.mig.LayoutUtil", splitMembers("HAS_BEANSHORIZONTALINFMAXMINPREFVERTICAL")); index.put("com.codename1.ui.layouts.mig.LinkHandler", splitMembers("HEIGHTWIDTHXX2YY2")); + } + + private static void fillFieldIndex25(Map index) { index.put("com.codename1.ui.layouts.mig.MigLayout", splitMembers("")); index.put("com.codename1.ui.layouts.mig.PlatformDefaults", splitMembers("BASE_FONT_SIZEBASE_REAL_PIXELBASE_SCALE_FACTORGNOMEMAC_OSXVISUAL_PADDING_PROPERTYWINDOWS_XP")); index.put("com.codename1.ui.layouts.mig.UnitConverter", splitMembers("UNABLE")); @@ -5646,9 +5977,6 @@ private static void fillFieldIndex23(Map index) { index.put("com.codename1.ui.plaf.StyleParser.StyleInfo", splitMembers("")); index.put("com.codename1.ui.plaf.UIManager", splitMembers("")); index.put("com.codename1.ui.scene.Bounds", splitMembers("")); - } - - private static void fillFieldIndex24(Map index) { index.put("com.codename1.ui.scene.Camera", splitMembers("farClipnearClip")); index.put("com.codename1.ui.scene.Node", splitMembers("boundsInLocallayoutXlayoutYlayoutZlocalCanvasZopacitypaintingRectrotaterotationAxisscaleXscaleYscaleZtranslateXtranslateYtranslateZvisible")); index.put("com.codename1.ui.scene.NodePainter", splitMembers("")); @@ -5675,6 +6003,9 @@ private static void fillFieldIndex24(Map index) { index.put("com.codename1.ui.tree.Tree", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.ui.tree.Tree.TreeState", splitMembers("")); index.put("com.codename1.ui.tree.TreeModel", splitMembers("")); + } + + private static void fillFieldIndex26(Map index) { index.put("com.codename1.ui.util.Effects", splitMembers("")); index.put("com.codename1.ui.util.EmbeddedContainer", splitMembers("BASELINEBOTTOMBRB_CENTER_OFFSETBRB_CONSTANT_ASCENTBRB_CONSTANT_DESCENTBRB_OTHERCENTERCROSSHAIR_CURSORDEFAULT_CURSORDRAG_REGION_IMMEDIATELY_DRAG_XDRAG_REGION_IMMEDIATELY_DRAG_XYDRAG_REGION_IMMEDIATELY_DRAG_YDRAG_REGION_LIKELY_DRAG_XDRAG_REGION_LIKELY_DRAG_XYDRAG_REGION_LIKELY_DRAG_YDRAG_REGION_NOT_DRAGGABLEDRAG_REGION_POSSIBLE_DRAG_XDRAG_REGION_POSSIBLE_DRAG_XYDRAG_REGION_POSSIBLE_DRAG_YE_RESIZE_CURSORHAND_CURSORLEFTMOVE_CURSORNE_RESIZE_CURSORNW_RESIZE_CURSORN_RESIZE_CURSORRIGHTSE_RESIZE_CURSORSW_RESIZE_CURSORS_RESIZE_CURSORTEXT_CURSORTOPWAIT_CURSORW_RESIZE_CURSOR")); index.put("com.codename1.ui.util.EventDispatcher", splitMembers("")); @@ -5713,9 +6044,6 @@ private static void fillFieldIndex24(Map index) { index.put("com.codename1.util.EasyThread.ErrorListener", splitMembers("")); index.put("com.codename1.util.FailureCallback", splitMembers("")); index.put("com.codename1.util.LazyValue", splitMembers("")); - } - - private static void fillFieldIndex25(Map index) { index.put("com.codename1.util.MathUtil", splitMembers("")); index.put("com.codename1.util.OnComplete", splitMembers("")); index.put("com.codename1.util.RunnableWithResult", splitMembers("")); @@ -5742,6 +6070,9 @@ private static void fillFieldIndex25(Map index) { index.put("com.codename1.util.regex.StringReader", splitMembers("")); index.put("com.codename1.vr.HeadTracker", splitMembers("")); index.put("com.codename1.vr.Media360View", splitMembers("")); + } + + private static void fillFieldIndex27(Map index) { index.put("com.codename1.vr.OrientationFilter", splitMembers("")); index.put("com.codename1.vr.TextureSource", splitMembers("")); index.put("com.codename1.vr.VRCameraRig", splitMembers("")); @@ -5750,6 +6081,7 @@ private static void fillFieldIndex25(Map index) { index.put("com.codename1.vr.VRSettings", splitMembers("")); index.put("com.codename1.vr.VRView", splitMembers("")); index.put("com.codename1.wearable.WearableConnection", splitMembers("")); + index.put("com.codename1.wearable.WearableConnection.DroppedDeliveryHandler", splitMembers("")); index.put("com.codename1.wearable.WearableDataListener", splitMembers("")); index.put("com.codename1.wearable.WearableMessage", splitMembers("")); index.put("com.codename1.wearable.WearableMessageListener", splitMembers("")); @@ -5780,9 +6112,6 @@ private static void fillFieldIndex25(Map index) { index.put("java.io.FileNotFoundException", splitMembers("")); index.put("java.io.Flushable", splitMembers("")); index.put("java.io.IOException", splitMembers("")); - } - - private static void fillFieldIndex26(Map index) { index.put("java.io.InputStream", splitMembers("")); index.put("java.io.InputStreamReader", splitMembers("")); index.put("java.io.InterruptedIOException", splitMembers("")); @@ -5808,6 +6137,9 @@ private static void fillFieldIndex26(Map index) { index.put("java.lang.Character", splitMembers("")); index.put("java.lang.Class", splitMembers("")); index.put("java.lang.ClassCastException", splitMembers("")); + } + + private static void fillFieldIndex28(Map index) { index.put("java.lang.ClassLoader", splitMembers("")); index.put("java.lang.ClassNotFoundException", splitMembers("")); index.put("java.lang.CloneNotSupportedException", splitMembers("")); @@ -5847,9 +6179,6 @@ private static void fillFieldIndex26(Map index) { index.put("java.lang.SafeVarargs", splitMembers("")); index.put("java.lang.SecurityException", splitMembers("")); index.put("java.lang.Short", splitMembers("")); - } - - private static void fillFieldIndex27(Map index) { index.put("java.lang.StackTraceElement", splitMembers("")); index.put("java.lang.String", splitMembers("")); index.put("java.lang.StringBuffer", splitMembers("")); @@ -5875,6 +6204,9 @@ private static void fillFieldIndex27(Map index) { index.put("java.text.DateFormat", splitMembers("")); index.put("java.text.DateFormatSymbols", splitMembers("")); index.put("java.text.Format", splitMembers("")); + } + + private static void fillFieldIndex29(Map index) { index.put("java.text.ParseException", splitMembers("")); index.put("java.text.SimpleDateFormat", splitMembers("")); index.put("java.time.Clock", splitMembers("")); @@ -5914,9 +6246,6 @@ private static void fillFieldIndex27(Map index) { index.put("java.util.Dictionary", splitMembers("")); index.put("java.util.EmptyStackException", splitMembers("")); index.put("java.util.Enumeration", splitMembers("")); - } - - private static void fillFieldIndex28(Map index) { index.put("java.util.EventListener", splitMembers("")); index.put("java.util.HashMap", splitMembers("")); index.put("java.util.HashSet", splitMembers("")); @@ -5942,6 +6271,9 @@ private static void fillFieldIndex28(Map index) { index.put("java.util.Random", splitMembers("")); index.put("java.util.RandomAccess", splitMembers("")); index.put("java.util.Set", splitMembers("")); + } + + private static void fillFieldIndex30(Map index) { index.put("java.util.SortedMap", splitMembers("")); index.put("java.util.SortedSet", splitMembers("")); index.put("java.util.Stack", splitMembers("")); @@ -6020,6 +6352,9 @@ private static Class findClassInPackage(String packageName, String fullName) if ("com.codename1.annotations".equals(packageName)) { return GeneratedAccess_com_codename1_annotations.findClass(fullName); } + if ("com.codename1.annotations.buildhints".equals(packageName)) { + return GeneratedAccess_com_codename1_annotations_buildhints.findClass(fullName); + } if ("com.codename1.annotations.graphql".equals(packageName)) { return GeneratedAccess_com_codename1_annotations_graphql.findClass(fullName); } @@ -6179,6 +6514,21 @@ private static Class findClassInPackage(String packageName, String fullName) if ("com.codename1.health.workout".equals(packageName)) { return GeneratedAccess_com_codename1_health_workout.findClass(fullName); } + if ("com.codename1.home".equals(packageName)) { + return GeneratedAccess_com_codename1_home.findClass(fullName); + } + if ("com.codename1.home.commissioning".equals(packageName)) { + return GeneratedAccess_com_codename1_home_commissioning.findClass(fullName); + } + if ("com.codename1.home.spi".equals(packageName)) { + return GeneratedAccess_com_codename1_home_spi.findClass(fullName); + } + if ("com.codename1.intents".equals(packageName)) { + return GeneratedAccess_com_codename1_intents.findClass(fullName); + } + if ("com.codename1.intents.spi".equals(packageName)) { + return GeneratedAccess_com_codename1_intents_spi.findClass(fullName); + } if ("com.codename1.io".equals(packageName)) { return GeneratedAccess_com_codename1_io.findClass(fullName); } @@ -6290,6 +6640,9 @@ private static Class findClassInPackage(String packageName, String fullName) if ("com.codename1.security".equals(packageName)) { return GeneratedAccess_com_codename1_security.findClass(fullName); } + if ("com.codename1.security.hardening".equals(packageName)) { + return GeneratedAccess_com_codename1_security_hardening.findClass(fullName); + } if ("com.codename1.security.shield".equals(packageName)) { return GeneratedAccess_com_codename1_security_shield.findClass(fullName); } @@ -6486,6 +6839,9 @@ public Object construct(Class type, Object[] args) throws Exception { if ("com.codename1.annotations".equals(candidate)) { return GeneratedAccess_com_codename1_annotations.construct(type, args); } + if ("com.codename1.annotations.buildhints".equals(candidate)) { + return GeneratedAccess_com_codename1_annotations_buildhints.construct(type, args); + } if ("com.codename1.annotations.graphql".equals(candidate)) { return GeneratedAccess_com_codename1_annotations_graphql.construct(type, args); } @@ -6645,6 +7001,21 @@ public Object construct(Class type, Object[] args) throws Exception { if ("com.codename1.health.workout".equals(candidate)) { return GeneratedAccess_com_codename1_health_workout.construct(type, args); } + if ("com.codename1.home".equals(candidate)) { + return GeneratedAccess_com_codename1_home.construct(type, args); + } + if ("com.codename1.home.commissioning".equals(candidate)) { + return GeneratedAccess_com_codename1_home_commissioning.construct(type, args); + } + if ("com.codename1.home.spi".equals(candidate)) { + return GeneratedAccess_com_codename1_home_spi.construct(type, args); + } + if ("com.codename1.intents".equals(candidate)) { + return GeneratedAccess_com_codename1_intents.construct(type, args); + } + if ("com.codename1.intents.spi".equals(candidate)) { + return GeneratedAccess_com_codename1_intents_spi.construct(type, args); + } if ("com.codename1.io".equals(candidate)) { return GeneratedAccess_com_codename1_io.construct(type, args); } @@ -6756,6 +7127,9 @@ public Object construct(Class type, Object[] args) throws Exception { if ("com.codename1.security".equals(candidate)) { return GeneratedAccess_com_codename1_security.construct(type, args); } + if ("com.codename1.security.hardening".equals(candidate)) { + return GeneratedAccess_com_codename1_security_hardening.construct(type, args); + } if ("com.codename1.security.shield".equals(candidate)) { return GeneratedAccess_com_codename1_security_shield.construct(type, args); } @@ -6943,6 +7317,9 @@ public Object invokeStatic(Class type, String name, Object[] args) throws Exc if ("com.codename1.annotations".equals(candidate)) { return GeneratedAccess_com_codename1_annotations.invokeStatic(type, name, args); } + if ("com.codename1.annotations.buildhints".equals(candidate)) { + return GeneratedAccess_com_codename1_annotations_buildhints.invokeStatic(type, name, args); + } if ("com.codename1.annotations.graphql".equals(candidate)) { return GeneratedAccess_com_codename1_annotations_graphql.invokeStatic(type, name, args); } @@ -7102,6 +7479,21 @@ public Object invokeStatic(Class type, String name, Object[] args) throws Exc if ("com.codename1.health.workout".equals(candidate)) { return GeneratedAccess_com_codename1_health_workout.invokeStatic(type, name, args); } + if ("com.codename1.home".equals(candidate)) { + return GeneratedAccess_com_codename1_home.invokeStatic(type, name, args); + } + if ("com.codename1.home.commissioning".equals(candidate)) { + return GeneratedAccess_com_codename1_home_commissioning.invokeStatic(type, name, args); + } + if ("com.codename1.home.spi".equals(candidate)) { + return GeneratedAccess_com_codename1_home_spi.invokeStatic(type, name, args); + } + if ("com.codename1.intents".equals(candidate)) { + return GeneratedAccess_com_codename1_intents.invokeStatic(type, name, args); + } + if ("com.codename1.intents.spi".equals(candidate)) { + return GeneratedAccess_com_codename1_intents_spi.invokeStatic(type, name, args); + } if ("com.codename1.io".equals(candidate)) { return GeneratedAccess_com_codename1_io.invokeStatic(type, name, args); } @@ -7213,6 +7605,9 @@ public Object invokeStatic(Class type, String name, Object[] args) throws Exc if ("com.codename1.security".equals(candidate)) { return GeneratedAccess_com_codename1_security.invokeStatic(type, name, args); } + if ("com.codename1.security.hardening".equals(candidate)) { + return GeneratedAccess_com_codename1_security_hardening.invokeStatic(type, name, args); + } if ("com.codename1.security.shield".equals(candidate)) { return GeneratedAccess_com_codename1_security_shield.invokeStatic(type, name, args); } @@ -7386,151 +7781,158 @@ private static java.util.Map buildPackageHandlerIndex() { m.put("com.codename1.ai.vision", Integer.valueOf(5)); m.put("com.codename1.analytics", Integer.valueOf(6)); m.put("com.codename1.annotations", Integer.valueOf(7)); - m.put("com.codename1.annotations.graphql", Integer.valueOf(8)); - m.put("com.codename1.annotations.grpc", Integer.valueOf(9)); - m.put("com.codename1.annotations.rest", Integer.valueOf(10)); - m.put("com.codename1.appreview", Integer.valueOf(11)); - m.put("com.codename1.ar", Integer.valueOf(12)); - m.put("com.codename1.background", Integer.valueOf(13)); - m.put("com.codename1.binding", Integer.valueOf(14)); - m.put("com.codename1.bluetooth", Integer.valueOf(15)); - m.put("com.codename1.bluetooth.classic", Integer.valueOf(16)); - m.put("com.codename1.bluetooth.gatt", Integer.valueOf(17)); - m.put("com.codename1.bluetooth.le", Integer.valueOf(18)); - m.put("com.codename1.bluetooth.le.server", Integer.valueOf(19)); - m.put("com.codename1.calendar", Integer.valueOf(20)); - m.put("com.codename1.camera", Integer.valueOf(21)); - m.put("com.codename1.capture", Integer.valueOf(22)); - m.put("com.codename1.car", Integer.valueOf(23)); - m.put("com.codename1.car.spi", Integer.valueOf(24)); - m.put("com.codename1.charts", Integer.valueOf(25)); - m.put("com.codename1.charts.compat", Integer.valueOf(26)); - m.put("com.codename1.charts.models", Integer.valueOf(27)); - m.put("com.codename1.charts.renderers", Integer.valueOf(28)); - m.put("com.codename1.charts.transitions", Integer.valueOf(29)); - m.put("com.codename1.charts.util", Integer.valueOf(30)); - m.put("com.codename1.charts.views", Integer.valueOf(31)); - m.put("com.codename1.cloud", Integer.valueOf(32)); - m.put("com.codename1.codescan", Integer.valueOf(33)); - m.put("com.codename1.compat.java.util", Integer.valueOf(34)); - m.put("com.codename1.components", Integer.valueOf(35)); - m.put("com.codename1.contacts", Integer.valueOf(36)); - m.put("com.codename1.crash", Integer.valueOf(37)); - m.put("com.codename1.db", Integer.valueOf(38)); - m.put("com.codename1.facebook", Integer.valueOf(39)); - m.put("com.codename1.facebook.ui", Integer.valueOf(40)); - m.put("com.codename1.gaming", Integer.valueOf(41)); - m.put("com.codename1.gaming.level", Integer.valueOf(42)); - m.put("com.codename1.gaming.physics", Integer.valueOf(43)); - m.put("com.codename1.gaming.physics.box2d.callbacks", Integer.valueOf(44)); - m.put("com.codename1.gaming.physics.box2d.collision", Integer.valueOf(45)); - m.put("com.codename1.gaming.physics.box2d.collision.broadphase", Integer.valueOf(46)); - m.put("com.codename1.gaming.physics.box2d.collision.shapes", Integer.valueOf(47)); - m.put("com.codename1.gaming.physics.box2d.common", Integer.valueOf(48)); - m.put("com.codename1.gaming.physics.box2d.dynamics", Integer.valueOf(49)); - m.put("com.codename1.gaming.physics.box2d.dynamics.contacts", Integer.valueOf(50)); - m.put("com.codename1.gaming.physics.box2d.dynamics.joints", Integer.valueOf(51)); - m.put("com.codename1.gaming.physics.box2d.pooling", Integer.valueOf(52)); - m.put("com.codename1.gaming.physics.box2d.pooling.arrays", Integer.valueOf(53)); - m.put("com.codename1.gaming.physics.box2d.pooling.normal", Integer.valueOf(54)); - m.put("com.codename1.gaming.physics.box2d.pooling.stacks", Integer.valueOf(55)); - m.put("com.codename1.gpu", Integer.valueOf(56)); - m.put("com.codename1.health", Integer.valueOf(57)); - m.put("com.codename1.health.nutrition", Integer.valueOf(58)); - m.put("com.codename1.health.sensors", Integer.valueOf(59)); - m.put("com.codename1.health.workout", Integer.valueOf(60)); - m.put("com.codename1.io", Integer.valueOf(61)); - m.put("com.codename1.io.bonjour", Integer.valueOf(62)); - m.put("com.codename1.io.graphql", Integer.valueOf(63)); - m.put("com.codename1.io.grpc", Integer.valueOf(64)); - m.put("com.codename1.io.gzip", Integer.valueOf(65)); - m.put("com.codename1.io.oidc", Integer.valueOf(66)); - m.put("com.codename1.io.rest", Integer.valueOf(67)); - m.put("com.codename1.io.services", Integer.valueOf(68)); - m.put("com.codename1.io.tar", Integer.valueOf(69)); - m.put("com.codename1.io.usb", Integer.valueOf(70)); - m.put("com.codename1.io.webauthn", Integer.valueOf(71)); - m.put("com.codename1.io.wifi", Integer.valueOf(72)); - m.put("com.codename1.javascript", Integer.valueOf(73)); - m.put("com.codename1.l10n", Integer.valueOf(74)); - m.put("com.codename1.location", Integer.valueOf(75)); - m.put("com.codename1.mapping", Integer.valueOf(76)); - m.put("com.codename1.maps", Integer.valueOf(77)); - m.put("com.codename1.maps.layers", Integer.valueOf(78)); - m.put("com.codename1.maps.providers", Integer.valueOf(79)); - m.put("com.codename1.maps.routing", Integer.valueOf(80)); - m.put("com.codename1.maps.spi", Integer.valueOf(81)); - m.put("com.codename1.maps.vector", Integer.valueOf(82)); - m.put("com.codename1.mcp", Integer.valueOf(83)); - m.put("com.codename1.media", Integer.valueOf(84)); - m.put("com.codename1.messaging", Integer.valueOf(85)); - m.put("com.codename1.nfc", Integer.valueOf(86)); - m.put("com.codename1.notifications", Integer.valueOf(87)); - m.put("com.codename1.orm", Integer.valueOf(88)); - m.put("com.codename1.payment", Integer.valueOf(89)); - m.put("com.codename1.plugin", Integer.valueOf(90)); - m.put("com.codename1.plugin.event", Integer.valueOf(91)); - m.put("com.codename1.printing", Integer.valueOf(92)); - m.put("com.codename1.processing", Integer.valueOf(93)); - m.put("com.codename1.properties", Integer.valueOf(94)); - m.put("com.codename1.push", Integer.valueOf(95)); - m.put("com.codename1.router", Integer.valueOf(96)); - m.put("com.codename1.security", Integer.valueOf(97)); - m.put("com.codename1.security.shield", Integer.valueOf(98)); - m.put("com.codename1.security.shield.spi", Integer.valueOf(99)); - m.put("com.codename1.sensors", Integer.valueOf(100)); - m.put("com.codename1.share", Integer.valueOf(101)); - m.put("com.codename1.social", Integer.valueOf(102)); - m.put("com.codename1.surfaces", Integer.valueOf(103)); - m.put("com.codename1.surfaces.spi", Integer.valueOf(104)); - m.put("com.codename1.system", Integer.valueOf(105)); - m.put("com.codename1.testing", Integer.valueOf(106)); - m.put("com.codename1.ui", Integer.valueOf(107)); - m.put("com.codename1.ui.accessibility", Integer.valueOf(108)); - m.put("com.codename1.ui.animations", Integer.valueOf(109)); - m.put("com.codename1.ui.css", Integer.valueOf(110)); - m.put("com.codename1.ui.editor", Integer.valueOf(111)); - m.put("com.codename1.ui.events", Integer.valueOf(112)); - m.put("com.codename1.ui.geom", Integer.valueOf(113)); - m.put("com.codename1.ui.html", Integer.valueOf(114)); - m.put("com.codename1.ui.layouts", Integer.valueOf(115)); - m.put("com.codename1.ui.layouts.mig", Integer.valueOf(116)); - m.put("com.codename1.ui.list", Integer.valueOf(117)); - m.put("com.codename1.ui.painter", Integer.valueOf(118)); - m.put("com.codename1.ui.plaf", Integer.valueOf(119)); - m.put("com.codename1.ui.scene", Integer.valueOf(120)); - m.put("com.codename1.ui.spinner", Integer.valueOf(121)); - m.put("com.codename1.ui.table", Integer.valueOf(122)); - m.put("com.codename1.ui.tree", Integer.valueOf(123)); - m.put("com.codename1.ui.util", Integer.valueOf(124)); - m.put("com.codename1.ui.validation", Integer.valueOf(125)); - m.put("com.codename1.util", Integer.valueOf(126)); - m.put("com.codename1.util.promise", Integer.valueOf(127)); - m.put("com.codename1.util.regex", Integer.valueOf(128)); - m.put("com.codename1.vr", Integer.valueOf(129)); - m.put("com.codename1.wearable", Integer.valueOf(130)); - m.put("com.codename1.wearable.spi", Integer.valueOf(131)); - m.put("com.codename1.xml", Integer.valueOf(132)); - m.put("com.codenameone.playground", Integer.valueOf(133)); - m.put("java.io", Integer.valueOf(134)); - m.put("java.lang", Integer.valueOf(135)); - m.put("java.lang.ref", Integer.valueOf(136)); - m.put("java.lang.reflect", Integer.valueOf(137)); - m.put("java.net", Integer.valueOf(138)); - m.put("java.nio.charset", Integer.valueOf(139)); - m.put("java.text", Integer.valueOf(140)); - m.put("java.time", Integer.valueOf(141)); - m.put("java.time.format", Integer.valueOf(142)); - m.put("java.time.temporal", Integer.valueOf(143)); - m.put("java.util", Integer.valueOf(144)); - m.put("java.util.concurrent", Integer.valueOf(145)); - m.put("java.util.concurrent.atomic", Integer.valueOf(146)); - m.put("java.util.function", Integer.valueOf(147)); - m.put("java.util.stream", Integer.valueOf(148)); + m.put("com.codename1.annotations.buildhints", Integer.valueOf(8)); + m.put("com.codename1.annotations.graphql", Integer.valueOf(9)); + m.put("com.codename1.annotations.grpc", Integer.valueOf(10)); + m.put("com.codename1.annotations.rest", Integer.valueOf(11)); + m.put("com.codename1.appreview", Integer.valueOf(12)); + m.put("com.codename1.ar", Integer.valueOf(13)); + m.put("com.codename1.background", Integer.valueOf(14)); + m.put("com.codename1.binding", Integer.valueOf(15)); + m.put("com.codename1.bluetooth", Integer.valueOf(16)); + m.put("com.codename1.bluetooth.classic", Integer.valueOf(17)); + m.put("com.codename1.bluetooth.gatt", Integer.valueOf(18)); + m.put("com.codename1.bluetooth.le", Integer.valueOf(19)); + m.put("com.codename1.bluetooth.le.server", Integer.valueOf(20)); + m.put("com.codename1.calendar", Integer.valueOf(21)); + m.put("com.codename1.camera", Integer.valueOf(22)); + m.put("com.codename1.capture", Integer.valueOf(23)); + m.put("com.codename1.car", Integer.valueOf(24)); + m.put("com.codename1.car.spi", Integer.valueOf(25)); + m.put("com.codename1.charts", Integer.valueOf(26)); + m.put("com.codename1.charts.compat", Integer.valueOf(27)); + m.put("com.codename1.charts.models", Integer.valueOf(28)); + m.put("com.codename1.charts.renderers", Integer.valueOf(29)); + m.put("com.codename1.charts.transitions", Integer.valueOf(30)); + m.put("com.codename1.charts.util", Integer.valueOf(31)); + m.put("com.codename1.charts.views", Integer.valueOf(32)); + m.put("com.codename1.cloud", Integer.valueOf(33)); + m.put("com.codename1.codescan", Integer.valueOf(34)); + m.put("com.codename1.compat.java.util", Integer.valueOf(35)); + m.put("com.codename1.components", Integer.valueOf(36)); + m.put("com.codename1.contacts", Integer.valueOf(37)); + m.put("com.codename1.crash", Integer.valueOf(38)); + m.put("com.codename1.db", Integer.valueOf(39)); + m.put("com.codename1.facebook", Integer.valueOf(40)); + m.put("com.codename1.facebook.ui", Integer.valueOf(41)); + m.put("com.codename1.gaming", Integer.valueOf(42)); + m.put("com.codename1.gaming.level", Integer.valueOf(43)); + m.put("com.codename1.gaming.physics", Integer.valueOf(44)); + m.put("com.codename1.gaming.physics.box2d.callbacks", Integer.valueOf(45)); + m.put("com.codename1.gaming.physics.box2d.collision", Integer.valueOf(46)); + m.put("com.codename1.gaming.physics.box2d.collision.broadphase", Integer.valueOf(47)); + m.put("com.codename1.gaming.physics.box2d.collision.shapes", Integer.valueOf(48)); + m.put("com.codename1.gaming.physics.box2d.common", Integer.valueOf(49)); + m.put("com.codename1.gaming.physics.box2d.dynamics", Integer.valueOf(50)); + m.put("com.codename1.gaming.physics.box2d.dynamics.contacts", Integer.valueOf(51)); + m.put("com.codename1.gaming.physics.box2d.dynamics.joints", Integer.valueOf(52)); + m.put("com.codename1.gaming.physics.box2d.pooling", Integer.valueOf(53)); + m.put("com.codename1.gaming.physics.box2d.pooling.arrays", Integer.valueOf(54)); + m.put("com.codename1.gaming.physics.box2d.pooling.normal", Integer.valueOf(55)); + m.put("com.codename1.gaming.physics.box2d.pooling.stacks", Integer.valueOf(56)); + m.put("com.codename1.gpu", Integer.valueOf(57)); + m.put("com.codename1.health", Integer.valueOf(58)); + m.put("com.codename1.health.nutrition", Integer.valueOf(59)); + m.put("com.codename1.health.sensors", Integer.valueOf(60)); + m.put("com.codename1.health.workout", Integer.valueOf(61)); + m.put("com.codename1.home", Integer.valueOf(62)); + m.put("com.codename1.home.commissioning", Integer.valueOf(63)); + m.put("com.codename1.home.spi", Integer.valueOf(64)); + m.put("com.codename1.intents", Integer.valueOf(65)); + m.put("com.codename1.intents.spi", Integer.valueOf(66)); + m.put("com.codename1.io", Integer.valueOf(67)); + m.put("com.codename1.io.bonjour", Integer.valueOf(68)); + m.put("com.codename1.io.graphql", Integer.valueOf(69)); + m.put("com.codename1.io.grpc", Integer.valueOf(70)); + m.put("com.codename1.io.gzip", Integer.valueOf(71)); + m.put("com.codename1.io.oidc", Integer.valueOf(72)); + m.put("com.codename1.io.rest", Integer.valueOf(73)); + m.put("com.codename1.io.services", Integer.valueOf(74)); + m.put("com.codename1.io.tar", Integer.valueOf(75)); + m.put("com.codename1.io.usb", Integer.valueOf(76)); + m.put("com.codename1.io.webauthn", Integer.valueOf(77)); + m.put("com.codename1.io.wifi", Integer.valueOf(78)); + m.put("com.codename1.javascript", Integer.valueOf(79)); + m.put("com.codename1.l10n", Integer.valueOf(80)); + m.put("com.codename1.location", Integer.valueOf(81)); + m.put("com.codename1.mapping", Integer.valueOf(82)); + m.put("com.codename1.maps", Integer.valueOf(83)); + m.put("com.codename1.maps.layers", Integer.valueOf(84)); + m.put("com.codename1.maps.providers", Integer.valueOf(85)); + m.put("com.codename1.maps.routing", Integer.valueOf(86)); + m.put("com.codename1.maps.spi", Integer.valueOf(87)); + m.put("com.codename1.maps.vector", Integer.valueOf(88)); + m.put("com.codename1.mcp", Integer.valueOf(89)); + m.put("com.codename1.media", Integer.valueOf(90)); + m.put("com.codename1.messaging", Integer.valueOf(91)); + m.put("com.codename1.nfc", Integer.valueOf(92)); + m.put("com.codename1.notifications", Integer.valueOf(93)); + m.put("com.codename1.orm", Integer.valueOf(94)); + m.put("com.codename1.payment", Integer.valueOf(95)); + m.put("com.codename1.plugin", Integer.valueOf(96)); + m.put("com.codename1.plugin.event", Integer.valueOf(97)); + m.put("com.codename1.printing", Integer.valueOf(98)); + m.put("com.codename1.processing", Integer.valueOf(99)); + m.put("com.codename1.properties", Integer.valueOf(100)); + m.put("com.codename1.push", Integer.valueOf(101)); + m.put("com.codename1.router", Integer.valueOf(102)); + m.put("com.codename1.security", Integer.valueOf(103)); + m.put("com.codename1.security.hardening", Integer.valueOf(104)); + m.put("com.codename1.security.shield", Integer.valueOf(105)); + m.put("com.codename1.security.shield.spi", Integer.valueOf(106)); + m.put("com.codename1.sensors", Integer.valueOf(107)); + m.put("com.codename1.share", Integer.valueOf(108)); + m.put("com.codename1.social", Integer.valueOf(109)); + m.put("com.codename1.surfaces", Integer.valueOf(110)); + m.put("com.codename1.surfaces.spi", Integer.valueOf(111)); + m.put("com.codename1.system", Integer.valueOf(112)); + m.put("com.codename1.testing", Integer.valueOf(113)); + m.put("com.codename1.ui", Integer.valueOf(114)); + m.put("com.codename1.ui.accessibility", Integer.valueOf(115)); + m.put("com.codename1.ui.animations", Integer.valueOf(116)); + m.put("com.codename1.ui.css", Integer.valueOf(117)); + m.put("com.codename1.ui.editor", Integer.valueOf(118)); + m.put("com.codename1.ui.events", Integer.valueOf(119)); + m.put("com.codename1.ui.geom", Integer.valueOf(120)); + m.put("com.codename1.ui.html", Integer.valueOf(121)); + m.put("com.codename1.ui.layouts", Integer.valueOf(122)); + m.put("com.codename1.ui.layouts.mig", Integer.valueOf(123)); + m.put("com.codename1.ui.list", Integer.valueOf(124)); + m.put("com.codename1.ui.painter", Integer.valueOf(125)); + m.put("com.codename1.ui.plaf", Integer.valueOf(126)); + m.put("com.codename1.ui.scene", Integer.valueOf(127)); + m.put("com.codename1.ui.spinner", Integer.valueOf(128)); + m.put("com.codename1.ui.table", Integer.valueOf(129)); + m.put("com.codename1.ui.tree", Integer.valueOf(130)); + m.put("com.codename1.ui.util", Integer.valueOf(131)); + m.put("com.codename1.ui.validation", Integer.valueOf(132)); + m.put("com.codename1.util", Integer.valueOf(133)); + m.put("com.codename1.util.promise", Integer.valueOf(134)); + m.put("com.codename1.util.regex", Integer.valueOf(135)); + m.put("com.codename1.vr", Integer.valueOf(136)); + m.put("com.codename1.wearable", Integer.valueOf(137)); + m.put("com.codename1.wearable.spi", Integer.valueOf(138)); + m.put("com.codename1.xml", Integer.valueOf(139)); + m.put("com.codenameone.playground", Integer.valueOf(140)); + m.put("java.io", Integer.valueOf(141)); + m.put("java.lang", Integer.valueOf(142)); + m.put("java.lang.ref", Integer.valueOf(143)); + m.put("java.lang.reflect", Integer.valueOf(144)); + m.put("java.net", Integer.valueOf(145)); + m.put("java.nio.charset", Integer.valueOf(146)); + m.put("java.text", Integer.valueOf(147)); + m.put("java.time", Integer.valueOf(148)); + m.put("java.time.format", Integer.valueOf(149)); + m.put("java.time.temporal", Integer.valueOf(150)); + m.put("java.util", Integer.valueOf(151)); + m.put("java.util.concurrent", Integer.valueOf(152)); + m.put("java.util.concurrent.atomic", Integer.valueOf(153)); + m.put("java.util.function", Integer.valueOf(154)); + m.put("java.util.stream", Integer.valueOf(155)); return m; } - private static final int PACKAGE_HANDLER_COUNT = 149; + private static final int PACKAGE_HANDLER_COUNT = 156; @Override public Object invoke(Object target, String name, Object[] args) throws Exception { @@ -7594,147 +7996,154 @@ private static Object dispatchInstance(int __idx, Object target, String name, Ob case 5: return GeneratedAccess_com_codename1_ai_vision.invoke(target, name, args); case 6: return GeneratedAccess_com_codename1_analytics.invoke(target, name, args); case 7: return GeneratedAccess_com_codename1_annotations.invoke(target, name, args); - case 8: return GeneratedAccess_com_codename1_annotations_graphql.invoke(target, name, args); - case 9: return GeneratedAccess_com_codename1_annotations_grpc.invoke(target, name, args); - case 10: return GeneratedAccess_com_codename1_annotations_rest.invoke(target, name, args); - case 11: return GeneratedAccess_com_codename1_appreview.invoke(target, name, args); - case 12: return GeneratedAccess_com_codename1_ar.invoke(target, name, args); - case 13: return GeneratedAccess_com_codename1_background.invoke(target, name, args); - case 14: return GeneratedAccess_com_codename1_binding.invoke(target, name, args); - case 15: return GeneratedAccess_com_codename1_bluetooth.invoke(target, name, args); - case 16: return GeneratedAccess_com_codename1_bluetooth_classic.invoke(target, name, args); - case 17: return GeneratedAccess_com_codename1_bluetooth_gatt.invoke(target, name, args); - case 18: return GeneratedAccess_com_codename1_bluetooth_le.invoke(target, name, args); - case 19: return GeneratedAccess_com_codename1_bluetooth_le_server.invoke(target, name, args); - case 20: return GeneratedAccess_com_codename1_calendar.invoke(target, name, args); - case 21: return GeneratedAccess_com_codename1_camera.invoke(target, name, args); - case 22: return GeneratedAccess_com_codename1_capture.invoke(target, name, args); - case 23: return GeneratedAccess_com_codename1_car.invoke(target, name, args); - case 24: return GeneratedAccess_com_codename1_car_spi.invoke(target, name, args); - case 25: return GeneratedAccess_com_codename1_charts.invoke(target, name, args); - case 26: return GeneratedAccess_com_codename1_charts_compat.invoke(target, name, args); - case 27: return GeneratedAccess_com_codename1_charts_models.invoke(target, name, args); - case 28: return GeneratedAccess_com_codename1_charts_renderers.invoke(target, name, args); - case 29: return GeneratedAccess_com_codename1_charts_transitions.invoke(target, name, args); - case 30: return GeneratedAccess_com_codename1_charts_util.invoke(target, name, args); - case 31: return GeneratedAccess_com_codename1_charts_views.invoke(target, name, args); - case 32: return GeneratedAccess_com_codename1_cloud.invoke(target, name, args); - case 33: return GeneratedAccess_com_codename1_codescan.invoke(target, name, args); - case 34: return GeneratedAccess_com_codename1_compat_java_util.invoke(target, name, args); - case 35: return GeneratedAccess_com_codename1_components.invoke(target, name, args); - case 36: return GeneratedAccess_com_codename1_contacts.invoke(target, name, args); - case 37: return GeneratedAccess_com_codename1_crash.invoke(target, name, args); - case 38: return GeneratedAccess_com_codename1_db.invoke(target, name, args); - case 39: return GeneratedAccess_com_codename1_facebook.invoke(target, name, args); - case 40: return GeneratedAccess_com_codename1_facebook_ui.invoke(target, name, args); - case 41: return GeneratedAccess_com_codename1_gaming.invoke(target, name, args); - case 42: return GeneratedAccess_com_codename1_gaming_level.invoke(target, name, args); - case 43: return GeneratedAccess_com_codename1_gaming_physics.invoke(target, name, args); - case 44: return GeneratedAccess_com_codename1_gaming_physics_box2d_callbacks.invoke(target, name, args); - case 45: return GeneratedAccess_com_codename1_gaming_physics_box2d_collision.invoke(target, name, args); - case 46: return GeneratedAccess_com_codename1_gaming_physics_box2d_collision_broadphase.invoke(target, name, args); - case 47: return GeneratedAccess_com_codename1_gaming_physics_box2d_collision_shapes.invoke(target, name, args); - case 48: return GeneratedAccess_com_codename1_gaming_physics_box2d_common.invoke(target, name, args); - case 49: return GeneratedAccess_com_codename1_gaming_physics_box2d_dynamics.invoke(target, name, args); - case 50: return GeneratedAccess_com_codename1_gaming_physics_box2d_dynamics_contacts.invoke(target, name, args); - case 51: return GeneratedAccess_com_codename1_gaming_physics_box2d_dynamics_joints.invoke(target, name, args); - case 52: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling.invoke(target, name, args); - case 53: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling_arrays.invoke(target, name, args); - case 54: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling_normal.invoke(target, name, args); - case 55: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling_stacks.invoke(target, name, args); - case 56: return GeneratedAccess_com_codename1_gpu.invoke(target, name, args); - case 57: return GeneratedAccess_com_codename1_health.invoke(target, name, args); - case 58: return GeneratedAccess_com_codename1_health_nutrition.invoke(target, name, args); - case 59: return GeneratedAccess_com_codename1_health_sensors.invoke(target, name, args); - case 60: return GeneratedAccess_com_codename1_health_workout.invoke(target, name, args); - case 61: return GeneratedAccess_com_codename1_io.invoke(target, name, args); - case 62: return GeneratedAccess_com_codename1_io_bonjour.invoke(target, name, args); - case 63: return GeneratedAccess_com_codename1_io_graphql.invoke(target, name, args); - case 64: return GeneratedAccess_com_codename1_io_grpc.invoke(target, name, args); - case 65: return GeneratedAccess_com_codename1_io_gzip.invoke(target, name, args); - case 66: return GeneratedAccess_com_codename1_io_oidc.invoke(target, name, args); - case 67: return GeneratedAccess_com_codename1_io_rest.invoke(target, name, args); - case 68: return GeneratedAccess_com_codename1_io_services.invoke(target, name, args); - case 69: return GeneratedAccess_com_codename1_io_tar.invoke(target, name, args); - case 70: return GeneratedAccess_com_codename1_io_usb.invoke(target, name, args); - case 71: return GeneratedAccess_com_codename1_io_webauthn.invoke(target, name, args); - case 72: return GeneratedAccess_com_codename1_io_wifi.invoke(target, name, args); - case 73: return GeneratedAccess_com_codename1_javascript.invoke(target, name, args); - case 74: return GeneratedAccess_com_codename1_l10n.invoke(target, name, args); - case 75: return GeneratedAccess_com_codename1_location.invoke(target, name, args); - case 76: return GeneratedAccess_com_codename1_mapping.invoke(target, name, args); - case 77: return GeneratedAccess_com_codename1_maps.invoke(target, name, args); - case 78: return GeneratedAccess_com_codename1_maps_layers.invoke(target, name, args); - case 79: return GeneratedAccess_com_codename1_maps_providers.invoke(target, name, args); - case 80: return GeneratedAccess_com_codename1_maps_routing.invoke(target, name, args); - case 81: return GeneratedAccess_com_codename1_maps_spi.invoke(target, name, args); - case 82: return GeneratedAccess_com_codename1_maps_vector.invoke(target, name, args); - case 83: return GeneratedAccess_com_codename1_mcp.invoke(target, name, args); - case 84: return GeneratedAccess_com_codename1_media.invoke(target, name, args); - case 85: return GeneratedAccess_com_codename1_messaging.invoke(target, name, args); - case 86: return GeneratedAccess_com_codename1_nfc.invoke(target, name, args); - case 87: return GeneratedAccess_com_codename1_notifications.invoke(target, name, args); - case 88: return GeneratedAccess_com_codename1_orm.invoke(target, name, args); - case 89: return GeneratedAccess_com_codename1_payment.invoke(target, name, args); - case 90: return GeneratedAccess_com_codename1_plugin.invoke(target, name, args); - case 91: return GeneratedAccess_com_codename1_plugin_event.invoke(target, name, args); - case 92: return GeneratedAccess_com_codename1_printing.invoke(target, name, args); - case 93: return GeneratedAccess_com_codename1_processing.invoke(target, name, args); - case 94: return GeneratedAccess_com_codename1_properties.invoke(target, name, args); - case 95: return GeneratedAccess_com_codename1_push.invoke(target, name, args); - case 96: return GeneratedAccess_com_codename1_router.invoke(target, name, args); - case 97: return GeneratedAccess_com_codename1_security.invoke(target, name, args); - case 98: return GeneratedAccess_com_codename1_security_shield.invoke(target, name, args); - case 99: return GeneratedAccess_com_codename1_security_shield_spi.invoke(target, name, args); - case 100: return GeneratedAccess_com_codename1_sensors.invoke(target, name, args); - case 101: return GeneratedAccess_com_codename1_share.invoke(target, name, args); - case 102: return GeneratedAccess_com_codename1_social.invoke(target, name, args); - case 103: return GeneratedAccess_com_codename1_surfaces.invoke(target, name, args); - case 104: return GeneratedAccess_com_codename1_surfaces_spi.invoke(target, name, args); - case 105: return GeneratedAccess_com_codename1_system.invoke(target, name, args); - case 106: return GeneratedAccess_com_codename1_testing.invoke(target, name, args); - case 107: return GeneratedAccess_com_codename1_ui.invoke(target, name, args); - case 108: return GeneratedAccess_com_codename1_ui_accessibility.invoke(target, name, args); - case 109: return GeneratedAccess_com_codename1_ui_animations.invoke(target, name, args); - case 110: return GeneratedAccess_com_codename1_ui_css.invoke(target, name, args); - case 111: return GeneratedAccess_com_codename1_ui_editor.invoke(target, name, args); - case 112: return GeneratedAccess_com_codename1_ui_events.invoke(target, name, args); - case 113: return GeneratedAccess_com_codename1_ui_geom.invoke(target, name, args); - case 114: return GeneratedAccess_com_codename1_ui_html.invoke(target, name, args); - case 115: return GeneratedAccess_com_codename1_ui_layouts.invoke(target, name, args); - case 116: return GeneratedAccess_com_codename1_ui_layouts_mig.invoke(target, name, args); - case 117: return GeneratedAccess_com_codename1_ui_list.invoke(target, name, args); - case 118: return GeneratedAccess_com_codename1_ui_painter.invoke(target, name, args); - case 119: return GeneratedAccess_com_codename1_ui_plaf.invoke(target, name, args); - case 120: return GeneratedAccess_com_codename1_ui_scene.invoke(target, name, args); - case 121: return GeneratedAccess_com_codename1_ui_spinner.invoke(target, name, args); - case 122: return GeneratedAccess_com_codename1_ui_table.invoke(target, name, args); - case 123: return GeneratedAccess_com_codename1_ui_tree.invoke(target, name, args); - case 124: return GeneratedAccess_com_codename1_ui_util.invoke(target, name, args); - case 125: return GeneratedAccess_com_codename1_ui_validation.invoke(target, name, args); - case 126: return GeneratedAccess_com_codename1_util.invoke(target, name, args); - case 127: return GeneratedAccess_com_codename1_util_promise.invoke(target, name, args); - case 128: return GeneratedAccess_com_codename1_util_regex.invoke(target, name, args); - case 129: return GeneratedAccess_com_codename1_vr.invoke(target, name, args); - case 130: return GeneratedAccess_com_codename1_wearable.invoke(target, name, args); - case 131: return GeneratedAccess_com_codename1_wearable_spi.invoke(target, name, args); - case 132: return GeneratedAccess_com_codename1_xml.invoke(target, name, args); - case 133: return GeneratedAccess_com_codenameone_playground.invoke(target, name, args); - case 134: return GeneratedAccess_java_io.invoke(target, name, args); - case 135: return GeneratedAccess_java_lang.invoke(target, name, args); - case 136: return GeneratedAccess_java_lang_ref.invoke(target, name, args); - case 137: return GeneratedAccess_java_lang_reflect.invoke(target, name, args); - case 138: return GeneratedAccess_java_net.invoke(target, name, args); - case 139: return GeneratedAccess_java_nio_charset.invoke(target, name, args); - case 140: return GeneratedAccess_java_text.invoke(target, name, args); - case 141: return GeneratedAccess_java_time.invoke(target, name, args); - case 142: return GeneratedAccess_java_time_format.invoke(target, name, args); - case 143: return GeneratedAccess_java_time_temporal.invoke(target, name, args); - case 144: return GeneratedAccess_java_util.invoke(target, name, args); - case 145: return GeneratedAccess_java_util_concurrent.invoke(target, name, args); - case 146: return GeneratedAccess_java_util_concurrent_atomic.invoke(target, name, args); - case 147: return GeneratedAccess_java_util_function.invoke(target, name, args); - case 148: return GeneratedAccess_java_util_stream.invoke(target, name, args); + case 8: return GeneratedAccess_com_codename1_annotations_buildhints.invoke(target, name, args); + case 9: return GeneratedAccess_com_codename1_annotations_graphql.invoke(target, name, args); + case 10: return GeneratedAccess_com_codename1_annotations_grpc.invoke(target, name, args); + case 11: return GeneratedAccess_com_codename1_annotations_rest.invoke(target, name, args); + case 12: return GeneratedAccess_com_codename1_appreview.invoke(target, name, args); + case 13: return GeneratedAccess_com_codename1_ar.invoke(target, name, args); + case 14: return GeneratedAccess_com_codename1_background.invoke(target, name, args); + case 15: return GeneratedAccess_com_codename1_binding.invoke(target, name, args); + case 16: return GeneratedAccess_com_codename1_bluetooth.invoke(target, name, args); + case 17: return GeneratedAccess_com_codename1_bluetooth_classic.invoke(target, name, args); + case 18: return GeneratedAccess_com_codename1_bluetooth_gatt.invoke(target, name, args); + case 19: return GeneratedAccess_com_codename1_bluetooth_le.invoke(target, name, args); + case 20: return GeneratedAccess_com_codename1_bluetooth_le_server.invoke(target, name, args); + case 21: return GeneratedAccess_com_codename1_calendar.invoke(target, name, args); + case 22: return GeneratedAccess_com_codename1_camera.invoke(target, name, args); + case 23: return GeneratedAccess_com_codename1_capture.invoke(target, name, args); + case 24: return GeneratedAccess_com_codename1_car.invoke(target, name, args); + case 25: return GeneratedAccess_com_codename1_car_spi.invoke(target, name, args); + case 26: return GeneratedAccess_com_codename1_charts.invoke(target, name, args); + case 27: return GeneratedAccess_com_codename1_charts_compat.invoke(target, name, args); + case 28: return GeneratedAccess_com_codename1_charts_models.invoke(target, name, args); + case 29: return GeneratedAccess_com_codename1_charts_renderers.invoke(target, name, args); + case 30: return GeneratedAccess_com_codename1_charts_transitions.invoke(target, name, args); + case 31: return GeneratedAccess_com_codename1_charts_util.invoke(target, name, args); + case 32: return GeneratedAccess_com_codename1_charts_views.invoke(target, name, args); + case 33: return GeneratedAccess_com_codename1_cloud.invoke(target, name, args); + case 34: return GeneratedAccess_com_codename1_codescan.invoke(target, name, args); + case 35: return GeneratedAccess_com_codename1_compat_java_util.invoke(target, name, args); + case 36: return GeneratedAccess_com_codename1_components.invoke(target, name, args); + case 37: return GeneratedAccess_com_codename1_contacts.invoke(target, name, args); + case 38: return GeneratedAccess_com_codename1_crash.invoke(target, name, args); + case 39: return GeneratedAccess_com_codename1_db.invoke(target, name, args); + case 40: return GeneratedAccess_com_codename1_facebook.invoke(target, name, args); + case 41: return GeneratedAccess_com_codename1_facebook_ui.invoke(target, name, args); + case 42: return GeneratedAccess_com_codename1_gaming.invoke(target, name, args); + case 43: return GeneratedAccess_com_codename1_gaming_level.invoke(target, name, args); + case 44: return GeneratedAccess_com_codename1_gaming_physics.invoke(target, name, args); + case 45: return GeneratedAccess_com_codename1_gaming_physics_box2d_callbacks.invoke(target, name, args); + case 46: return GeneratedAccess_com_codename1_gaming_physics_box2d_collision.invoke(target, name, args); + case 47: return GeneratedAccess_com_codename1_gaming_physics_box2d_collision_broadphase.invoke(target, name, args); + case 48: return GeneratedAccess_com_codename1_gaming_physics_box2d_collision_shapes.invoke(target, name, args); + case 49: return GeneratedAccess_com_codename1_gaming_physics_box2d_common.invoke(target, name, args); + case 50: return GeneratedAccess_com_codename1_gaming_physics_box2d_dynamics.invoke(target, name, args); + case 51: return GeneratedAccess_com_codename1_gaming_physics_box2d_dynamics_contacts.invoke(target, name, args); + case 52: return GeneratedAccess_com_codename1_gaming_physics_box2d_dynamics_joints.invoke(target, name, args); + case 53: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling.invoke(target, name, args); + case 54: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling_arrays.invoke(target, name, args); + case 55: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling_normal.invoke(target, name, args); + case 56: return GeneratedAccess_com_codename1_gaming_physics_box2d_pooling_stacks.invoke(target, name, args); + case 57: return GeneratedAccess_com_codename1_gpu.invoke(target, name, args); + case 58: return GeneratedAccess_com_codename1_health.invoke(target, name, args); + case 59: return GeneratedAccess_com_codename1_health_nutrition.invoke(target, name, args); + case 60: return GeneratedAccess_com_codename1_health_sensors.invoke(target, name, args); + case 61: return GeneratedAccess_com_codename1_health_workout.invoke(target, name, args); + case 62: return GeneratedAccess_com_codename1_home.invoke(target, name, args); + case 63: return GeneratedAccess_com_codename1_home_commissioning.invoke(target, name, args); + case 64: return GeneratedAccess_com_codename1_home_spi.invoke(target, name, args); + case 65: return GeneratedAccess_com_codename1_intents.invoke(target, name, args); + case 66: return GeneratedAccess_com_codename1_intents_spi.invoke(target, name, args); + case 67: return GeneratedAccess_com_codename1_io.invoke(target, name, args); + case 68: return GeneratedAccess_com_codename1_io_bonjour.invoke(target, name, args); + case 69: return GeneratedAccess_com_codename1_io_graphql.invoke(target, name, args); + case 70: return GeneratedAccess_com_codename1_io_grpc.invoke(target, name, args); + case 71: return GeneratedAccess_com_codename1_io_gzip.invoke(target, name, args); + case 72: return GeneratedAccess_com_codename1_io_oidc.invoke(target, name, args); + case 73: return GeneratedAccess_com_codename1_io_rest.invoke(target, name, args); + case 74: return GeneratedAccess_com_codename1_io_services.invoke(target, name, args); + case 75: return GeneratedAccess_com_codename1_io_tar.invoke(target, name, args); + case 76: return GeneratedAccess_com_codename1_io_usb.invoke(target, name, args); + case 77: return GeneratedAccess_com_codename1_io_webauthn.invoke(target, name, args); + case 78: return GeneratedAccess_com_codename1_io_wifi.invoke(target, name, args); + case 79: return GeneratedAccess_com_codename1_javascript.invoke(target, name, args); + case 80: return GeneratedAccess_com_codename1_l10n.invoke(target, name, args); + case 81: return GeneratedAccess_com_codename1_location.invoke(target, name, args); + case 82: return GeneratedAccess_com_codename1_mapping.invoke(target, name, args); + case 83: return GeneratedAccess_com_codename1_maps.invoke(target, name, args); + case 84: return GeneratedAccess_com_codename1_maps_layers.invoke(target, name, args); + case 85: return GeneratedAccess_com_codename1_maps_providers.invoke(target, name, args); + case 86: return GeneratedAccess_com_codename1_maps_routing.invoke(target, name, args); + case 87: return GeneratedAccess_com_codename1_maps_spi.invoke(target, name, args); + case 88: return GeneratedAccess_com_codename1_maps_vector.invoke(target, name, args); + case 89: return GeneratedAccess_com_codename1_mcp.invoke(target, name, args); + case 90: return GeneratedAccess_com_codename1_media.invoke(target, name, args); + case 91: return GeneratedAccess_com_codename1_messaging.invoke(target, name, args); + case 92: return GeneratedAccess_com_codename1_nfc.invoke(target, name, args); + case 93: return GeneratedAccess_com_codename1_notifications.invoke(target, name, args); + case 94: return GeneratedAccess_com_codename1_orm.invoke(target, name, args); + case 95: return GeneratedAccess_com_codename1_payment.invoke(target, name, args); + case 96: return GeneratedAccess_com_codename1_plugin.invoke(target, name, args); + case 97: return GeneratedAccess_com_codename1_plugin_event.invoke(target, name, args); + case 98: return GeneratedAccess_com_codename1_printing.invoke(target, name, args); + case 99: return GeneratedAccess_com_codename1_processing.invoke(target, name, args); + case 100: return GeneratedAccess_com_codename1_properties.invoke(target, name, args); + case 101: return GeneratedAccess_com_codename1_push.invoke(target, name, args); + case 102: return GeneratedAccess_com_codename1_router.invoke(target, name, args); + case 103: return GeneratedAccess_com_codename1_security.invoke(target, name, args); + case 104: return GeneratedAccess_com_codename1_security_hardening.invoke(target, name, args); + case 105: return GeneratedAccess_com_codename1_security_shield.invoke(target, name, args); + case 106: return GeneratedAccess_com_codename1_security_shield_spi.invoke(target, name, args); + case 107: return GeneratedAccess_com_codename1_sensors.invoke(target, name, args); + case 108: return GeneratedAccess_com_codename1_share.invoke(target, name, args); + case 109: return GeneratedAccess_com_codename1_social.invoke(target, name, args); + case 110: return GeneratedAccess_com_codename1_surfaces.invoke(target, name, args); + case 111: return GeneratedAccess_com_codename1_surfaces_spi.invoke(target, name, args); + case 112: return GeneratedAccess_com_codename1_system.invoke(target, name, args); + case 113: return GeneratedAccess_com_codename1_testing.invoke(target, name, args); + case 114: return GeneratedAccess_com_codename1_ui.invoke(target, name, args); + case 115: return GeneratedAccess_com_codename1_ui_accessibility.invoke(target, name, args); + case 116: return GeneratedAccess_com_codename1_ui_animations.invoke(target, name, args); + case 117: return GeneratedAccess_com_codename1_ui_css.invoke(target, name, args); + case 118: return GeneratedAccess_com_codename1_ui_editor.invoke(target, name, args); + case 119: return GeneratedAccess_com_codename1_ui_events.invoke(target, name, args); + case 120: return GeneratedAccess_com_codename1_ui_geom.invoke(target, name, args); + case 121: return GeneratedAccess_com_codename1_ui_html.invoke(target, name, args); + case 122: return GeneratedAccess_com_codename1_ui_layouts.invoke(target, name, args); + case 123: return GeneratedAccess_com_codename1_ui_layouts_mig.invoke(target, name, args); + case 124: return GeneratedAccess_com_codename1_ui_list.invoke(target, name, args); + case 125: return GeneratedAccess_com_codename1_ui_painter.invoke(target, name, args); + case 126: return GeneratedAccess_com_codename1_ui_plaf.invoke(target, name, args); + case 127: return GeneratedAccess_com_codename1_ui_scene.invoke(target, name, args); + case 128: return GeneratedAccess_com_codename1_ui_spinner.invoke(target, name, args); + case 129: return GeneratedAccess_com_codename1_ui_table.invoke(target, name, args); + case 130: return GeneratedAccess_com_codename1_ui_tree.invoke(target, name, args); + case 131: return GeneratedAccess_com_codename1_ui_util.invoke(target, name, args); + case 132: return GeneratedAccess_com_codename1_ui_validation.invoke(target, name, args); + case 133: return GeneratedAccess_com_codename1_util.invoke(target, name, args); + case 134: return GeneratedAccess_com_codename1_util_promise.invoke(target, name, args); + case 135: return GeneratedAccess_com_codename1_util_regex.invoke(target, name, args); + case 136: return GeneratedAccess_com_codename1_vr.invoke(target, name, args); + case 137: return GeneratedAccess_com_codename1_wearable.invoke(target, name, args); + case 138: return GeneratedAccess_com_codename1_wearable_spi.invoke(target, name, args); + case 139: return GeneratedAccess_com_codename1_xml.invoke(target, name, args); + case 140: return GeneratedAccess_com_codenameone_playground.invoke(target, name, args); + case 141: return GeneratedAccess_java_io.invoke(target, name, args); + case 142: return GeneratedAccess_java_lang.invoke(target, name, args); + case 143: return GeneratedAccess_java_lang_ref.invoke(target, name, args); + case 144: return GeneratedAccess_java_lang_reflect.invoke(target, name, args); + case 145: return GeneratedAccess_java_net.invoke(target, name, args); + case 146: return GeneratedAccess_java_nio_charset.invoke(target, name, args); + case 147: return GeneratedAccess_java_text.invoke(target, name, args); + case 148: return GeneratedAccess_java_time.invoke(target, name, args); + case 149: return GeneratedAccess_java_time_format.invoke(target, name, args); + case 150: return GeneratedAccess_java_time_temporal.invoke(target, name, args); + case 151: return GeneratedAccess_java_util.invoke(target, name, args); + case 152: return GeneratedAccess_java_util_concurrent.invoke(target, name, args); + case 153: return GeneratedAccess_java_util_concurrent_atomic.invoke(target, name, args); + case 154: return GeneratedAccess_java_util_function.invoke(target, name, args); + case 155: return GeneratedAccess_java_util_stream.invoke(target, name, args); default: throw new CN1AccessException("no instance handler for index " + __idx); } } @@ -7779,6 +8188,9 @@ public Object getStaticField(Class type, String name) throws Exception { if ("com.codename1.annotations".equals(candidate)) { return GeneratedAccess_com_codename1_annotations.getStaticField(type, name); } + if ("com.codename1.annotations.buildhints".equals(candidate)) { + return GeneratedAccess_com_codename1_annotations_buildhints.getStaticField(type, name); + } if ("com.codename1.annotations.graphql".equals(candidate)) { return GeneratedAccess_com_codename1_annotations_graphql.getStaticField(type, name); } @@ -7938,6 +8350,21 @@ public Object getStaticField(Class type, String name) throws Exception { if ("com.codename1.health.workout".equals(candidate)) { return GeneratedAccess_com_codename1_health_workout.getStaticField(type, name); } + if ("com.codename1.home".equals(candidate)) { + return GeneratedAccess_com_codename1_home.getStaticField(type, name); + } + if ("com.codename1.home.commissioning".equals(candidate)) { + return GeneratedAccess_com_codename1_home_commissioning.getStaticField(type, name); + } + if ("com.codename1.home.spi".equals(candidate)) { + return GeneratedAccess_com_codename1_home_spi.getStaticField(type, name); + } + if ("com.codename1.intents".equals(candidate)) { + return GeneratedAccess_com_codename1_intents.getStaticField(type, name); + } + if ("com.codename1.intents.spi".equals(candidate)) { + return GeneratedAccess_com_codename1_intents_spi.getStaticField(type, name); + } if ("com.codename1.io".equals(candidate)) { return GeneratedAccess_com_codename1_io.getStaticField(type, name); } @@ -8049,6 +8476,9 @@ public Object getStaticField(Class type, String name) throws Exception { if ("com.codename1.security".equals(candidate)) { return GeneratedAccess_com_codename1_security.getStaticField(type, name); } + if ("com.codename1.security.hardening".equals(candidate)) { + return GeneratedAccess_com_codename1_security_hardening.getStaticField(type, name); + } if ("com.codename1.security.shield".equals(candidate)) { return GeneratedAccess_com_codename1_security_shield.getStaticField(type, name); } @@ -8251,6 +8681,11 @@ public Object getField(Object target, String name) throws Exception { } catch (CN1AccessException ex) { unsupported = ex; } + try { + return GeneratedAccess_com_codename1_annotations_buildhints.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } try { return GeneratedAccess_com_codename1_annotations_graphql.getField(target, name); } catch (CN1AccessException ex) { @@ -8516,6 +8951,31 @@ public Object getField(Object target, String name) throws Exception { } catch (CN1AccessException ex) { unsupported = ex; } + try { + return GeneratedAccess_com_codename1_home.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + return GeneratedAccess_com_codename1_home_commissioning.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + return GeneratedAccess_com_codename1_home_spi.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + return GeneratedAccess_com_codename1_intents.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + return GeneratedAccess_com_codename1_intents_spi.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } try { return GeneratedAccess_com_codename1_io.getField(target, name); } catch (CN1AccessException ex) { @@ -8701,6 +9161,11 @@ public Object getField(Object target, String name) throws Exception { } catch (CN1AccessException ex) { unsupported = ex; } + try { + return GeneratedAccess_com_codename1_security_hardening.getField(target, name); + } catch (CN1AccessException ex) { + unsupported = ex; + } try { return GeneratedAccess_com_codename1_security_shield.getField(target, name); } catch (CN1AccessException ex) { @@ -8998,6 +9463,10 @@ public void setStaticField(Class type, String name, Object value) throws Exce GeneratedAccess_com_codename1_annotations.setStaticField(type, name, value); return; } + if ("com.codename1.annotations.buildhints".equals(candidate)) { + GeneratedAccess_com_codename1_annotations_buildhints.setStaticField(type, name, value); + return; + } if ("com.codename1.annotations.graphql".equals(candidate)) { GeneratedAccess_com_codename1_annotations_graphql.setStaticField(type, name, value); return; @@ -9210,6 +9679,26 @@ public void setStaticField(Class type, String name, Object value) throws Exce GeneratedAccess_com_codename1_health_workout.setStaticField(type, name, value); return; } + if ("com.codename1.home".equals(candidate)) { + GeneratedAccess_com_codename1_home.setStaticField(type, name, value); + return; + } + if ("com.codename1.home.commissioning".equals(candidate)) { + GeneratedAccess_com_codename1_home_commissioning.setStaticField(type, name, value); + return; + } + if ("com.codename1.home.spi".equals(candidate)) { + GeneratedAccess_com_codename1_home_spi.setStaticField(type, name, value); + return; + } + if ("com.codename1.intents".equals(candidate)) { + GeneratedAccess_com_codename1_intents.setStaticField(type, name, value); + return; + } + if ("com.codename1.intents.spi".equals(candidate)) { + GeneratedAccess_com_codename1_intents_spi.setStaticField(type, name, value); + return; + } if ("com.codename1.io".equals(candidate)) { GeneratedAccess_com_codename1_io.setStaticField(type, name, value); return; @@ -9358,6 +9847,10 @@ public void setStaticField(Class type, String name, Object value) throws Exce GeneratedAccess_com_codename1_security.setStaticField(type, name, value); return; } + if ("com.codename1.security.hardening".equals(candidate)) { + GeneratedAccess_com_codename1_security_hardening.setStaticField(type, name, value); + return; + } if ("com.codename1.security.shield".equals(candidate)) { GeneratedAccess_com_codename1_security_shield.setStaticField(type, name, value); return; @@ -9619,6 +10112,12 @@ public void setField(Object target, String name, Object value) throws Exception } catch (CN1AccessException ex) { unsupported = ex; } + try { + GeneratedAccess_com_codename1_annotations_buildhints.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } try { GeneratedAccess_com_codename1_annotations_graphql.setField(target, name, value); return; @@ -9937,6 +10436,36 @@ public void setField(Object target, String name, Object value) throws Exception } catch (CN1AccessException ex) { unsupported = ex; } + try { + GeneratedAccess_com_codename1_home.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + GeneratedAccess_com_codename1_home_commissioning.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + GeneratedAccess_com_codename1_home_spi.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + GeneratedAccess_com_codename1_intents.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } + try { + GeneratedAccess_com_codename1_intents_spi.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } try { GeneratedAccess_com_codename1_io.setField(target, name, value); return; @@ -10159,6 +10688,12 @@ public void setField(Object target, String name, Object value) throws Exception } catch (CN1AccessException ex) { unsupported = ex; } + try { + GeneratedAccess_com_codename1_security_hardening.setField(target, name, value); + return; + } catch (CN1AccessException ex) { + unsupported = ex; + } try { GeneratedAccess_com_codename1_security_shield.setField(target, name, value); return; diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ai_vision.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ai_vision.java index 52998b9d85e..955ec85683d 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ai_vision.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ai_vision.java @@ -55,9 +55,18 @@ private static Class findClassChunk0(String simpleName) { if ("Barcode".equals(simpleName)) { return com.codename1.ai.vision.Barcode.class; } + if ("BarcodeFormat".equals(simpleName)) { + return com.codename1.ai.vision.BarcodeFormat.class; + } if ("BarcodeScanner".equals(simpleName)) { return com.codename1.ai.vision.BarcodeScanner.class; } + if ("CodeScanner".equals(simpleName)) { + return com.codename1.ai.vision.CodeScanner.class; + } + if ("CodeScannerOptions".equals(simpleName)) { + return com.codename1.ai.vision.CodeScannerOptions.class; + } if ("DocumentScanResult".equals(simpleName)) { return com.codename1.ai.vision.DocumentScanResult.class; } @@ -70,6 +79,9 @@ private static Class findClassChunk0(String simpleName) { if ("FaceDetector".equals(simpleName)) { return com.codename1.ai.vision.FaceDetector.class; } + if ("FaceLandmarks".equals(simpleName)) { + return com.codename1.ai.vision.FaceLandmarks.class; + } if ("ImageLabel".equals(simpleName)) { return com.codename1.ai.vision.ImageLabel.class; } @@ -85,6 +97,9 @@ private static Class findClassChunk0(String simpleName) { if ("PoseDetector".equals(simpleName)) { return com.codename1.ai.vision.PoseDetector.class; } + if ("PoseLandmarks".equals(simpleName)) { + return com.codename1.ai.vision.PoseLandmarks.class; + } if ("SegmentationMask".equals(simpleName)) { return com.codename1.ai.vision.SegmentationMask.class; } @@ -100,6 +115,9 @@ private static Class findClassChunk0(String simpleName) { if ("TextRecognizer".equals(simpleName)) { return com.codename1.ai.vision.TextRecognizer.class; } + if ("TextScript".equals(simpleName)) { + return com.codename1.ai.vision.TextScript.class; + } if ("VisionAnalyzer".equals(simpleName)) { return com.codename1.ai.vision.VisionAnalyzer.class; } @@ -109,6 +127,9 @@ private static Class findClassChunk0(String simpleName) { if ("VisionBackends".equals(simpleName)) { return com.codename1.ai.vision.VisionBackends.class; } + if ("VisionCameraView".equals(simpleName)) { + return com.codename1.ai.vision.VisionCameraView.class; + } if ("VisionException".equals(simpleName)) { return com.codename1.ai.vision.VisionException.class; } @@ -160,6 +181,12 @@ public static Object construct(Class type, Object[] args) throws Exception { return new com.codename1.ai.vision.BarcodeScanner((com.codename1.ai.vision.VisionOptions) adaptedArgs[0]); } } + if (type == com.codename1.ai.vision.CodeScannerOptions.class) { + if (matches(safeArgs, new Class[0], false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[0], false); + return new com.codename1.ai.vision.CodeScannerOptions(); + } + } if (type == com.codename1.ai.vision.DocumentScanResult.class) { if (matches(safeArgs, new Class[]{byte[][].class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{byte[][].class}, false); @@ -292,6 +319,12 @@ public static Object construct(Class type, Object[] args) throws Exception { return new com.codename1.ai.vision.TextRecognizer((com.codename1.ai.vision.VisionOptions) adaptedArgs[0]); } } + if (type == com.codename1.ai.vision.VisionCameraView.class) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionAnalyzer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.VisionAnalyzer.class}, false); + return new com.codename1.ai.vision.VisionCameraView((com.codename1.ai.vision.VisionAnalyzer) adaptedArgs[0]); + } + } if (type == com.codename1.ai.vision.VisionException.class) { if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false); @@ -341,12 +374,76 @@ public static Object construct(Class type, Object[] args) throws Exception { public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { Object[] safeArgs = safeArgs(args); - if (type == com.codename1.ai.vision.VisionBackends.class) return invokeStatic0(name, safeArgs); - if (type == com.codename1.ai.vision.VisionImage.class) return invokeStatic1(name, safeArgs); + if (type == com.codename1.ai.vision.BarcodeFormat.class) return invokeStatic0(name, safeArgs); + if (type == com.codename1.ai.vision.CodeScanner.class) return invokeStatic1(name, safeArgs); + if (type == com.codename1.ai.vision.TextScript.class) return invokeStatic2(name, safeArgs); + if (type == com.codename1.ai.vision.VisionBackends.class) return invokeStatic3(name, safeArgs); + if (type == com.codename1.ai.vision.VisionImage.class) return invokeStatic4(name, safeArgs); throw unsupportedStatic(type, name, safeArgs); } private static Object invokeStatic0(String name, Object[] safeArgs) throws Exception { + if ("matches".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.Barcode.class, java.lang.String[].class}, true)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.Barcode.class, java.lang.String[].class}, true); + java.lang.String[] varArgs = new java.lang.String[adaptedArgs.length - 1]; + for (int i = 1; i < adaptedArgs.length; i++) { + varArgs[i - 1] = (java.lang.String) adaptedArgs[i]; + } + return com.codename1.ai.vision.BarcodeFormat.matches((com.codename1.ai.vision.Barcode) adaptedArgs[0], varArgs); + } + } + throw unsupportedStatic(com.codename1.ai.vision.BarcodeFormat.class, name, safeArgs); + } + + private static Object invokeStatic1(String name, Object[] safeArgs) throws Exception { + if ("isSupported".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.CodeScanner.isSupported(); + } + } + if ("scan".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.CodeScanner.scan(); + } + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.CodeScannerOptions.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.CodeScannerOptions.class}, false); + return com.codename1.ai.vision.CodeScanner.scan((com.codename1.ai.vision.CodeScannerOptions) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.ai.vision.CodeScanner.class, name, safeArgs); + } + + private static Object invokeStatic2(String name, Object[] safeArgs) throws Exception { + if ("chinese".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.TextScript.chinese(); + } + } + if ("devanagari".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.TextScript.devanagari(); + } + } + if ("japanese".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.TextScript.japanese(); + } + } + if ("korean".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.TextScript.korean(); + } + } + if ("latin".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.ai.vision.TextScript.latin(); + } + } + throw unsupportedStatic(com.codename1.ai.vision.TextScript.class, name, safeArgs); + } + + private static Object invokeStatic3(String name, Object[] safeArgs) throws Exception { if ("appleVision".equals(name)) { if (safeArgs.length == 0) { return com.codename1.ai.vision.VisionBackends.appleVision(); @@ -390,7 +487,7 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep throw unsupportedStatic(com.codename1.ai.vision.VisionBackends.class, name, safeArgs); } - private static Object invokeStatic1(String name, Object[] safeArgs) throws Exception { + private static Object invokeStatic4(String name, Object[] safeArgs) throws Exception { if ("encoded".equals(name)) { if (matches(safeArgs, new Class[]{byte[].class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{byte[].class}, false); @@ -407,6 +504,18 @@ private static Object invokeStatic1(String name, Object[] safeArgs) throws Excep return com.codename1.ai.vision.VisionImage.fromCameraFrame((com.codename1.camera.CameraFrame) adaptedArgs[0]); } } + if ("fromFile".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.ai.vision.VisionImage.fromFile((java.lang.String) adaptedArgs[0]); + } + } + if ("fromImage".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Image.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Image.class}, false); + return com.codename1.ai.vision.VisionImage.fromImage((com.codename1.ui.Image) adaptedArgs[0]); + } + } if ("pixels".equals(name)) { if (matches(safeArgs, new Class[]{byte[].class, java.lang.Integer.class, java.lang.Integer.class, com.codename1.camera.FrameFormat.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{byte[].class, java.lang.Integer.class, java.lang.Integer.class, com.codename1.camera.FrameFormat.class, java.lang.Integer.class}, false); @@ -426,128 +535,149 @@ public static Object invoke(Object target, String name, Object[] args) throws Ex unsupported = ex; } } + if (target instanceof com.codename1.ai.vision.CodeScannerOptions) { + try { + return invoke1((com.codename1.ai.vision.CodeScannerOptions) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } if (target instanceof com.codename1.ai.vision.DocumentScanResult) { try { - return invoke1((com.codename1.ai.vision.DocumentScanResult) target, name, safeArgs); + return invoke2((com.codename1.ai.vision.DocumentScanResult) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.Face) { try { - return invoke2((com.codename1.ai.vision.Face) target, name, safeArgs); + return invoke3((com.codename1.ai.vision.Face) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.ImageLabel) { try { - return invoke3((com.codename1.ai.vision.ImageLabel) target, name, safeArgs); + return invoke4((com.codename1.ai.vision.ImageLabel) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.Pose) { try { - return invoke4((com.codename1.ai.vision.Pose) target, name, safeArgs); + return invoke5((com.codename1.ai.vision.Pose) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.Pose.Landmark) { try { - return invoke5((com.codename1.ai.vision.Pose.Landmark) target, name, safeArgs); + return invoke6((com.codename1.ai.vision.Pose.Landmark) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.SegmentationMask) { try { - return invoke6((com.codename1.ai.vision.SegmentationMask) target, name, safeArgs); + return invoke7((com.codename1.ai.vision.SegmentationMask) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.TextRecognitionResult) { try { - return invoke7((com.codename1.ai.vision.TextRecognitionResult) target, name, safeArgs); + return invoke8((com.codename1.ai.vision.TextRecognitionResult) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.TextRecognitionResult.TextBlock) { try { - return invoke8((com.codename1.ai.vision.TextRecognitionResult.TextBlock) target, name, safeArgs); + return invoke9((com.codename1.ai.vision.TextRecognitionResult.TextBlock) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.ai.vision.TextScript) { + try { + return invoke10((com.codename1.ai.vision.TextScript) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.ai.vision.VisionCameraView) { + try { + return invoke11((com.codename1.ai.vision.VisionCameraView) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionException) { try { - return invoke9((com.codename1.ai.vision.VisionException) target, name, safeArgs); + return invoke12((com.codename1.ai.vision.VisionException) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionImage) { try { - return invoke10((com.codename1.ai.vision.VisionImage) target, name, safeArgs); + return invoke13((com.codename1.ai.vision.VisionImage) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionMetadata) { try { - return invoke11((com.codename1.ai.vision.VisionMetadata) target, name, safeArgs); + return invoke14((com.codename1.ai.vision.VisionMetadata) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionOptions) { try { - return invoke12((com.codename1.ai.vision.VisionOptions) target, name, safeArgs); + return invoke15((com.codename1.ai.vision.VisionOptions) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionPipeline) { try { - return invoke13((com.codename1.ai.vision.VisionPipeline) target, name, safeArgs); + return invoke16((com.codename1.ai.vision.VisionPipeline) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionPoint) { try { - return invoke14((com.codename1.ai.vision.VisionPoint) target, name, safeArgs); + return invoke17((com.codename1.ai.vision.VisionPoint) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionRect) { try { - return invoke15((com.codename1.ai.vision.VisionRect) target, name, safeArgs); + return invoke18((com.codename1.ai.vision.VisionRect) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionAnalyzer) { try { - return invoke16((com.codename1.ai.vision.VisionAnalyzer) target, name, safeArgs); + return invoke19((com.codename1.ai.vision.VisionAnalyzer) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionBackend) { try { - return invoke17((com.codename1.ai.vision.VisionBackend) target, name, safeArgs); + return invoke20((com.codename1.ai.vision.VisionBackend) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.ai.vision.VisionPipelineListener) { try { - return invoke18((com.codename1.ai.vision.VisionPipelineListener) target, name, safeArgs); + return invoke21((com.codename1.ai.vision.VisionPipelineListener) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } @@ -592,7 +722,81 @@ private static Object invoke0(com.codename1.ai.vision.Barcode typedTarget, Strin throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke1(com.codename1.ai.vision.DocumentScanResult typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke1(com.codename1.ai.vision.CodeScannerOptions typedTarget, String name, Object[] safeArgs) throws Exception { + if ("facing".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.camera.CameraFacing.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.camera.CameraFacing.class}, false); + return typedTarget.facing((com.codename1.camera.CameraFacing) adaptedArgs[0]); + } + } + if ("formats".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String[].class}, true)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String[].class}, true); + java.lang.String[] varArgs = new java.lang.String[adaptedArgs.length - 0]; + for (int i = 0; i < adaptedArgs.length; i++) { + varArgs[i - 0] = (java.lang.String) adaptedArgs[i]; + } + return typedTarget.formats(varArgs); + } + } + if ("getFacing".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getFacing(); + } + } + if ("getFormats".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getFormats(); + } + } + if ("getHint".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getHint(); + } + } + if ("getTitle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTitle(); + } + } + if ("getVisionOptions".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getVisionOptions(); + } + } + if ("hint".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.hint((java.lang.String) adaptedArgs[0]); + } + } + if ("isTorchButton".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isTorchButton(); + } + } + if ("title".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.title((java.lang.String) adaptedArgs[0]); + } + } + if ("torchButton".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.torchButton(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("visionOptions".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionOptions.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.VisionOptions.class}, false); + return typedTarget.visionOptions((com.codename1.ai.vision.VisionOptions) adaptedArgs[0]); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke2(com.codename1.ai.vision.DocumentScanResult typedTarget, String name, Object[] safeArgs) throws Exception { if ("getMetadata".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getMetadata(); @@ -612,12 +816,18 @@ private static Object invoke1(com.codename1.ai.vision.DocumentScanResult typedTa throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke2(com.codename1.ai.vision.Face typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke3(com.codename1.ai.vision.Face typedTarget, String name, Object[] safeArgs) throws Exception { if ("getBounds".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getBounds(); } } + if ("getLandmark".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getLandmark((java.lang.String) adaptedArgs[0]); + } + } if ("getLandmarks".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getLandmarks(); @@ -656,7 +866,7 @@ private static Object invoke2(com.codename1.ai.vision.Face typedTarget, String n throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke3(com.codename1.ai.vision.ImageLabel typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke4(com.codename1.ai.vision.ImageLabel typedTarget, String name, Object[] safeArgs) throws Exception { if ("getConfidence".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getConfidence(); @@ -680,7 +890,13 @@ private static Object invoke3(com.codename1.ai.vision.ImageLabel typedTarget, St throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke4(com.codename1.ai.vision.Pose typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke5(com.codename1.ai.vision.Pose typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getLandmark".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getLandmark((java.lang.String) adaptedArgs[0]); + } + } if ("getLandmarks".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getLandmarks(); @@ -694,7 +910,7 @@ private static Object invoke4(com.codename1.ai.vision.Pose typedTarget, String n throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke5(com.codename1.ai.vision.Pose.Landmark typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke6(com.codename1.ai.vision.Pose.Landmark typedTarget, String name, Object[] safeArgs) throws Exception { if ("getConfidence".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getConfidence(); @@ -713,12 +929,24 @@ private static Object invoke5(com.codename1.ai.vision.Pose.Landmark typedTarget, throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke6(com.codename1.ai.vision.SegmentationMask typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke7(com.codename1.ai.vision.SegmentationMask typedTarget, String name, Object[] safeArgs) throws Exception { + if ("cutOut".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Image.class, java.lang.Float.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Image.class, java.lang.Float.class}, false); + return typedTarget.cutOut((com.codename1.ui.Image) adaptedArgs[0], ((Number) adaptedArgs[1]).floatValue()); + } + } if ("getConfidence".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getConfidence(); } } + if ("getConfidenceAt".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.getConfidenceAt(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } if ("getHeight".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getHeight(); @@ -734,10 +962,16 @@ private static Object invoke6(com.codename1.ai.vision.SegmentationMask typedTarg return typedTarget.getWidth(); } } + if ("toMaskImage".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.toMaskImage(toIntValue(adaptedArgs[0])); + } + } throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke7(com.codename1.ai.vision.TextRecognitionResult typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke8(com.codename1.ai.vision.TextRecognitionResult typedTarget, String name, Object[] safeArgs) throws Exception { if ("getBlocks".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getBlocks(); @@ -756,7 +990,7 @@ private static Object invoke7(com.codename1.ai.vision.TextRecognitionResult type throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke8(com.codename1.ai.vision.TextRecognitionResult.TextBlock typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke9(com.codename1.ai.vision.TextRecognitionResult.TextBlock typedTarget, String name, Object[] safeArgs) throws Exception { if ("getBounds".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getBounds(); @@ -780,186 +1014,2291 @@ private static Object invoke8(com.codename1.ai.vision.TextRecognitionResult.Text throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke9(com.codename1.ai.vision.VisionException typedTarget, String name, Object[] safeArgs) throws Exception { - if ("getCode".equals(name)) { + private static Object invoke10(com.codename1.ai.vision.TextScript typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getId".equals(name)) { if (safeArgs.length == 0) { - return typedTarget.getCode(); + return typedTarget.getId(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); } } throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke10(com.codename1.ai.vision.VisionImage typedTarget, String name, Object[] safeArgs) throws Exception { - if ("getEncodedBytes".equals(name)) { + private static Object invoke11(com.codename1.ai.vision.VisionCameraView typedTarget, String name, Object[] safeArgs) throws Exception { + if ("accessibilityChanged".equals(name)) { if (safeArgs.length == 0) { - return typedTarget.getEncodedBytes(); + typedTarget.accessibilityChanged(); return null; + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.accessibilityChanged(toIntValue(adaptedArgs[0])); return null; } } - if ("getEncodedBytesUnsafe".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getEncodedBytesUnsafe(); + if ("add".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + return typedTarget.add((com.codename1.ui.Component) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{com.codename1.ui.Image.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Image.class}, false); + return typedTarget.add((com.codename1.ui.Image) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.add((java.lang.String) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.Object.class, com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class, com.codename1.ui.Component.class}, false); + return typedTarget.add((java.lang.Object) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1]); + } + if (matches(safeArgs, new Class[]{java.lang.Object.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class, java.lang.String.class}, false); + return typedTarget.add((java.lang.Object) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + if (matches(safeArgs, new Class[]{java.lang.Object.class, com.codename1.ui.Image.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class, com.codename1.ui.Image.class}, false); + return typedTarget.add((java.lang.Object) adaptedArgs[0], (com.codename1.ui.Image) adaptedArgs[1]); } } - if ("getFormat".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getFormat(); + if ("addAll".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component[].class}, true)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component[].class}, true); + com.codename1.ui.Component[] varArgs = new com.codename1.ui.Component[adaptedArgs.length - 0]; + for (int i = 0; i < adaptedArgs.length; i++) { + varArgs[i - 0] = (com.codename1.ui.Component) adaptedArgs[i]; + } + return typedTarget.addAll(varArgs); } } - if ("getHeight".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getHeight(); + if ("addComponent".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.addComponent((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, com.codename1.ui.Component.class}, false); + typedTarget.addComponent(toIntValue(adaptedArgs[0]), (com.codename1.ui.Component) adaptedArgs[1]); return null; + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Object.class, com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Object.class, com.codename1.ui.Component.class}, false); + typedTarget.addComponent(toIntValue(adaptedArgs[0]), (java.lang.Object) adaptedArgs[1], (com.codename1.ui.Component) adaptedArgs[2]); return null; } } - if ("getPixels".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getPixels(); + if ("addContextMenuListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addContextMenuListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getPixelsUnsafe".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getPixelsUnsafe(); + if ("addDragFinishedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addDragFinishedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getRotationDegrees".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getRotationDegrees(); + if ("addDragOverListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addDragOverListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getTimestampNanos".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getTimestampNanos(); + if ("addDropListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addDropListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getWidth".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getWidth(); + if ("addFocusListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.FocusListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.FocusListener.class}, false); + typedTarget.addFocusListener((com.codename1.ui.events.FocusListener) adaptedArgs[0]); return null; } } - throw unsupportedInstance(typedTarget, name, safeArgs); - } - - private static Object invoke11(com.codename1.ai.vision.VisionMetadata typedTarget, String name, Object[] safeArgs) throws Exception { - if ("get".equals(name)) { - if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { - Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); - return typedTarget.get((java.lang.String) adaptedArgs[0]); + if ("addLongPressListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addLongPressListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getBackendId".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getBackendId(); + if ("addMouseWheelListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addMouseWheelListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getValues".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getValues(); + if ("addPointerDraggedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addPointerDraggedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - throw unsupportedInstance(typedTarget, name, safeArgs); - } - - private static Object invoke12(com.codename1.ai.vision.VisionOptions typedTarget, String name, Object[] safeArgs) throws Exception { - if ("backend".equals(name)) { - if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionBackend.class}, false)) { - Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.VisionBackend.class}, false); - return typedTarget.backend((com.codename1.ai.vision.VisionBackend) adaptedArgs[0]); + if ("addPointerPressedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addPointerPressedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getBackend".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getBackend(); + if ("addPointerReleasedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addPointerReleasedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("getMaximumResults".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getMaximumResults(); + if ("addPullToRefresh".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Runnable.class}, false); + typedTarget.addPullToRefresh((java.lang.Runnable) adaptedArgs[0]); return null; } } - if ("getMinimumConfidence".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getMinimumConfidence(); + if ("addScrollListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ScrollListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ScrollListener.class}, false); + typedTarget.addScrollListener((com.codename1.ui.events.ScrollListener) adaptedArgs[0]); return null; } } - if ("maximumResults".equals(name)) { - if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { - Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); - return typedTarget.maximumResults(toIntValue(adaptedArgs[0])); + if ("addStateChangeListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addStateChangeListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - if ("minimumConfidence".equals(name)) { - if (matches(safeArgs, new Class[]{java.lang.Float.class}, false)) { - Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Float.class}, false); - return typedTarget.minimumConfidence(((Number) adaptedArgs[0]).floatValue()); + if ("addStylusListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addStylusListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } - throw unsupportedInstance(typedTarget, name, safeArgs); - } - - private static Object invoke13(com.codename1.ai.vision.VisionPipeline typedTarget, String name, Object[] safeArgs) throws Exception { - if ("close".equals(name)) { + if ("animate".equals(name)) { if (safeArgs.length == 0) { - typedTarget.close(); return null; + return typedTarget.animate(); } } - if ("isBusy".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.isBusy(); + if ("animateHierarchy".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.animateHierarchy(toIntValue(adaptedArgs[0])); return null; } } - throw unsupportedInstance(typedTarget, name, safeArgs); - } - - private static Object invoke14(com.codename1.ai.vision.VisionPoint typedTarget, String name, Object[] safeArgs) throws Exception { - if ("getX".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getX(); + if ("animateHierarchyAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.animateHierarchyAndWait(toIntValue(adaptedArgs[0])); return null; } } - if ("getY".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getY(); + if ("animateHierarchyFade".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.animateHierarchyFade(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; } } - throw unsupportedInstance(typedTarget, name, safeArgs); - } - - private static Object invoke15(com.codename1.ai.vision.VisionRect typedTarget, String name, Object[] safeArgs) throws Exception { - if ("getHeight".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getHeight(); + if ("animateHierarchyFadeAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.animateHierarchyFadeAndWait(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; } } - if ("getWidth".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getWidth(); + if ("animateLayout".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.animateLayout(toIntValue(adaptedArgs[0])); return null; } } - if ("getX".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getX(); + if ("animateLayoutAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.animateLayoutAndWait(toIntValue(adaptedArgs[0])); return null; } } - if ("getY".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.getY(); + if ("animateLayoutFade".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.animateLayoutFade(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; } } - throw unsupportedInstance(typedTarget, name, safeArgs); - } - - private static Object invoke16(com.codename1.ai.vision.VisionAnalyzer typedTarget, String name, Object[] safeArgs) throws Exception { - if ("close".equals(name)) { - if (safeArgs.length == 0) { - typedTarget.close(); return null; + if ("animateLayoutFadeAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.animateLayoutFadeAndWait(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; } } - if ("isSupported".equals(name)) { - if (safeArgs.length == 0) { - return typedTarget.isSupported(); + if ("animateUnlayout".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Runnable.class}, false); + typedTarget.animateUnlayout(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), (java.lang.Runnable) adaptedArgs[2]); return null; } } - if ("process".equals(name)) { - if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionImage.class}, false)) { + if ("animateUnlayoutAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.animateUnlayoutAndWait(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; + } + } + if ("announceForAccessibility".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.announceForAccessibility((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("applyRTL".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.applyRTL(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("bindProperty".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, com.codename1.cloud.BindTarget.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, com.codename1.cloud.BindTarget.class}, false); + typedTarget.bindProperty((java.lang.String) adaptedArgs[0], (com.codename1.cloud.BindTarget) adaptedArgs[1]); return null; + } + } + if ("blocksSideSwipe".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.blocksSideSwipe(); + } + } + if ("clearClientProperties".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.clearClientProperties(); return null; + } + } + if ("close".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.close(); return null; + } + } + if ("contains".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + return typedTarget.contains((com.codename1.ui.Component) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.contains(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("containsOrOwns".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.containsOrOwns(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("createAnimateHierarchy".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.createAnimateHierarchy(toIntValue(adaptedArgs[0])); + } + } + if ("createAnimateHierarchyFade".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.createAnimateHierarchyFade(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("createAnimateLayout".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.createAnimateLayout(toIntValue(adaptedArgs[0])); + } + } + if ("createAnimateLayoutFade".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.createAnimateLayoutFade(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("createAnimateLayoutFadeAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.createAnimateLayoutFadeAndWait(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("createAnimateUnlayout".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Runnable.class}, false); + return typedTarget.createAnimateUnlayout(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), (java.lang.Runnable) adaptedArgs[2]); + } + } + if ("createReplaceTransition".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class}, false); + return typedTarget.createReplaceTransition((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], (com.codename1.ui.animations.Transition) adaptedArgs[2]); + } + } + if ("createStyleAnimation".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false); + return typedTarget.createStyleAnimation((java.lang.String) adaptedArgs[0], toIntValue(adaptedArgs[1])); + } + } + if ("drop".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.drop((com.codename1.ui.Component) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2])); return null; + } + } + if ("findDropTargetAt".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.findDropTargetAt(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("findFirstFocusable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.findFirstFocusable(); + } + } + if ("flushReplace".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.flushReplace(); return null; + } + } + if ("forceRevalidate".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.forceRevalidate(); return null; + } + } + if ("getAbsoluteX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAbsoluteX(); + } + } + if ("getAbsoluteY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAbsoluteY(); + } + } + if ("getAccessibilityNode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessibilityNode(); + } + } + if ("getAccessibilityText".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessibilityText(); + } + } + if ("getAllStyles".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAllStyles(); + } + } + if ("getAnimationManager".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAnimationManager(); + } + } + if ("getBaseline".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.getBaseline(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("getBaselineResizeBehavior".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBaselineResizeBehavior(); + } + } + if ("getBindablePropertyNames".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBindablePropertyNames(); + } + } + if ("getBindablePropertyTypes".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBindablePropertyTypes(); + } + } + if ("getBottomGap".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBottomGap(); + } + } + if ("getBoundPropertyValue".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getBoundPropertyValue((java.lang.String) adaptedArgs[0]); + } + } + if ("getBounds".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Rectangle.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Rectangle.class}, false); + return typedTarget.getBounds((com.codename1.ui.geom.Rectangle) adaptedArgs[0]); + } + } + if ("getChildrenAsList".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.getChildrenAsList(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("getClientProperty".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getClientProperty((java.lang.String) adaptedArgs[0]); + } + } + if ("getClosestComponentTo".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.getClosestComponentTo(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("getCloudBoundProperty".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCloudBoundProperty(); + } + } + if ("getCloudDestinationProperty".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCloudDestinationProperty(); + } + } + if ("getComponentAt".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.getComponentAt(toIntValue(adaptedArgs[0])); + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.getComponentAt(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("getComponentCount".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getComponentCount(); + } + } + if ("getComponentForm".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getComponentForm(); + } + } + if ("getComponentIndex".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + return typedTarget.getComponentIndex((com.codename1.ui.Component) adaptedArgs[0]); + } + } + if ("getComponentState".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getComponentState(); + } + } + if ("getCursor".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCursor(); + } + } + if ("getDirtyRegion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDirtyRegion(); + } + } + if ("getDisabledStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDisabledStyle(); + } + } + if ("getDragTransparency".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDragTransparency(); + } + } + if ("getDraggedx".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDraggedx(); + } + } + if ("getDraggedy".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDraggedy(); + } + } + if ("getEditingDelegate".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEditingDelegate(); + } + } + if ("getFacing".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getFacing(); + } + } + if ("getHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getHeight(); + } + } + if ("getInlineAllStyles".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInlineAllStyles(); + } + } + if ("getInlineDisabledStyles".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInlineDisabledStyles(); + } + } + if ("getInlinePressedStyles".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInlinePressedStyles(); + } + } + if ("getInlineSelectedStyles".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInlineSelectedStyles(); + } + } + if ("getInlineStylesTheme".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInlineStylesTheme(); + } + } + if ("getInlineUnselectedStyles".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInlineUnselectedStyles(); + } + } + if ("getInnerHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInnerHeight(); + } + } + if ("getInnerPreferredH".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInnerPreferredH(); + } + } + if ("getInnerPreferredW".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInnerPreferredW(); + } + } + if ("getInnerWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInnerWidth(); + } + } + if ("getInnerX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInnerX(); + } + } + if ("getInnerY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInnerY(); + } + } + if ("getLabelForComponent".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getLabelForComponent(); + } + } + if ("getLayout".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getLayout(); + } + } + if ("getLayoutHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getLayoutHeight(); + } + } + if ("getLayoutWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getLayoutWidth(); + } + } + if ("getLeadComponent".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getLeadComponent(); + } + } + if ("getLeadParent".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getLeadParent(); + } + } + if ("getListener".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getListener(); + } + } + if ("getMaxFps".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaxFps(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getNativeOverlay".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNativeOverlay(); + } + } + if ("getNextFocusDown".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNextFocusDown(); + } + } + if ("getNextFocusLeft".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNextFocusLeft(); + } + } + if ("getNextFocusRight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNextFocusRight(); + } + } + if ("getNextFocusUp".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNextFocusUp(); + } + } + if ("getOuterHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOuterHeight(); + } + } + if ("getOuterPreferredH".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOuterPreferredH(); + } + } + if ("getOuterPreferredW".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOuterPreferredW(); + } + } + if ("getOuterWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOuterWidth(); + } + } + if ("getOuterX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOuterX(); + } + } + if ("getOuterY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOuterY(); + } + } + if ("getOwner".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOwner(); + } + } + if ("getParent".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getParent(); + } + } + if ("getPreferredH".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPreferredH(); + } + } + if ("getPreferredSize".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPreferredSize(); + } + } + if ("getPreferredSizeStr".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPreferredSizeStr(); + } + } + if ("getPreferredTabIndex".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPreferredTabIndex(); + } + } + if ("getPreferredW".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPreferredW(); + } + } + if ("getPressedStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPressedStyle(); + } + } + if ("getPropertyNames".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPropertyNames(); + } + } + if ("getPropertyTypeNames".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPropertyTypeNames(); + } + } + if ("getPropertyTypes".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPropertyTypes(); + } + } + if ("getPropertyValue".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getPropertyValue((java.lang.String) adaptedArgs[0]); + } + } + if ("getResponderAt".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.getResponderAt(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + if ("getSafeAreaRoot".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSafeAreaRoot(); + } + } + if ("getSameHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSameHeight(); + } + } + if ("getSameWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSameWidth(); + } + } + if ("getScaleType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScaleType(); + } + } + if ("getScrollAnimationSpeed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollAnimationSpeed(); + } + } + if ("getScrollDimension".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollDimension(); + } + } + if ("getScrollIncrement".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollIncrement(); + } + } + if ("getScrollOpacity".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollOpacity(); + } + } + if ("getScrollOpacityChangeSpeed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollOpacityChangeSpeed(); + } + } + if ("getScrollX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollX(); + } + } + if ("getScrollY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollY(); + } + } + if ("getScrollable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScrollable(); + } + } + if ("getSelectCommandText".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSelectCommandText(); + } + } + if ("getSelectedRect".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSelectedRect(); + } + } + if ("getSelectedStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSelectedStyle(); + } + } + if ("getSemantics".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSemantics(); + } + } + if ("getSession".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSession(); + } + } + if ("getSideGap".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSideGap(); + } + } + if ("getStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStyle(); + } + } + if ("getTabIndex".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTabIndex(); + } + } + if ("getTensileLength".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTensileLength(); + } + } + if ("getTextSelectionSupport".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTextSelectionSupport(); + } + } + if ("getTooltip".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTooltip(); + } + } + if ("getUIID".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getUIID(); + } + } + if ("getUIManager".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getUIManager(); + } + } + if ("getUnselectedStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getUnselectedStyle(); + } + } + if ("getVisibleBounds".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Rectangle.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Rectangle.class}, false); + return typedTarget.getVisibleBounds((com.codename1.ui.geom.Rectangle) adaptedArgs[0]); + } + } + if ("getWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getWidth(); + } + } + if ("getX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getX(); + } + } + if ("getY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getY(); + } + } + if ("growShrink".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.growShrink(toIntValue(adaptedArgs[0])); return null; + } + } + if ("handlesInput".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.handlesInput(); + } + } + if ("hasFixedPreferredSize".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hasFixedPreferredSize(); + } + } + if ("hasFocus".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hasFocus(); + } + } + if ("invalidate".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.invalidate(); return null; + } + } + if ("isAlwaysTensile".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isAlwaysTensile(); + } + } + if ("isBlockLead".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isBlockLead(); + } + } + if ("isCellRenderer".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isCellRenderer(); + } + } + if ("isChildOf".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Container.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Container.class}, false); + return typedTarget.isChildOf((com.codename1.ui.Container) adaptedArgs[0]); + } + } + if ("isDraggable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDraggable(); + } + } + if ("isDropTarget".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDropTarget(); + } + } + if ("isEditable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEditable(); + } + } + if ("isEditing".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEditing(); + } + } + if ("isEnabled".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEnabled(); + } + } + if ("isFlatten".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isFlatten(); + } + } + if ("isFocusable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isFocusable(); + } + } + if ("isGrabsPointerEvents".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isGrabsPointerEvents(); + } + } + if ("isHScrollThumbGrabbed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHScrollThumbGrabbed(); + } + } + if ("isHScrollThumbHover".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHScrollThumbHover(); + } + } + if ("isHidden".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHidden(); + } + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.isHidden(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("isHideInLandscape".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHideInLandscape(); + } + } + if ("isHideInPortrait".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHideInPortrait(); + } + } + if ("isIgnorePointerEvents".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isIgnorePointerEvents(); + } + } + if ("isOpaque".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isOpaque(); + } + } + if ("isOwnedBy".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + return typedTarget.isOwnedBy((com.codename1.ui.Component) adaptedArgs[0]); + } + } + if ("isPinchBlocksDragAndDrop".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isPinchBlocksDragAndDrop(); + } + } + if ("isRTL".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isRTL(); + } + } + if ("isRippleEffect".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isRippleEffect(); + } + } + if ("isRunning".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isRunning(); + } + } + if ("isSafeArea".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSafeArea(); + } + } + if ("isSafeAreaRoot".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSafeAreaRoot(); + } + } + if ("isScrollVisible".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isScrollVisible(); + } + } + if ("isScrollableX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isScrollableX(); + } + } + if ("isScrollableY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isScrollableY(); + } + } + if ("isSmoothScrolling".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSmoothScrolling(); + } + } + if ("isSnapToGrid".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSnapToGrid(); + } + } + if ("isSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSupported(); + } + } + if ("isSurface".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSurface(); + } + } + if ("isTactileTouch".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isTactileTouch(); + } + } + if ("isTensileDragEnabled".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isTensileDragEnabled(); + } + } + if ("isTraversable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isTraversable(); + } + } + if ("isVScrollThumbGrabbed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isVScrollThumbGrabbed(); + } + } + if ("isVScrollThumbHover".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isVScrollThumbHover(); + } + } + if ("isVisible".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isVisible(); + } + } + if ("iterator".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.iterator(); + } + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.iterator(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("keyPressed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.keyPressed(toIntValue(adaptedArgs[0])); return null; + } + } + if ("keyReleased".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.keyReleased(toIntValue(adaptedArgs[0])); return null; + } + } + if ("keyRepeated".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.keyRepeated(toIntValue(adaptedArgs[0])); return null; + } + } + if ("layoutContainer".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.layoutContainer(); return null; + } + } + if ("longPointerPress".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.longPointerPress(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; + } + } + if ("morph".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, java.lang.Integer.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, java.lang.Integer.class, java.lang.Runnable.class}, false); + typedTarget.morph((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], toIntValue(adaptedArgs[2]), (java.lang.Runnable) adaptedArgs[3]); return null; + } + } + if ("morphAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, java.lang.Integer.class}, false); + typedTarget.morphAndWait((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], toIntValue(adaptedArgs[2])); return null; + } + } + if ("paint".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false); + typedTarget.paint((com.codename1.ui.Graphics) adaptedArgs[0]); return null; + } + } + if ("paintBackgrounds".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false); + typedTarget.paintBackgrounds((com.codename1.ui.Graphics) adaptedArgs[0]); return null; + } + } + if ("paintComponent".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false); + typedTarget.paintComponent((com.codename1.ui.Graphics) adaptedArgs[0]); return null; + } + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class, java.lang.Boolean.class}, false); + typedTarget.paintComponent((com.codename1.ui.Graphics) adaptedArgs[0], ((Boolean) adaptedArgs[1]).booleanValue()); return null; + } + } + if ("paintComponentBackground".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false); + typedTarget.paintComponentBackground((com.codename1.ui.Graphics) adaptedArgs[0]); return null; + } + } + if ("paintIntersectingComponentsAbove".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class}, false); + typedTarget.paintIntersectingComponentsAbove((com.codename1.ui.Graphics) adaptedArgs[0]); return null; + } + } + if ("paintLock".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.paintLock(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("paintLockRelease".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.paintLockRelease(); return null; + } + } + if ("paintRippleOverlay".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.paintRippleOverlay((com.codename1.ui.Graphics) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3])); return null; + } + } + if ("paintShadows".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Graphics.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Graphics.class, java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.paintShadows((com.codename1.ui.Graphics) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2])); return null; + } + } + if ("pointerDragged".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.pointerDragged(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; + } + if (matches(safeArgs, new Class[]{int[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{int[].class, int[].class}, false); + typedTarget.pointerDragged((int[]) adaptedArgs[0], (int[]) adaptedArgs[1]); return null; + } + } + if ("pointerHover".equals(name)) { + if (matches(safeArgs, new Class[]{int[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{int[].class, int[].class}, false); + typedTarget.pointerHover((int[]) adaptedArgs[0], (int[]) adaptedArgs[1]); return null; + } + } + if ("pointerHoverPressed".equals(name)) { + if (matches(safeArgs, new Class[]{int[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{int[].class, int[].class}, false); + typedTarget.pointerHoverPressed((int[]) adaptedArgs[0], (int[]) adaptedArgs[1]); return null; + } + } + if ("pointerHoverReleased".equals(name)) { + if (matches(safeArgs, new Class[]{int[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{int[].class, int[].class}, false); + typedTarget.pointerHoverReleased((int[]) adaptedArgs[0], (int[]) adaptedArgs[1]); return null; + } + } + if ("pointerPressed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.pointerPressed(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; + } + if (matches(safeArgs, new Class[]{int[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{int[].class, int[].class}, false); + typedTarget.pointerPressed((int[]) adaptedArgs[0], (int[]) adaptedArgs[1]); return null; + } + } + if ("pointerReleased".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.pointerReleased(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); return null; + } + if (matches(safeArgs, new Class[]{int[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{int[].class, int[].class}, false); + typedTarget.pointerReleased((int[]) adaptedArgs[0], (int[]) adaptedArgs[1]); return null; + } + } + if ("putClientProperty".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false); + typedTarget.putClientProperty((java.lang.String) adaptedArgs[0], (java.lang.Object) adaptedArgs[1]); return null; + } + } + if ("refreshTheme".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.refreshTheme(); return null; + } + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.refreshTheme(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("remove".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.remove(); return null; + } + } + if ("removeAll".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.removeAll(); return null; + } + } + if ("removeComponent".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.removeComponent((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("removeContextMenuListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeContextMenuListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeDragFinishedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeDragFinishedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeDragOverListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeDragOverListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeDropListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeDropListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeFocusListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.FocusListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.FocusListener.class}, false); + typedTarget.removeFocusListener((com.codename1.ui.events.FocusListener) adaptedArgs[0]); return null; + } + } + if ("removeLongPressListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeLongPressListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeMouseWheelListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeMouseWheelListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removePointerDraggedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removePointerDraggedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removePointerPressedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removePointerPressedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removePointerReleasedListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removePointerReleasedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeScrollListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ScrollListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ScrollListener.class}, false); + typedTarget.removeScrollListener((com.codename1.ui.events.ScrollListener) adaptedArgs[0]); return null; + } + } + if ("removeStateChangeListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeStateChangeListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("removeStylusListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeStylusListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } + if ("repaint".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.repaint(); return null; + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.repaint(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3])); return null; + } + } + if ("replace".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class}, false); + typedTarget.replace((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], (com.codename1.ui.animations.Transition) adaptedArgs[2]); return null; + } + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class, java.lang.Runnable.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class, java.lang.Runnable.class, java.lang.Integer.class}, false); + typedTarget.replace((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], (com.codename1.ui.animations.Transition) adaptedArgs[2], (java.lang.Runnable) adaptedArgs[3], toIntValue(adaptedArgs[4])); return null; + } + } + if ("replaceAndWait".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class}, false); + typedTarget.replaceAndWait((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], (com.codename1.ui.animations.Transition) adaptedArgs[2]); return null; + } + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class, java.lang.Integer.class}, false); + typedTarget.replaceAndWait((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], (com.codename1.ui.animations.Transition) adaptedArgs[2], toIntValue(adaptedArgs[3])); return null; + } + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class, com.codename1.ui.Component.class, com.codename1.ui.animations.Transition.class, java.lang.Boolean.class}, false); + typedTarget.replaceAndWait((com.codename1.ui.Component) adaptedArgs[0], (com.codename1.ui.Component) adaptedArgs[1], (com.codename1.ui.animations.Transition) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue()); return null; + } + } + if ("requestFocus".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.requestFocus(); return null; + } + } + if ("respondsToPointerEvents".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.respondsToPointerEvents(); + } + } + if ("revalidate".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.revalidate(); return null; + } + } + if ("revalidateLater".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.revalidateLater(); return null; + } + } + if ("revalidateWithAnimationSafety".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.revalidateWithAnimationSafety(); return null; + } + } + if ("scrollComponentToVisible".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.scrollComponentToVisible((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("scrollRectToVisible".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, com.codename1.ui.Component.class}, false); + typedTarget.scrollRectToVisible(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3]), (com.codename1.ui.Component) adaptedArgs[4]); return null; + } + } + if ("setAccessibilityText".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setAccessibilityText((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setAlwaysTensile".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setAlwaysTensile(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setBlockLead".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setBlockLead(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setBoundPropertyValue".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false); + typedTarget.setBoundPropertyValue((java.lang.String) adaptedArgs[0], (java.lang.Object) adaptedArgs[1]); return null; + } + } + if ("setCellRenderer".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setCellRenderer(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setCloudBoundProperty".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setCloudBoundProperty((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setCloudDestinationProperty".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setCloudDestinationProperty((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setComponentState".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class}, false); + typedTarget.setComponentState((java.lang.Object) adaptedArgs[0]); return null; + } + } + if ("setCursor".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setCursor(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setDirtyRegion".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Rectangle.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Rectangle.class}, false); + typedTarget.setDirtyRegion((com.codename1.ui.geom.Rectangle) adaptedArgs[0]); return null; + } + } + if ("setDisabledStyle".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false); + typedTarget.setDisabledStyle((com.codename1.ui.plaf.Style) adaptedArgs[0]); return null; + } + } + if ("setDragTransparency".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Byte.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Byte.class}, false); + typedTarget.setDragTransparency((byte) toIntValue(adaptedArgs[0])); return null; + } + } + if ("setDraggable".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setDraggable(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setDropTarget".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setDropTarget(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setEditingDelegate".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Editable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Editable.class}, false); + typedTarget.setEditingDelegate((com.codename1.ui.Editable) adaptedArgs[0]); return null; + } + } + if ("setEnabled".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setEnabled(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setFacing".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.camera.CameraFacing.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.camera.CameraFacing.class}, false); + typedTarget.setFacing((com.codename1.camera.CameraFacing) adaptedArgs[0]); return null; + } + } + if ("setFlatten".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setFlatten(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setFocus".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setFocus(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setFocusable".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setFocusable(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setGrabsPointerEvents".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setGrabsPointerEvents(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setHandlesInput".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setHandlesInput(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setHeight".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setHeight(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setHidden".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setHidden(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + if (matches(safeArgs, new Class[]{java.lang.Boolean.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class, java.lang.Boolean.class}, false); + typedTarget.setHidden(((Boolean) adaptedArgs[0]).booleanValue(), ((Boolean) adaptedArgs[1]).booleanValue()); return null; + } + } + if ("setHideInLandscape".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setHideInLandscape(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setHideInPortrait".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setHideInPortrait(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setHorizontalScrollBounds".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.setHorizontalScrollBounds(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3]), toIntValue(adaptedArgs[4]), toIntValue(adaptedArgs[5]), toIntValue(adaptedArgs[6]), toIntValue(adaptedArgs[7])); return null; + } + } + if ("setIgnorePointerEvents".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setIgnorePointerEvents(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setInlineAllStyles".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setInlineAllStyles((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setInlineDisabledStyles".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setInlineDisabledStyles((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setInlinePressedStyles".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setInlinePressedStyles((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setInlineSelectedStyles".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setInlineSelectedStyles((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setInlineStylesTheme".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.util.Resources.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.util.Resources.class}, false); + typedTarget.setInlineStylesTheme((com.codename1.ui.util.Resources) adaptedArgs[0]); return null; + } + } + if ("setInlineUnselectedStyles".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setInlineUnselectedStyles((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setIsScrollVisible".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setIsScrollVisible(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setLabelForComponent".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Label.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Label.class}, false); + typedTarget.setLabelForComponent((com.codename1.ui.Label) adaptedArgs[0]); return null; + } + } + if ("setLayout".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.layouts.Layout.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.layouts.Layout.class}, false); + typedTarget.setLayout((com.codename1.ui.layouts.Layout) adaptedArgs[0]); return null; + } + } + if ("setLeadComponent".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.setLeadComponent((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("setListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionPipelineListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.VisionPipelineListener.class}, false); + typedTarget.setListener((com.codename1.ai.vision.VisionPipelineListener) adaptedArgs[0]); return null; + } + } + if ("setMaxFps".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setMaxFps(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setName".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setName((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setNextFocusDown".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.setNextFocusDown((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("setNextFocusLeft".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.setNextFocusLeft((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("setNextFocusRight".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.setNextFocusRight((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("setNextFocusUp".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.setNextFocusUp((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("setOpaque".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setOpaque(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setOwner".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + typedTarget.setOwner((com.codename1.ui.Component) adaptedArgs[0]); return null; + } + } + if ("setPinchBlocksDragAndDrop".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setPinchBlocksDragAndDrop(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setPreferredH".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setPreferredH(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setPreferredSize".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false); + typedTarget.setPreferredSize((com.codename1.ui.geom.Dimension) adaptedArgs[0]); return null; + } + } + if ("setPreferredSizeStr".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setPreferredSizeStr((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setPreferredTabIndex".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setPreferredTabIndex(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setPreferredW".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setPreferredW(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setPressedStyle".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false); + typedTarget.setPressedStyle((com.codename1.ui.plaf.Style) adaptedArgs[0]); return null; + } + } + if ("setPropertyValue".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false); + return typedTarget.setPropertyValue((java.lang.String) adaptedArgs[0], (java.lang.Object) adaptedArgs[1]); + } + } + if ("setPullToRefresh".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Runnable.class}, false); + typedTarget.setPullToRefresh((java.lang.Runnable) adaptedArgs[0]); return null; + } + } + if ("setRTL".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setRTL(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setRippleEffect".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setRippleEffect(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setSafeArea".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setSafeArea(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setSafeAreaRoot".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setSafeAreaRoot(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setScaleType".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.camera.ScaleType.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.camera.ScaleType.class}, false); + typedTarget.setScaleType((com.codename1.camera.ScaleType) adaptedArgs[0]); return null; + } + } + if ("setScrollAnimationSpeed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setScrollAnimationSpeed(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setScrollIncrement".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setScrollIncrement(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setScrollOpacityChangeSpeed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setScrollOpacityChangeSpeed(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setScrollSize".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false); + typedTarget.setScrollSize((com.codename1.ui.geom.Dimension) adaptedArgs[0]); return null; + } + } + if ("setScrollVisible".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setScrollVisible(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setScrollable".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setScrollable(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setScrollableX".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setScrollableX(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setScrollableY".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setScrollableY(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setSelectCommandText".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setSelectCommandText((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setSelectedStyle".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false); + typedTarget.setSelectedStyle((com.codename1.ui.plaf.Style) adaptedArgs[0]); return null; + } + } + if ("setShouldCalcPreferredSize".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setShouldCalcPreferredSize(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setSize".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false); + typedTarget.setSize((com.codename1.ui.geom.Dimension) adaptedArgs[0]); return null; + } + } + if ("setSmoothScrolling".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setSmoothScrolling(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setSnapToGrid".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setSnapToGrid(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setTabIndex".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setTabIndex(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setTactileTouch".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setTactileTouch(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setTensileDragEnabled".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setTensileDragEnabled(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setTensileLength".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setTensileLength(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setTooltip".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setTooltip((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("setTorchEnabled".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setTorchEnabled(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setTraversable".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setTraversable(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setUIID".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.setUIID((java.lang.String) adaptedArgs[0]); return null; + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + typedTarget.setUIID((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); return null; + } + } + if ("setUIManager".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.plaf.UIManager.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.plaf.UIManager.class}, false); + typedTarget.setUIManager((com.codename1.ui.plaf.UIManager) adaptedArgs[0]); return null; + } + } + if ("setUnselectedStyle".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.plaf.Style.class}, false); + typedTarget.setUnselectedStyle((com.codename1.ui.plaf.Style) adaptedArgs[0]); return null; + } + } + if ("setVerticalScrollBounds".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false); + typedTarget.setVerticalScrollBounds(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3]), toIntValue(adaptedArgs[4]), toIntValue(adaptedArgs[5]), toIntValue(adaptedArgs[6]), toIntValue(adaptedArgs[7])); return null; + } + } + if ("setVisible".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setVisible(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } + if ("setWidth".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setWidth(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setX".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setX(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setY".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setY(toIntValue(adaptedArgs[0])); return null; + } + } + if ("start".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.start(); return null; + } + } + if ("startEditingAsync".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.startEditingAsync(); return null; + } + } + if ("stop".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.stop(); return null; + } + } + if ("stopEditing".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Runnable.class}, false); + typedTarget.stopEditing((java.lang.Runnable) adaptedArgs[0]); return null; + } + } + if ("stripMarginAndPadding".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.stripMarginAndPadding(); + } + } + if ("styleChanged".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, com.codename1.ui.plaf.Style.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, com.codename1.ui.plaf.Style.class}, false); + typedTarget.styleChanged((java.lang.String) adaptedArgs[0], (com.codename1.ui.plaf.Style) adaptedArgs[1]); return null; + } + } + if ("toImage".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toImage(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + if ("unbindProperty".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, com.codename1.cloud.BindTarget.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, com.codename1.cloud.BindTarget.class}, false); + typedTarget.unbindProperty((java.lang.String) adaptedArgs[0], (com.codename1.cloud.BindTarget) adaptedArgs[1]); return null; + } + } + if ("updateTabIndices".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.updateTabIndices(toIntValue(adaptedArgs[0])); + } + } + if ("visibleBoundsContains".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.visibleBoundsContains(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke12(com.codename1.ai.vision.VisionException typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getCode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCode(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke13(com.codename1.ai.vision.VisionImage typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getEncodedBytes".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEncodedBytes(); + } + } + if ("getEncodedBytesUnsafe".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEncodedBytesUnsafe(); + } + } + if ("getFormat".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getFormat(); + } + } + if ("getHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getHeight(); + } + } + if ("getPixels".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPixels(); + } + } + if ("getPixelsUnsafe".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPixelsUnsafe(); + } + } + if ("getRotationDegrees".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRotationDegrees(); + } + } + if ("getTimestampNanos".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTimestampNanos(); + } + } + if ("getWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getWidth(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke14(com.codename1.ai.vision.VisionMetadata typedTarget, String name, Object[] safeArgs) throws Exception { + if ("get".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.get((java.lang.String) adaptedArgs[0]); + } + } + if ("getBackendId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBackendId(); + } + } + if ("getValues".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValues(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke15(com.codename1.ai.vision.VisionOptions typedTarget, String name, Object[] safeArgs) throws Exception { + if ("backend".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionBackend.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.VisionBackend.class}, false); + return typedTarget.backend((com.codename1.ai.vision.VisionBackend) adaptedArgs[0]); + } + } + if ("getBackend".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBackend(); + } + } + if ("getMaximumResults".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaximumResults(); + } + } + if ("getMinimumConfidence".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMinimumConfidence(); + } + } + if ("getTextScript".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTextScript(); + } + } + if ("maximumResults".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.maximumResults(toIntValue(adaptedArgs[0])); + } + } + if ("minimumConfidence".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Float.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Float.class}, false); + return typedTarget.minimumConfidence(((Number) adaptedArgs[0]).floatValue()); + } + } + if ("textScript".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.TextScript.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.TextScript.class}, false); + return typedTarget.textScript((com.codename1.ai.vision.TextScript) adaptedArgs[0]); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke16(com.codename1.ai.vision.VisionPipeline typedTarget, String name, Object[] safeArgs) throws Exception { + if ("close".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.close(); return null; + } + } + if ("isBusy".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isBusy(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke17(com.codename1.ai.vision.VisionPoint typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getX(); + } + } + if ("getY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getY(); + } + } + if ("toPoint".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + return typedTarget.toPoint((com.codename1.ui.Component) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.toPoint(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3])); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke18(com.codename1.ai.vision.VisionRect typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getHeight".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getHeight(); + } + } + if ("getWidth".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getWidth(); + } + } + if ("getX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getX(); + } + } + if ("getY".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getY(); + } + } + if ("isEmpty".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEmpty(); + } + } + if ("toBounds".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.Component.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.Component.class}, false); + return typedTarget.toBounds((com.codename1.ui.Component) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Integer.class}, false); + return typedTarget.toBounds(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2]), toIntValue(adaptedArgs[3])); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke19(com.codename1.ai.vision.VisionAnalyzer typedTarget, String name, Object[] safeArgs) throws Exception { + if ("close".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.close(); return null; + } + } + if ("isSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSupported(); + } + } + if ("process".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ai.vision.VisionImage.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ai.vision.VisionImage.class}, false); return typedTarget.process((com.codename1.ai.vision.VisionImage) adaptedArgs[0]); } @@ -967,7 +3306,7 @@ private static Object invoke16(com.codename1.ai.vision.VisionAnalyzer typedTarge throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke17(com.codename1.ai.vision.VisionBackend typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke20(com.codename1.ai.vision.VisionBackend typedTarget, String name, Object[] safeArgs) throws Exception { if ("getId".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getId(); @@ -976,7 +3315,7 @@ private static Object invoke17(com.codename1.ai.vision.VisionBackend typedTarget throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke18(com.codename1.ai.vision.VisionPipelineListener typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke21(com.codename1.ai.vision.VisionPipelineListener typedTarget, String name, Object[] safeArgs) throws Exception { if ("error".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Throwable.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Throwable.class}, false); @@ -993,19 +3332,128 @@ private static Object invoke18(com.codename1.ai.vision.VisionPipelineListener ty } public static Object getStaticField(Class type, String name) throws Exception { - if (type == com.codename1.ai.vision.TextRecognitionResult.class) return getStaticField0(name); - if (type == com.codename1.ai.vision.VisionException.class) return getStaticField1(name); - if (type == com.codename1.ai.vision.VisionFeature.class) return getStaticField2(name); - if (type == com.codename1.ai.vision.VisionRect.class) return getStaticField3(name); + if (type == com.codename1.ai.vision.BarcodeFormat.class) return getStaticField0(name); + if (type == com.codename1.ai.vision.FaceLandmarks.class) return getStaticField1(name); + if (type == com.codename1.ai.vision.PoseLandmarks.class) return getStaticField2(name); + if (type == com.codename1.ai.vision.TextRecognitionResult.class) return getStaticField3(name); + if (type == com.codename1.ai.vision.VisionCameraView.class) return getStaticField4(name); + if (type == com.codename1.ai.vision.VisionException.class) return getStaticField5(name); + if (type == com.codename1.ai.vision.VisionFeature.class) return getStaticField6(name); + if (type == com.codename1.ai.vision.VisionRect.class) return getStaticField7(name); throw unsupportedStaticField(type, name); } private static Object getStaticField0(String name) throws Exception { + if ("AZTEC".equals(name)) return com.codename1.ai.vision.BarcodeFormat.AZTEC; + if ("CODABAR".equals(name)) return com.codename1.ai.vision.BarcodeFormat.CODABAR; + if ("CODE_128".equals(name)) return com.codename1.ai.vision.BarcodeFormat.CODE_128; + if ("CODE_39".equals(name)) return com.codename1.ai.vision.BarcodeFormat.CODE_39; + if ("CODE_93".equals(name)) return com.codename1.ai.vision.BarcodeFormat.CODE_93; + if ("DATA_MATRIX".equals(name)) return com.codename1.ai.vision.BarcodeFormat.DATA_MATRIX; + if ("EAN_13".equals(name)) return com.codename1.ai.vision.BarcodeFormat.EAN_13; + if ("EAN_8".equals(name)) return com.codename1.ai.vision.BarcodeFormat.EAN_8; + if ("ITF".equals(name)) return com.codename1.ai.vision.BarcodeFormat.ITF; + if ("PDF417".equals(name)) return com.codename1.ai.vision.BarcodeFormat.PDF417; + if ("QR_CODE".equals(name)) return com.codename1.ai.vision.BarcodeFormat.QR_CODE; + if ("UNKNOWN".equals(name)) return com.codename1.ai.vision.BarcodeFormat.UNKNOWN; + if ("UPC_A".equals(name)) return com.codename1.ai.vision.BarcodeFormat.UPC_A; + if ("UPC_E".equals(name)) return com.codename1.ai.vision.BarcodeFormat.UPC_E; + throw unsupportedStaticField(com.codename1.ai.vision.BarcodeFormat.class, name); + } + + private static Object getStaticField1(String name) throws Exception { + if ("LEFT_EYE".equals(name)) return com.codename1.ai.vision.FaceLandmarks.LEFT_EYE; + if ("MOUTH_LEFT".equals(name)) return com.codename1.ai.vision.FaceLandmarks.MOUTH_LEFT; + if ("MOUTH_RIGHT".equals(name)) return com.codename1.ai.vision.FaceLandmarks.MOUTH_RIGHT; + if ("NOSE_BASE".equals(name)) return com.codename1.ai.vision.FaceLandmarks.NOSE_BASE; + if ("RIGHT_EYE".equals(name)) return com.codename1.ai.vision.FaceLandmarks.RIGHT_EYE; + throw unsupportedStaticField(com.codename1.ai.vision.FaceLandmarks.class, name); + } + + private static Object getStaticField2(String name) throws Exception { + if ("LEFT_ANKLE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_ANKLE; + if ("LEFT_EAR".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_EAR; + if ("LEFT_ELBOW".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_ELBOW; + if ("LEFT_EYE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_EYE; + if ("LEFT_EYE_INNER".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_EYE_INNER; + if ("LEFT_EYE_OUTER".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_EYE_OUTER; + if ("LEFT_FOOT_INDEX".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_FOOT_INDEX; + if ("LEFT_HEEL".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_HEEL; + if ("LEFT_HIP".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_HIP; + if ("LEFT_INDEX".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_INDEX; + if ("LEFT_KNEE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_KNEE; + if ("LEFT_MOUTH".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_MOUTH; + if ("LEFT_PINKY".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_PINKY; + if ("LEFT_SHOULDER".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_SHOULDER; + if ("LEFT_THUMB".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_THUMB; + if ("LEFT_WRIST".equals(name)) return com.codename1.ai.vision.PoseLandmarks.LEFT_WRIST; + if ("NECK".equals(name)) return com.codename1.ai.vision.PoseLandmarks.NECK; + if ("NOSE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.NOSE; + if ("RIGHT_ANKLE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_ANKLE; + if ("RIGHT_EAR".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_EAR; + if ("RIGHT_ELBOW".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_ELBOW; + if ("RIGHT_EYE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_EYE; + if ("RIGHT_EYE_INNER".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_EYE_INNER; + if ("RIGHT_EYE_OUTER".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_EYE_OUTER; + if ("RIGHT_FOOT_INDEX".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_FOOT_INDEX; + if ("RIGHT_HEEL".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_HEEL; + if ("RIGHT_HIP".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_HIP; + if ("RIGHT_INDEX".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_INDEX; + if ("RIGHT_KNEE".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_KNEE; + if ("RIGHT_MOUTH".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_MOUTH; + if ("RIGHT_PINKY".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_PINKY; + if ("RIGHT_SHOULDER".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_SHOULDER; + if ("RIGHT_THUMB".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_THUMB; + if ("RIGHT_WRIST".equals(name)) return com.codename1.ai.vision.PoseLandmarks.RIGHT_WRIST; + if ("ROOT".equals(name)) return com.codename1.ai.vision.PoseLandmarks.ROOT; + if ("UNKNOWN".equals(name)) return com.codename1.ai.vision.PoseLandmarks.UNKNOWN; + throw unsupportedStaticField(com.codename1.ai.vision.PoseLandmarks.class, name); + } + + private static Object getStaticField3(String name) throws Exception { if ("EMPTY".equals(name)) return com.codename1.ai.vision.TextRecognitionResult.EMPTY; throw unsupportedStaticField(com.codename1.ai.vision.TextRecognitionResult.class, name); } - private static Object getStaticField1(String name) throws Exception { + private static Object getStaticField4(String name) throws Exception { + if ("BASELINE".equals(name)) return com.codename1.ai.vision.VisionCameraView.BASELINE; + if ("BOTTOM".equals(name)) return com.codename1.ai.vision.VisionCameraView.BOTTOM; + if ("BRB_CENTER_OFFSET".equals(name)) return com.codename1.ai.vision.VisionCameraView.BRB_CENTER_OFFSET; + if ("BRB_CONSTANT_ASCENT".equals(name)) return com.codename1.ai.vision.VisionCameraView.BRB_CONSTANT_ASCENT; + if ("BRB_CONSTANT_DESCENT".equals(name)) return com.codename1.ai.vision.VisionCameraView.BRB_CONSTANT_DESCENT; + if ("BRB_OTHER".equals(name)) return com.codename1.ai.vision.VisionCameraView.BRB_OTHER; + if ("CENTER".equals(name)) return com.codename1.ai.vision.VisionCameraView.CENTER; + if ("CROSSHAIR_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.CROSSHAIR_CURSOR; + if ("DEFAULT_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.DEFAULT_CURSOR; + if ("DRAG_REGION_IMMEDIATELY_DRAG_X".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_IMMEDIATELY_DRAG_X; + if ("DRAG_REGION_IMMEDIATELY_DRAG_XY".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_IMMEDIATELY_DRAG_XY; + if ("DRAG_REGION_IMMEDIATELY_DRAG_Y".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_IMMEDIATELY_DRAG_Y; + if ("DRAG_REGION_LIKELY_DRAG_X".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_LIKELY_DRAG_X; + if ("DRAG_REGION_LIKELY_DRAG_XY".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_LIKELY_DRAG_XY; + if ("DRAG_REGION_LIKELY_DRAG_Y".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_LIKELY_DRAG_Y; + if ("DRAG_REGION_NOT_DRAGGABLE".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_NOT_DRAGGABLE; + if ("DRAG_REGION_POSSIBLE_DRAG_X".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_POSSIBLE_DRAG_X; + if ("DRAG_REGION_POSSIBLE_DRAG_XY".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_POSSIBLE_DRAG_XY; + if ("DRAG_REGION_POSSIBLE_DRAG_Y".equals(name)) return com.codename1.ai.vision.VisionCameraView.DRAG_REGION_POSSIBLE_DRAG_Y; + if ("E_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.E_RESIZE_CURSOR; + if ("HAND_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.HAND_CURSOR; + if ("LEFT".equals(name)) return com.codename1.ai.vision.VisionCameraView.LEFT; + if ("MOVE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.MOVE_CURSOR; + if ("NE_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.NE_RESIZE_CURSOR; + if ("NW_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.NW_RESIZE_CURSOR; + if ("N_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.N_RESIZE_CURSOR; + if ("RIGHT".equals(name)) return com.codename1.ai.vision.VisionCameraView.RIGHT; + if ("SE_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.SE_RESIZE_CURSOR; + if ("SW_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.SW_RESIZE_CURSOR; + if ("S_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.S_RESIZE_CURSOR; + if ("TEXT_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.TEXT_CURSOR; + if ("TOP".equals(name)) return com.codename1.ai.vision.VisionCameraView.TOP; + if ("WAIT_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.WAIT_CURSOR; + if ("W_RESIZE_CURSOR".equals(name)) return com.codename1.ai.vision.VisionCameraView.W_RESIZE_CURSOR; + throw unsupportedStaticField(com.codename1.ai.vision.VisionCameraView.class, name); + } + + private static Object getStaticField5(String name) throws Exception { if ("BACKEND_ERROR".equals(name)) return com.codename1.ai.vision.VisionException.BACKEND_ERROR; if ("CANCELLED".equals(name)) return com.codename1.ai.vision.VisionException.CANCELLED; if ("INVALID_IMAGE".equals(name)) return com.codename1.ai.vision.VisionException.INVALID_IMAGE; @@ -1014,7 +3462,7 @@ private static Object getStaticField1(String name) throws Exception { throw unsupportedStaticField(com.codename1.ai.vision.VisionException.class, name); } - private static Object getStaticField2(String name) throws Exception { + private static Object getStaticField6(String name) throws Exception { if ("BARCODE_SCANNING".equals(name)) return com.codename1.ai.vision.VisionFeature.BARCODE_SCANNING; if ("DOCUMENT_SCANNING".equals(name)) return com.codename1.ai.vision.VisionFeature.DOCUMENT_SCANNING; if ("FACE_DETECTION".equals(name)) return com.codename1.ai.vision.VisionFeature.FACE_DETECTION; @@ -1025,7 +3473,7 @@ private static Object getStaticField2(String name) throws Exception { throw unsupportedStaticField(com.codename1.ai.vision.VisionFeature.class, name); } - private static Object getStaticField3(String name) throws Exception { + private static Object getStaticField7(String name) throws Exception { if ("EMPTY".equals(name)) return com.codename1.ai.vision.VisionRect.EMPTY; throw unsupportedStaticField(com.codename1.ai.vision.VisionRect.class, name); } diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations.java index 810d22da378..c464ef3bf8f 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations.java @@ -52,6 +52,9 @@ public static Class findClassBySimpleName(String simpleName) { private static Class findClassChunk0(String simpleName) { + if ("AppIntent".equals(simpleName)) { + return com.codename1.annotations.AppIntent.class; + } if ("Async".equals(simpleName)) { return com.codename1.annotations.Async.class; } @@ -88,6 +91,24 @@ private static Class findClassChunk0(String simpleName) { if ("Entity".equals(simpleName)) { return com.codename1.annotations.Entity.class; } + if ("EntityId".equals(simpleName)) { + return com.codename1.annotations.EntityId.class; + } + if ("EntityImage".equals(simpleName)) { + return com.codename1.annotations.EntityImage.class; + } + if ("EntityQuery".equals(simpleName)) { + return com.codename1.annotations.EntityQuery.class; + } + if ("Kind".equals(simpleName)) { + return com.codename1.annotations.EntityQuery.Kind.class; + } + if ("EntitySubtitle".equals(simpleName)) { + return com.codename1.annotations.EntitySubtitle.class; + } + if ("EntityTitle".equals(simpleName)) { + return com.codename1.annotations.EntityTitle.class; + } if ("ExistIn".equals(simpleName)) { return com.codename1.annotations.ExistIn.class; } @@ -97,6 +118,12 @@ private static Class findClassChunk0(String simpleName) { if ("Id".equals(simpleName)) { return com.codename1.annotations.Id.class; } + if ("IntentEntity".equals(simpleName)) { + return com.codename1.annotations.IntentEntity.class; + } + if ("IntentParam".equals(simpleName)) { + return com.codename1.annotations.IntentParam.class; + } if ("JsonIgnore".equals(simpleName)) { return com.codename1.annotations.JsonIgnore.class; } @@ -160,142 +187,170 @@ public static Object invokeStatic(Class type, String name, Object[] args) thr public static Object invoke(Object target, String name, Object[] args) throws Exception { Object[] safeArgs = safeArgs(args); CN1AccessException unsupported = null; + if (target instanceof com.codename1.annotations.AppIntent) { + try { + return invoke0((com.codename1.annotations.AppIntent) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } if (target instanceof com.codename1.annotations.Bind) { try { - return invoke0((com.codename1.annotations.Bind) target, name, safeArgs); + return invoke1((com.codename1.annotations.Bind) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Column) { try { - return invoke1((com.codename1.annotations.Column) target, name, safeArgs); + return invoke2((com.codename1.annotations.Column) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Concrete) { try { - return invoke2((com.codename1.annotations.Concrete) target, name, safeArgs); + return invoke3((com.codename1.annotations.Concrete) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Email) { try { - return invoke3((com.codename1.annotations.Email) target, name, safeArgs); + return invoke4((com.codename1.annotations.Email) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Entity) { try { - return invoke4((com.codename1.annotations.Entity) target, name, safeArgs); + return invoke5((com.codename1.annotations.Entity) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.EntityQuery) { + try { + return invoke6((com.codename1.annotations.EntityQuery) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.ExistIn) { try { - return invoke5((com.codename1.annotations.ExistIn) target, name, safeArgs); + return invoke7((com.codename1.annotations.ExistIn) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Id) { try { - return invoke6((com.codename1.annotations.Id) target, name, safeArgs); + return invoke8((com.codename1.annotations.Id) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.IntentEntity) { + try { + return invoke9((com.codename1.annotations.IntentEntity) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.IntentParam) { + try { + return invoke10((com.codename1.annotations.IntentParam) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.JsonProperty) { try { - return invoke7((com.codename1.annotations.JsonProperty) target, name, safeArgs); + return invoke11((com.codename1.annotations.JsonProperty) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Length) { try { - return invoke8((com.codename1.annotations.Length) target, name, safeArgs); + return invoke12((com.codename1.annotations.Length) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Numeric) { try { - return invoke9((com.codename1.annotations.Numeric) target, name, safeArgs); + return invoke13((com.codename1.annotations.Numeric) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Regex) { try { - return invoke10((com.codename1.annotations.Regex) target, name, safeArgs); + return invoke14((com.codename1.annotations.Regex) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Required) { try { - return invoke11((com.codename1.annotations.Required) target, name, safeArgs); + return invoke15((com.codename1.annotations.Required) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Route) { try { - return invoke12((com.codename1.annotations.Route) target, name, safeArgs); + return invoke16((com.codename1.annotations.Route) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Route.Routes) { try { - return invoke13((com.codename1.annotations.Route.Routes) target, name, safeArgs); + return invoke17((com.codename1.annotations.Route.Routes) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.RouteParam) { try { - return invoke14((com.codename1.annotations.RouteParam) target, name, safeArgs); + return invoke18((com.codename1.annotations.RouteParam) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Url) { try { - return invoke15((com.codename1.annotations.Url) target, name, safeArgs); + return invoke19((com.codename1.annotations.Url) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.Validate) { try { - return invoke16((com.codename1.annotations.Validate) target, name, safeArgs); + return invoke20((com.codename1.annotations.Validate) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.XmlAttribute) { try { - return invoke17((com.codename1.annotations.XmlAttribute) target, name, safeArgs); + return invoke21((com.codename1.annotations.XmlAttribute) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.XmlElement) { try { - return invoke18((com.codename1.annotations.XmlElement) target, name, safeArgs); + return invoke22((com.codename1.annotations.XmlElement) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.annotations.XmlRoot) { try { - return invoke19((com.codename1.annotations.XmlRoot) target, name, safeArgs); + return invoke23((com.codename1.annotations.XmlRoot) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } @@ -306,7 +361,61 @@ public static Object invoke(Object target, String name, Object[] args) throws Ex throw unsupportedInstance(target, name, safeArgs); } - private static Object invoke0(com.codename1.annotations.Bind typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke0(com.codename1.annotations.AppIntent typedTarget, String name, Object[] safeArgs) throws Exception { + if ("description".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.description(); + } + } + if ("destructive".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.destructive(); + } + } + if ("discoverable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.discoverable(); + } + } + if ("exposure".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.exposure(); + } + } + if ("headless".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.headless(); + } + } + if ("opensRoute".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.opensRoute(); + } + } + if ("phrases".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.phrases(); + } + } + if ("timeoutSeconds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.timeoutSeconds(); + } + } + if ("title".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.title(); + } + } + if ("value".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.value(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke1(com.codename1.annotations.Bind typedTarget, String name, Object[] safeArgs) throws Exception { if ("attr".equals(name)) { if (safeArgs.length == 0) { return typedTarget.attr(); @@ -335,7 +444,7 @@ private static Object invoke0(com.codename1.annotations.Bind typedTarget, String throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke1(com.codename1.annotations.Column typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke2(com.codename1.annotations.Column typedTarget, String name, Object[] safeArgs) throws Exception { if ("name".equals(name)) { if (safeArgs.length == 0) { return typedTarget.name(); @@ -354,7 +463,7 @@ private static Object invoke1(com.codename1.annotations.Column typedTarget, Stri throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke2(com.codename1.annotations.Concrete typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke3(com.codename1.annotations.Concrete typedTarget, String name, Object[] safeArgs) throws Exception { if ("linux".equals(name)) { if (safeArgs.length == 0) { return typedTarget.linux(); @@ -373,7 +482,7 @@ private static Object invoke2(com.codename1.annotations.Concrete typedTarget, St throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke3(com.codename1.annotations.Email typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke4(com.codename1.annotations.Email typedTarget, String name, Object[] safeArgs) throws Exception { if ("message".equals(name)) { if (safeArgs.length == 0) { return typedTarget.message(); @@ -382,7 +491,7 @@ private static Object invoke3(com.codename1.annotations.Email typedTarget, Strin throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke4(com.codename1.annotations.Entity typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke5(com.codename1.annotations.Entity typedTarget, String name, Object[] safeArgs) throws Exception { if ("table".equals(name)) { if (safeArgs.length == 0) { return typedTarget.table(); @@ -391,7 +500,16 @@ private static Object invoke4(com.codename1.annotations.Entity typedTarget, Stri throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke5(com.codename1.annotations.ExistIn typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke6(com.codename1.annotations.EntityQuery typedTarget, String name, Object[] safeArgs) throws Exception { + if ("value".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.value(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke7(com.codename1.annotations.ExistIn typedTarget, String name, Object[] safeArgs) throws Exception { if ("caseSensitive".equals(name)) { if (safeArgs.length == 0) { return typedTarget.caseSensitive(); @@ -410,7 +528,7 @@ private static Object invoke5(com.codename1.annotations.ExistIn typedTarget, Str throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke6(com.codename1.annotations.Id typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke8(com.codename1.annotations.Id typedTarget, String name, Object[] safeArgs) throws Exception { if ("autoIncrement".equals(name)) { if (safeArgs.length == 0) { return typedTarget.autoIncrement(); @@ -419,7 +537,17 @@ private static Object invoke6(com.codename1.annotations.Id typedTarget, String n throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke7(com.codename1.annotations.JsonProperty typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke9(com.codename1.annotations.IntentEntity typedTarget, String name, Object[] safeArgs) throws Exception { + if ("indexed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.indexed(); + } + } + if ("title".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.title(); + } + } if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -428,7 +556,45 @@ private static Object invoke7(com.codename1.annotations.JsonProperty typedTarget throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke8(com.codename1.annotations.Length typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke10(com.codename1.annotations.IntentParam typedTarget, String name, Object[] safeArgs) throws Exception { + if ("defaultValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.defaultValue(); + } + } + if ("options".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.options(); + } + } + if ("required".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.required(); + } + } + if ("title".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.title(); + } + } + if ("value".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.value(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke11(com.codename1.annotations.JsonProperty typedTarget, String name, Object[] safeArgs) throws Exception { + if ("value".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.value(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke12(com.codename1.annotations.Length typedTarget, String name, Object[] safeArgs) throws Exception { if ("message".equals(name)) { if (safeArgs.length == 0) { return typedTarget.message(); @@ -442,7 +608,7 @@ private static Object invoke8(com.codename1.annotations.Length typedTarget, Stri throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke9(com.codename1.annotations.Numeric typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke13(com.codename1.annotations.Numeric typedTarget, String name, Object[] safeArgs) throws Exception { if ("decimal".equals(name)) { if (safeArgs.length == 0) { return typedTarget.decimal(); @@ -466,7 +632,7 @@ private static Object invoke9(com.codename1.annotations.Numeric typedTarget, Str throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke10(com.codename1.annotations.Regex typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke14(com.codename1.annotations.Regex typedTarget, String name, Object[] safeArgs) throws Exception { if ("message".equals(name)) { if (safeArgs.length == 0) { return typedTarget.message(); @@ -480,7 +646,7 @@ private static Object invoke10(com.codename1.annotations.Regex typedTarget, Stri throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke11(com.codename1.annotations.Required typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke15(com.codename1.annotations.Required typedTarget, String name, Object[] safeArgs) throws Exception { if ("message".equals(name)) { if (safeArgs.length == 0) { return typedTarget.message(); @@ -489,7 +655,7 @@ private static Object invoke11(com.codename1.annotations.Required typedTarget, S throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke12(com.codename1.annotations.Route typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke16(com.codename1.annotations.Route typedTarget, String name, Object[] safeArgs) throws Exception { if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -498,7 +664,7 @@ private static Object invoke12(com.codename1.annotations.Route typedTarget, Stri throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke13(com.codename1.annotations.Route.Routes typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke17(com.codename1.annotations.Route.Routes typedTarget, String name, Object[] safeArgs) throws Exception { if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -507,7 +673,7 @@ private static Object invoke13(com.codename1.annotations.Route.Routes typedTarge throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke14(com.codename1.annotations.RouteParam typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke18(com.codename1.annotations.RouteParam typedTarget, String name, Object[] safeArgs) throws Exception { if ("required".equals(name)) { if (safeArgs.length == 0) { return typedTarget.required(); @@ -521,7 +687,7 @@ private static Object invoke14(com.codename1.annotations.RouteParam typedTarget, throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke15(com.codename1.annotations.Url typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke19(com.codename1.annotations.Url typedTarget, String name, Object[] safeArgs) throws Exception { if ("message".equals(name)) { if (safeArgs.length == 0) { return typedTarget.message(); @@ -530,7 +696,7 @@ private static Object invoke15(com.codename1.annotations.Url typedTarget, String throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke16(com.codename1.annotations.Validate typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke20(com.codename1.annotations.Validate typedTarget, String name, Object[] safeArgs) throws Exception { if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -539,7 +705,7 @@ private static Object invoke16(com.codename1.annotations.Validate typedTarget, S throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke17(com.codename1.annotations.XmlAttribute typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke21(com.codename1.annotations.XmlAttribute typedTarget, String name, Object[] safeArgs) throws Exception { if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -548,7 +714,7 @@ private static Object invoke17(com.codename1.annotations.XmlAttribute typedTarge throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke18(com.codename1.annotations.XmlElement typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke22(com.codename1.annotations.XmlElement typedTarget, String name, Object[] safeArgs) throws Exception { if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -557,7 +723,7 @@ private static Object invoke18(com.codename1.annotations.XmlElement typedTarget, throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke19(com.codename1.annotations.XmlRoot typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke23(com.codename1.annotations.XmlRoot typedTarget, String name, Object[] safeArgs) throws Exception { if ("value".equals(name)) { if (safeArgs.length == 0) { return typedTarget.value(); @@ -567,9 +733,17 @@ private static Object invoke19(com.codename1.annotations.XmlRoot typedTarget, St } public static Object getStaticField(Class type, String name) throws Exception { + if (type == com.codename1.annotations.EntityQuery.Kind.class) return getStaticField0(name); throw unsupportedStaticField(type, name); } + private static Object getStaticField0(String name) throws Exception { + if ("BY_ID".equals(name)) return com.codename1.annotations.EntityQuery.Kind.BY_ID; + if ("SEARCH".equals(name)) return com.codename1.annotations.EntityQuery.Kind.SEARCH; + if ("SUGGESTED".equals(name)) return com.codename1.annotations.EntityQuery.Kind.SUGGESTED; + throw unsupportedStaticField(com.codename1.annotations.EntityQuery.Kind.class, name); + } + public static Object getField(Object target, String name) throws Exception { throw unsupportedField(target, name); } diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations_buildhints.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations_buildhints.java new file mode 100644 index 00000000000..3dbf762dd66 --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_annotations_buildhints.java @@ -0,0 +1,1153 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_annotations_buildhints { + private GeneratedAccess_com_codename1_annotations_buildhints() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("Android".equals(simpleName)) { + return com.codename1.annotations.buildhints.Android.class; + } + if ("AndroidThemeMode".equals(simpleName)) { + return com.codename1.annotations.buildhints.AndroidThemeMode.class; + } + if ("Build".equals(simpleName)) { + return com.codename1.annotations.buildhints.Build.class; + } + if ("Desktop".equals(simpleName)) { + return com.codename1.annotations.buildhints.Desktop.class; + } + if ("DesktopTitleBar".equals(simpleName)) { + return com.codename1.annotations.buildhints.DesktopTitleBar.class; + } + if ("HardenControlFlow".equals(simpleName)) { + return com.codename1.annotations.buildhints.HardenControlFlow.class; + } + if ("HardenLevel".equals(simpleName)) { + return com.codename1.annotations.buildhints.HardenLevel.class; + } + if ("HardenStrings".equals(simpleName)) { + return com.codename1.annotations.buildhints.HardenStrings.class; + } + if ("Hardening".equals(simpleName)) { + return com.codename1.annotations.buildhints.Hardening.class; + } + if ("InstallLocation".equals(simpleName)) { + return com.codename1.annotations.buildhints.InstallLocation.class; + } + if ("Ios".equals(simpleName)) { + return com.codename1.annotations.buildhints.Ios.class; + } + if ("IosDependencyManager".equals(simpleName)) { + return com.codename1.annotations.buildhints.IosDependencyManager.class; + } + if ("IosPrivacy".equals(simpleName)) { + return com.codename1.annotations.buildhints.IosPrivacy.class; + } + if ("IosProjectType".equals(simpleName)) { + return com.codename1.annotations.buildhints.IosProjectType.class; + } + if ("IosThemeMode".equals(simpleName)) { + return com.codename1.annotations.buildhints.IosThemeMode.class; + } + if ("NativeThemeMode".equals(simpleName)) { + return com.codename1.annotations.buildhints.NativeThemeMode.class; + } + if ("OnDeviceDebug".equals(simpleName)) { + return com.codename1.annotations.buildhints.OnDeviceDebug.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedStatic(type, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (target instanceof com.codename1.annotations.buildhints.AndroidThemeMode) { + try { + return invoke0((com.codename1.annotations.buildhints.AndroidThemeMode) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.DesktopTitleBar) { + try { + return invoke1((com.codename1.annotations.buildhints.DesktopTitleBar) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.HardenControlFlow) { + try { + return invoke2((com.codename1.annotations.buildhints.HardenControlFlow) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.HardenLevel) { + try { + return invoke3((com.codename1.annotations.buildhints.HardenLevel) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.HardenStrings) { + try { + return invoke4((com.codename1.annotations.buildhints.HardenStrings) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.InstallLocation) { + try { + return invoke5((com.codename1.annotations.buildhints.InstallLocation) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.IosDependencyManager) { + try { + return invoke6((com.codename1.annotations.buildhints.IosDependencyManager) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.IosProjectType) { + try { + return invoke7((com.codename1.annotations.buildhints.IosProjectType) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.IosThemeMode) { + try { + return invoke8((com.codename1.annotations.buildhints.IosThemeMode) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.NativeThemeMode) { + try { + return invoke9((com.codename1.annotations.buildhints.NativeThemeMode) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.Android) { + try { + return invoke10((com.codename1.annotations.buildhints.Android) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.Build) { + try { + return invoke11((com.codename1.annotations.buildhints.Build) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.Desktop) { + try { + return invoke12((com.codename1.annotations.buildhints.Desktop) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.Hardening) { + try { + return invoke13((com.codename1.annotations.buildhints.Hardening) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.Ios) { + try { + return invoke14((com.codename1.annotations.buildhints.Ios) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.IosPrivacy) { + try { + return invoke15((com.codename1.annotations.buildhints.IosPrivacy) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.annotations.buildhints.OnDeviceDebug) { + try { + return invoke16((com.codename1.annotations.buildhints.OnDeviceDebug) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + private static Object invoke0(com.codename1.annotations.buildhints.AndroidThemeMode typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke1(com.codename1.annotations.buildhints.DesktopTitleBar typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke2(com.codename1.annotations.buildhints.HardenControlFlow typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke3(com.codename1.annotations.buildhints.HardenLevel typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke4(com.codename1.annotations.buildhints.HardenStrings typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke5(com.codename1.annotations.buildhints.InstallLocation typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke6(com.codename1.annotations.buildhints.IosDependencyManager typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke7(com.codename1.annotations.buildhints.IosProjectType typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke8(com.codename1.annotations.buildhints.IosThemeMode typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke9(com.codename1.annotations.buildhints.NativeThemeMode typedTarget, String name, Object[] safeArgs) throws Exception { + if ("wireValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wireValue(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke10(com.codename1.annotations.buildhints.Android typedTarget, String name, Object[] safeArgs) throws Exception { + if ("activityLaunchMode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.activityLaunchMode(); + } + } + if ("appBundle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.appBundle(); + } + } + if ("buildToolsVersion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.buildToolsVersion(); + } + } + if ("captureRecord".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.captureRecord(); + } + } + if ("debug".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.debug(); + } + } + if ("disableR8".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.disableR8(); + } + } + if ("enableProguard".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.enableProguard(); + } + } + if ("gradleDep".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.gradleDep(); + } + } + if ("hideStatusBar".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hideStatusBar(); + } + } + if ("installLocation".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.installLocation(); + } + } + if ("licenseKey".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.licenseKey(); + } + } + if ("minSdkVersion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.minSdkVersion(); + } + } + if ("multidex".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.multidex(); + } + } + if ("newFirebaseMessaging".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.newFirebaseMessaging(); + } + } + if ("proguardKeep".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.proguardKeep(); + } + } + if ("release".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.release(); + } + } + if ("repositories".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.repositories(); + } + } + if ("targetSDKVersion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.targetSDKVersion(); + } + } + if ("themeMode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.themeMode(); + } + } + if ("topDependency".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.topDependency(); + } + } + if ("useAndroidX".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.useAndroidX(); + } + } + if ("xapplication".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.xapplication(); + } + } + if ("xgradle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.xgradle(); + } + } + if ("xpermissions".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.xpermissions(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke11(com.codename1.annotations.buildhints.Build typedTarget, String name, Object[] safeArgs) throws Exception { + if ("facebookAppId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.facebookAppId(); + } + } + if ("gcmSenderId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.gcmSenderId(); + } + } + if ("nativeTheme".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.nativeTheme(); + } + } + if ("noExtraResources".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.noExtraResources(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke12(com.codename1.annotations.buildhints.Desktop typedTarget, String name, Object[] safeArgs) throws Exception { + if ("adaptToRetina".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.adaptToRetina(); + } + } + if ("fullscreen".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.fullscreen(); + } + } + if ("height".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.height(); + } + } + if ("interactiveScrollbars".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.interactiveScrollbars(); + } + } + if ("resizable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.resizable(); + } + } + if ("titleBar".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.titleBar(); + } + } + if ("width".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.width(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke13(com.codename1.annotations.buildhints.Hardening typedTarget, String name, Object[] safeArgs) throws Exception { + if ("allowUnhardenedLocalBuild".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.allowUnhardenedLocalBuild(); + } + } + if ("controlFlow".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.controlFlow(); + } + } + if ("keep".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.keep(); + } + } + if ("level".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.level(); + } + } + if ("rename".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.rename(); + } + } + if ("strings".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.strings(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke14(com.codename1.annotations.buildhints.Ios typedTarget, String name, Object[] safeArgs) throws Exception { + if ("addLibs".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.addLibs(); + } + } + if ("applicationQueriesSchemes".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.applicationQueriesSchemes(); + } + } + if ("beforeFinishLaunching".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.beforeFinishLaunching(); + } + } + if ("bundleVersion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.bundleVersion(); + } + } + if ("dependencyManager".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.dependencyManager(); + } + } + if ("deploymentTarget".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.deploymentTarget(); + } + } + if ("glAppDelegateHeader".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.glAppDelegateHeader(); + } + } + if ("includePush".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.includePush(); + } + } + if ("interfaceOrientation".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.interfaceOrientation(); + } + } + if ("minDeploymentTarget".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.minDeploymentTarget(); + } + } + if ("newStorageLocation".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.newStorageLocation(); + } + } + if ("objC".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.objC(); + } + } + if ("plistInject".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.plistInject(); + } + } + if ("pods".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.pods(); + } + } + if ("podsPlatform".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.podsPlatform(); + } + } + if ("podsSources".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.podsSources(); + } + } + if ("prerenderedIcon".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.prerenderedIcon(); + } + } + if ("projectType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.projectType(); + } + } + if ("spmPackages".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.spmPackages(); + } + } + if ("teamId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.teamId(); + } + } + if ("themeMode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.themeMode(); + } + } + if ("uiscene".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.uiscene(); + } + } + if ("urlScheme".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.urlScheme(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke15(com.codename1.annotations.buildhints.IosPrivacy typedTarget, String name, Object[] safeArgs) throws Exception { + if ("calendarsFullAccessUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.calendarsFullAccessUsageDescription(); + } + } + if ("calendarsUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.calendarsUsageDescription(); + } + } + if ("calendarsWriteOnlyAccessUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.calendarsWriteOnlyAccessUsageDescription(); + } + } + if ("cameraUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.cameraUsageDescription(); + } + } + if ("healthShareUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.healthShareUsageDescription(); + } + } + if ("healthUpdateUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.healthUpdateUsageDescription(); + } + } + if ("localNetworkUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.localNetworkUsageDescription(); + } + } + if ("locationAlwaysAndWhenInUseUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.locationAlwaysAndWhenInUseUsageDescription(); + } + } + if ("locationAlwaysUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.locationAlwaysUsageDescription(); + } + } + if ("locationWhenInUseUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.locationWhenInUseUsageDescription(); + } + } + if ("microphoneUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.microphoneUsageDescription(); + } + } + if ("remindersFullAccessUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.remindersFullAccessUsageDescription(); + } + } + if ("remindersUsageDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.remindersUsageDescription(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke16(com.codename1.annotations.buildhints.OnDeviceDebug typedTarget, String name, Object[] safeArgs) throws Exception { + if ("android".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.android(); + } + } + if ("ios".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.ios(); + } + } + if ("iosProxyHost".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.iosProxyHost(); + } + } + if ("iosProxyPort".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.iosProxyPort(); + } + } + if ("iosWaitForAttach".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.iosWaitForAttach(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + if (type == com.codename1.annotations.buildhints.AndroidThemeMode.class) return getStaticField0(name); + if (type == com.codename1.annotations.buildhints.DesktopTitleBar.class) return getStaticField1(name); + if (type == com.codename1.annotations.buildhints.HardenControlFlow.class) return getStaticField2(name); + if (type == com.codename1.annotations.buildhints.HardenLevel.class) return getStaticField3(name); + if (type == com.codename1.annotations.buildhints.HardenStrings.class) return getStaticField4(name); + if (type == com.codename1.annotations.buildhints.InstallLocation.class) return getStaticField5(name); + if (type == com.codename1.annotations.buildhints.IosDependencyManager.class) return getStaticField6(name); + if (type == com.codename1.annotations.buildhints.IosProjectType.class) return getStaticField7(name); + if (type == com.codename1.annotations.buildhints.IosThemeMode.class) return getStaticField8(name); + if (type == com.codename1.annotations.buildhints.NativeThemeMode.class) return getStaticField9(name); + throw unsupportedStaticField(type, name); + } + + private static Object getStaticField0(String name) throws Exception { + if ("AUTO".equals(name)) return com.codename1.annotations.buildhints.AndroidThemeMode.AUTO; + if ("HOLOLIGHT".equals(name)) return com.codename1.annotations.buildhints.AndroidThemeMode.HOLOLIGHT; + if ("LEGACY".equals(name)) return com.codename1.annotations.buildhints.AndroidThemeMode.LEGACY; + if ("MODERN".equals(name)) return com.codename1.annotations.buildhints.AndroidThemeMode.MODERN; + throw unsupportedStaticField(com.codename1.annotations.buildhints.AndroidThemeMode.class, name); + } + + private static Object getStaticField1(String name) throws Exception { + if ("CUSTOM".equals(name)) return com.codename1.annotations.buildhints.DesktopTitleBar.CUSTOM; + if ("NATIVE".equals(name)) return com.codename1.annotations.buildhints.DesktopTitleBar.NATIVE; + if ("TOOLBAR".equals(name)) return com.codename1.annotations.buildhints.DesktopTitleBar.TOOLBAR; + throw unsupportedStaticField(com.codename1.annotations.buildhints.DesktopTitleBar.class, name); + } + + private static Object getStaticField2(String name) throws Exception { + if ("OFF".equals(name)) return com.codename1.annotations.buildhints.HardenControlFlow.OFF; + if ("ON".equals(name)) return com.codename1.annotations.buildhints.HardenControlFlow.ON; + throw unsupportedStaticField(com.codename1.annotations.buildhints.HardenControlFlow.class, name); + } + + private static Object getStaticField3(String name) throws Exception { + if ("AGGRESSIVE".equals(name)) return com.codename1.annotations.buildhints.HardenLevel.AGGRESSIVE; + if ("OFF".equals(name)) return com.codename1.annotations.buildhints.HardenLevel.OFF; + if ("PARANOID".equals(name)) return com.codename1.annotations.buildhints.HardenLevel.PARANOID; + if ("STANDARD".equals(name)) return com.codename1.annotations.buildhints.HardenLevel.STANDARD; + throw unsupportedStaticField(com.codename1.annotations.buildhints.HardenLevel.class, name); + } + + private static Object getStaticField4(String name) throws Exception { + if ("ALL".equals(name)) return com.codename1.annotations.buildhints.HardenStrings.ALL; + if ("CONSTANTS".equals(name)) return com.codename1.annotations.buildhints.HardenStrings.CONSTANTS; + if ("OFF".equals(name)) return com.codename1.annotations.buildhints.HardenStrings.OFF; + throw unsupportedStaticField(com.codename1.annotations.buildhints.HardenStrings.class, name); + } + + private static Object getStaticField5(String name) throws Exception { + if ("AUTO".equals(name)) return com.codename1.annotations.buildhints.InstallLocation.AUTO; + if ("INTERNAL_ONLY".equals(name)) return com.codename1.annotations.buildhints.InstallLocation.INTERNAL_ONLY; + if ("PREFER_EXTERNAL".equals(name)) return com.codename1.annotations.buildhints.InstallLocation.PREFER_EXTERNAL; + throw unsupportedStaticField(com.codename1.annotations.buildhints.InstallLocation.class, name); + } + + private static Object getStaticField6(String name) throws Exception { + if ("AUTO".equals(name)) return com.codename1.annotations.buildhints.IosDependencyManager.AUTO; + if ("BOTH".equals(name)) return com.codename1.annotations.buildhints.IosDependencyManager.BOTH; + if ("COCOAPODS".equals(name)) return com.codename1.annotations.buildhints.IosDependencyManager.COCOAPODS; + if ("NONE".equals(name)) return com.codename1.annotations.buildhints.IosDependencyManager.NONE; + if ("SPM".equals(name)) return com.codename1.annotations.buildhints.IosDependencyManager.SPM; + throw unsupportedStaticField(com.codename1.annotations.buildhints.IosDependencyManager.class, name); + } + + private static Object getStaticField7(String name) throws Exception { + if ("IOS".equals(name)) return com.codename1.annotations.buildhints.IosProjectType.IOS; + if ("IPAD".equals(name)) return com.codename1.annotations.buildhints.IosProjectType.IPAD; + if ("IPHONE".equals(name)) return com.codename1.annotations.buildhints.IosProjectType.IPHONE; + throw unsupportedStaticField(com.codename1.annotations.buildhints.IosProjectType.class, name); + } + + private static Object getStaticField8(String name) throws Exception { + if ("AUTO".equals(name)) return com.codename1.annotations.buildhints.IosThemeMode.AUTO; + if ("IOS7".equals(name)) return com.codename1.annotations.buildhints.IosThemeMode.IOS7; + if ("LEGACY".equals(name)) return com.codename1.annotations.buildhints.IosThemeMode.LEGACY; + if ("MODERN".equals(name)) return com.codename1.annotations.buildhints.IosThemeMode.MODERN; + throw unsupportedStaticField(com.codename1.annotations.buildhints.IosThemeMode.class, name); + } + + private static Object getStaticField9(String name) throws Exception { + if ("CUSTOM".equals(name)) return com.codename1.annotations.buildhints.NativeThemeMode.CUSTOM; + if ("LEGACY".equals(name)) return com.codename1.annotations.buildhints.NativeThemeMode.LEGACY; + if ("MODERN".equals(name)) return com.codename1.annotations.buildhints.NativeThemeMode.MODERN; + throw unsupportedStaticField(com.codename1.annotations.buildhints.NativeThemeMode.class, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_crash.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_crash.java index a89227ff424..b6a1894fd65 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_crash.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_crash.java @@ -143,6 +143,12 @@ private static Object invoke0(com.codename1.crash.PiiScrubber typedTarget, Strin return typedTarget.scrubMessage((java.lang.String) adaptedArgs[0]); } } + if ("scrubRawStack".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.scrubRawStack((java.lang.String) adaptedArgs[0]); + } + } throw unsupportedInstance(typedTarget, name, safeArgs); } diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_db.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_db.java index e6cb467b589..f0230a10e9f 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_db.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_db.java @@ -165,6 +165,12 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep return com.codename1.db.Database.isCustomPathSupported(); } } + if ("isDatabaseBeingDeleted".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.db.Database.isDatabaseBeingDeleted((java.lang.String) adaptedArgs[0]); + } + } if ("isEncrypted".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -181,6 +187,12 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep return com.codename1.db.Database.isLegacyBehavior(); } } + if ("normalizeDatabaseKey".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.db.Database.normalizeDatabaseKey((java.lang.String) adaptedArgs[0]); + } + } if ("openOrCreate".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home.java new file mode 100644 index 00000000000..2d9ba9422db --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home.java @@ -0,0 +1,2561 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_home { + private GeneratedAccess_com_codename1_home() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("Accessory".equals(simpleName)) { + return com.codename1.home.Accessory.class; + } + if ("AccessoryCategory".equals(simpleName)) { + return com.codename1.home.AccessoryCategory.class; + } + if ("AccessoryService".equals(simpleName)) { + return com.codename1.home.AccessoryService.class; + } + if ("AirQualityLevel".equals(simpleName)) { + return com.codename1.home.AirQualityLevel.class; + } + if ("AlarmState".equals(simpleName)) { + return com.codename1.home.AlarmState.class; + } + if ("ChargingState".equals(simpleName)) { + return com.codename1.home.ChargingState.class; + } + if ("DoorState".equals(simpleName)) { + return com.codename1.home.DoorState.class; + } + if ("FanMode".equals(simpleName)) { + return com.codename1.home.FanMode.class; + } + if ("HeatingCoolingMode".equals(simpleName)) { + return com.codename1.home.HeatingCoolingMode.class; + } + if ("HomeAuthorizationStatus".equals(simpleName)) { + return com.codename1.home.HomeAuthorizationStatus.class; + } + if ("HomeAvailability".equals(simpleName)) { + return com.codename1.home.HomeAvailability.class; + } + if ("HomeBackend".equals(simpleName)) { + return com.codename1.home.HomeBackend.class; + } + if ("HomeChangeListener".equals(simpleName)) { + return com.codename1.home.HomeChangeListener.class; + } + if ("HomeConfigurationException".equals(simpleName)) { + return com.codename1.home.HomeConfigurationException.class; + } + if ("HomeError".equals(simpleName)) { + return com.codename1.home.HomeError.class; + } + if ("HomeException".equals(simpleName)) { + return com.codename1.home.HomeException.class; + } + if ("HomeRoom".equals(simpleName)) { + return com.codename1.home.HomeRoom.class; + } + if ("HomeStructure".equals(simpleName)) { + return com.codename1.home.HomeStructure.class; + } + if ("HomeStructureEvent".equals(simpleName)) { + return com.codename1.home.HomeStructureEvent.class; + } + if ("HomeStructureListener".equals(simpleName)) { + return com.codename1.home.HomeStructureListener.class; + } + if ("HomeZone".equals(simpleName)) { + return com.codename1.home.HomeZone.class; + } + if ("LockState".equals(simpleName)) { + return com.codename1.home.LockState.class; + } + if ("PositionState".equals(simpleName)) { + return com.codename1.home.PositionState.class; + } + if ("Scene".equals(simpleName)) { + return com.codename1.home.Scene.class; + } + if ("SceneAction".equals(simpleName)) { + return com.codename1.home.SceneAction.class; + } + if ("SceneType".equals(simpleName)) { + return com.codename1.home.SceneType.class; + } + if ("ServiceType".equals(simpleName)) { + return com.codename1.home.ServiceType.class; + } + if ("SmartHome".equals(simpleName)) { + return com.codename1.home.SmartHome.class; + } + if ("StructureChangeKind".equals(simpleName)) { + return com.codename1.home.StructureChangeKind.class; + } + if ("SubscriptionRequest".equals(simpleName)) { + return com.codename1.home.SubscriptionRequest.class; + } + if ("Trait".equals(simpleName)) { + return com.codename1.home.Trait.class; + } + if ("TraitChangeBatch".equals(simpleName)) { + return com.codename1.home.TraitChangeBatch.class; + } + if ("TraitConstraint".equals(simpleName)) { + return com.codename1.home.TraitConstraint.class; + } + if ("TraitReadRequest".equals(simpleName)) { + return com.codename1.home.TraitReadRequest.class; + } + if ("TraitReading".equals(simpleName)) { + return com.codename1.home.TraitReading.class; + } + if ("TraitSubscription".equals(simpleName)) { + return com.codename1.home.TraitSubscription.class; + } + if ("TraitUnit".equals(simpleName)) { + return com.codename1.home.TraitUnit.class; + } + if ("TraitUnitDimension".equals(simpleName)) { + return com.codename1.home.TraitUnitDimension.class; + } + if ("TraitValue".equals(simpleName)) { + return com.codename1.home.TraitValue.class; + } + if ("TraitValueKind".equals(simpleName)) { + return com.codename1.home.TraitValueKind.class; + } + if ("TraitWrite".equals(simpleName)) { + return com.codename1.home.TraitWrite.class; + } + if ("TraitWriteResult".equals(simpleName)) { + return com.codename1.home.TraitWriteResult.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.home.Accessory.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, com.codename1.home.AccessoryCategory.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.String.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, com.codename1.home.AccessoryCategory.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.String.class, java.util.List.class}, false); + return new com.codename1.home.Accessory((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (com.codename1.home.AccessoryCategory) adaptedArgs[3], (java.lang.String) adaptedArgs[4], (java.lang.String) adaptedArgs[5], (java.lang.String) adaptedArgs[6], ((Boolean) adaptedArgs[7]).booleanValue(), (java.lang.String) adaptedArgs[8], (java.util.List) adaptedArgs[9]); + } + } + if (type == com.codename1.home.AccessoryService.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.ServiceType.class, java.lang.Boolean.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.ServiceType.class, java.lang.Boolean.class, java.util.List.class}, false); + return new com.codename1.home.AccessoryService((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.ServiceType) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue(), (java.util.List) adaptedArgs[4]); + } + } + if (type == com.codename1.home.HomeConfigurationException.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return new com.codename1.home.HomeConfigurationException((java.lang.String) adaptedArgs[0]); + } + } + if (type == com.codename1.home.HomeException.class) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeError.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeError.class, java.lang.String.class}, false); + return new com.codename1.home.HomeException((com.codename1.home.HomeError) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + if (matches(safeArgs, new Class[]{com.codename1.home.HomeError.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeError.class, java.lang.String.class, java.lang.String.class}, false); + return new com.codename1.home.HomeException((com.codename1.home.HomeError) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + if (matches(safeArgs, new Class[]{com.codename1.home.HomeError.class, java.lang.String.class, java.lang.String.class, java.lang.Throwable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeError.class, java.lang.String.class, java.lang.String.class, java.lang.Throwable.class}, false); + return new com.codename1.home.HomeException((com.codename1.home.HomeError) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (java.lang.Throwable) adaptedArgs[3]); + } + } + if (type == com.codename1.home.HomeRoom.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false); + return new com.codename1.home.HomeRoom((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + } + if (type == com.codename1.home.HomeStructure.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.util.List.class, java.util.List.class, java.util.List.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.util.List.class, java.util.List.class, java.util.List.class, java.util.List.class}, false); + return new com.codename1.home.HomeStructure((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], ((Boolean) adaptedArgs[2]).booleanValue(), ((Boolean) adaptedArgs[3]).booleanValue(), ((Boolean) adaptedArgs[4]).booleanValue(), (java.util.List) adaptedArgs[5], (java.util.List) adaptedArgs[6], (java.util.List) adaptedArgs[7], (java.util.List) adaptedArgs[8]); + } + } + if (type == com.codename1.home.HomeStructureEvent.class) { + if (matches(safeArgs, new Class[]{com.codename1.home.StructureChangeKind.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.StructureChangeKind.class, java.lang.String.class, java.lang.String.class}, false); + return new com.codename1.home.HomeStructureEvent((com.codename1.home.StructureChangeKind) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + } + if (type == com.codename1.home.HomeZone.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.util.List.class}, false); + return new com.codename1.home.HomeZone((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.util.List) adaptedArgs[2]); + } + } + if (type == com.codename1.home.Scene.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, com.codename1.home.SceneType.class, java.lang.Boolean.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, com.codename1.home.SceneType.class, java.lang.Boolean.class, java.util.List.class}, false); + return new com.codename1.home.Scene((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (com.codename1.home.SceneType) adaptedArgs[3], ((Boolean) adaptedArgs[4]).booleanValue(), (java.util.List) adaptedArgs[5]); + } + } + if (type == com.codename1.home.SceneAction.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class}, false); + return new com.codename1.home.SceneAction((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2], (com.codename1.home.TraitValue) adaptedArgs[3]); + } + } + if (type == com.codename1.home.SubscriptionRequest.class) { + if (matches(safeArgs, new Class[0], false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[0], false); + return new com.codename1.home.SubscriptionRequest(); + } + } + if (type == com.codename1.home.TraitChangeBatch.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.List.class, java.lang.Boolean.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.List.class, java.lang.Boolean.class, java.lang.Boolean.class}, false); + return new com.codename1.home.TraitChangeBatch((java.lang.String) adaptedArgs[0], (java.util.List) adaptedArgs[1], ((Boolean) adaptedArgs[2]).booleanValue(), ((Boolean) adaptedArgs[3]).booleanValue()); + } + } + if (type == com.codename1.home.TraitReadRequest.class) { + if (matches(safeArgs, new Class[0], false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[0], false); + return new com.codename1.home.TraitReadRequest(); + } + } + if (type == com.codename1.home.TraitWrite.class) { + if (matches(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class}, false); + return new com.codename1.home.TraitWrite((com.codename1.home.Accessory) adaptedArgs[0], (com.codename1.home.AccessoryService) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2], (com.codename1.home.TraitValue) adaptedArgs[3]); + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class}, false); + return new com.codename1.home.TraitWrite((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2], (com.codename1.home.TraitValue) adaptedArgs[3]); + } + } + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.home.AirQualityLevel.class) return invokeStatic0(name, safeArgs); + if (type == com.codename1.home.AlarmState.class) return invokeStatic1(name, safeArgs); + if (type == com.codename1.home.ChargingState.class) return invokeStatic2(name, safeArgs); + if (type == com.codename1.home.DoorState.class) return invokeStatic3(name, safeArgs); + if (type == com.codename1.home.FanMode.class) return invokeStatic4(name, safeArgs); + if (type == com.codename1.home.HeatingCoolingMode.class) return invokeStatic5(name, safeArgs); + if (type == com.codename1.home.HomeError.class) return invokeStatic6(name, safeArgs); + if (type == com.codename1.home.LockState.class) return invokeStatic7(name, safeArgs); + if (type == com.codename1.home.PositionState.class) return invokeStatic8(name, safeArgs); + if (type == com.codename1.home.SmartHome.class) return invokeStatic9(name, safeArgs); + if (type == com.codename1.home.Trait.class) return invokeStatic10(name, safeArgs); + if (type == com.codename1.home.TraitConstraint.class) return invokeStatic11(name, safeArgs); + if (type == com.codename1.home.TraitReading.class) return invokeStatic12(name, safeArgs); + if (type == com.codename1.home.TraitUnit.class) return invokeStatic13(name, safeArgs); + if (type == com.codename1.home.TraitValue.class) return invokeStatic14(name, safeArgs); + if (type == com.codename1.home.TraitWriteResult.class) return invokeStatic15(name, safeArgs); + throw unsupportedStatic(type, name, safeArgs); + } + + private static Object invokeStatic0(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.AirQualityLevel.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.AirQualityLevel.class, name, safeArgs); + } + + private static Object invokeStatic1(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.AlarmState.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.AlarmState.class, name, safeArgs); + } + + private static Object invokeStatic2(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.ChargingState.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.ChargingState.class, name, safeArgs); + } + + private static Object invokeStatic3(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.DoorState.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.DoorState.class, name, safeArgs); + } + + private static Object invokeStatic4(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.FanMode.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.FanMode.class, name, safeArgs); + } + + private static Object invokeStatic5(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.HeatingCoolingMode.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.HeatingCoolingMode.class, name, safeArgs); + } + + private static Object invokeStatic6(String name, Object[] safeArgs) throws Exception { + if ("forName".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.home.HomeError.forName((java.lang.String) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.HomeError.class, name, safeArgs); + } + + private static Object invokeStatic7(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.LockState.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.LockState.class, name, safeArgs); + } + + private static Object invokeStatic8(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return com.codename1.home.PositionState.of((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.PositionState.class, name, safeArgs); + } + + private static Object invokeStatic9(String name, Object[] safeArgs) throws Exception { + if ("deliverAuthorization".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverAuthorization(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("deliverChanges".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String[].class}, false); + com.codename1.home.SmartHome.deliverChanges((java.lang.String) adaptedArgs[0], (java.lang.String[]) adaptedArgs[1]); return null; + } + } + if ("deliverCommissioningResult".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Integer.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverCommissioningResult(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (java.lang.String) adaptedArgs[3], toIntValue(adaptedArgs[4]), (java.lang.String) adaptedArgs[5]); return null; + } + } + if ("deliverDrained".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverDrained(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("deliverIdentifyResult".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverIdentifyResult(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1]); return null; + } + } + if ("deliverReadings".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverReadings(toIntValue(adaptedArgs[0]), (java.lang.String[]) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("deliverRefreshed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverRefreshed(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1]); return null; + } + } + if ("deliverResyncRequired".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverResyncRequired((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("deliverSceneResult".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverSceneResult(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (java.lang.String) adaptedArgs[3]); return null; + } + } + if ("deliverStarted".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverStarted(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1]), (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("deliverWriteResults".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String.class}, false); + com.codename1.home.SmartHome.deliverWriteResults(toIntValue(adaptedArgs[0]), (java.lang.String[]) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("getInstance".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.home.SmartHome.getInstance(); + } + } + if ("notifyStructureChanged".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class}, false); + com.codename1.home.SmartHome.notifyStructureChanged(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); return null; + } + } + throw unsupportedStatic(com.codename1.home.SmartHome.class, name, safeArgs); + } + + private static Object invokeStatic10(String name, Object[] safeArgs) throws Exception { + if ("all".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.home.Trait.all(); + } + } + if ("forId".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.home.Trait.forId((java.lang.String) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.Trait.class, name, safeArgs); + } + + private static Object invokeStatic11(String name, Object[] safeArgs) throws Exception { + if ("choices".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, int[].class}, false); + return com.codename1.home.TraitConstraint.choices((com.codename1.home.Trait) adaptedArgs[0], ((Boolean) adaptedArgs[1]).booleanValue(), ((Boolean) adaptedArgs[2]).booleanValue(), ((Boolean) adaptedArgs[3]).booleanValue(), (int[]) adaptedArgs[4]); + } + } + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class}, false); + return com.codename1.home.TraitConstraint.of((com.codename1.home.Trait) adaptedArgs[0], ((Boolean) adaptedArgs[1]).booleanValue(), ((Boolean) adaptedArgs[2]).booleanValue(), ((Boolean) adaptedArgs[3]).booleanValue()); + } + } + if ("ranged".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Double.class, java.lang.Double.class, java.lang.Double.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Double.class, java.lang.Double.class, java.lang.Double.class}, false); + return com.codename1.home.TraitConstraint.ranged((com.codename1.home.Trait) adaptedArgs[0], ((Boolean) adaptedArgs[1]).booleanValue(), ((Boolean) adaptedArgs[2]).booleanValue(), ((Boolean) adaptedArgs[3]).booleanValue(), ((Number) adaptedArgs[4]).doubleValue(), ((Number) adaptedArgs[5]).doubleValue(), ((Number) adaptedArgs[6]).doubleValue()); + } + } + throw unsupportedStatic(com.codename1.home.TraitConstraint.class, name, safeArgs); + } + + private static Object invokeStatic12(String name, Object[] safeArgs) throws Exception { + if ("absent".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class}, false); + return com.codename1.home.TraitReading.absent((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2]); + } + } + if ("failed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.HomeError.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.HomeError.class, java.lang.String.class}, false); + return com.codename1.home.TraitReading.failed((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2], (com.codename1.home.HomeError) adaptedArgs[3], (java.lang.String) adaptedArgs[4]); + } + } + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class, java.lang.Long.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class, com.codename1.home.TraitValue.class, java.lang.Long.class}, false); + return com.codename1.home.TraitReading.of((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2], (com.codename1.home.TraitValue) adaptedArgs[3], ((Number) adaptedArgs[4]).longValue()); + } + } + throw unsupportedStatic(com.codename1.home.TraitReading.class, name, safeArgs); + } + + private static Object invokeStatic13(String name, Object[] safeArgs) throws Exception { + if ("convert".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Double.class, com.codename1.home.TraitUnit.class, com.codename1.home.TraitUnit.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Double.class, com.codename1.home.TraitUnit.class, com.codename1.home.TraitUnit.class}, false); + return com.codename1.home.TraitUnit.convert(((Number) adaptedArgs[0]).doubleValue(), (com.codename1.home.TraitUnit) adaptedArgs[1], (com.codename1.home.TraitUnit) adaptedArgs[2]); + } + } + if ("forWireId".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return com.codename1.home.TraitUnit.forWireId(toIntValue(adaptedArgs[0])); + } + } + if ("kelvinToMired".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Double.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Double.class}, false); + return com.codename1.home.TraitUnit.kelvinToMired(((Number) adaptedArgs[0]).doubleValue()); + } + } + if ("miredToKelvin".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Double.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Double.class}, false); + return com.codename1.home.TraitUnit.miredToKelvin(((Number) adaptedArgs[0]).doubleValue()); + } + } + throw unsupportedStatic(com.codename1.home.TraitUnit.class, name, safeArgs); + } + + private static Object invokeStatic14(String name, Object[] safeArgs) throws Exception { + if ("of".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return com.codename1.home.TraitValue.of(((Boolean) adaptedArgs[0]).booleanValue()); + } + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return com.codename1.home.TraitValue.of(toIntValue(adaptedArgs[0])); + } + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.home.TraitValue.of((java.lang.String) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.Double.class, com.codename1.home.TraitUnit.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Double.class, com.codename1.home.TraitUnit.class}, false); + return com.codename1.home.TraitValue.of(((Number) adaptedArgs[0]).doubleValue(), (com.codename1.home.TraitUnit) adaptedArgs[1]); + } + } + if ("ofEnum".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Enum.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Enum.class}, false); + return com.codename1.home.TraitValue.ofEnum((java.lang.Enum) adaptedArgs[0]); + } + } + if ("ofEnumOrdinal".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return com.codename1.home.TraitValue.ofEnumOrdinal(toIntValue(adaptedArgs[0])); + } + } + throw unsupportedStatic(com.codename1.home.TraitValue.class, name, safeArgs); + } + + private static Object invokeStatic15(String name, Object[] safeArgs) throws Exception { + if ("applied".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitWrite.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitWrite.class}, false); + return com.codename1.home.TraitWriteResult.applied((com.codename1.home.TraitWrite) adaptedArgs[0]); + } + } + if ("failed".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitWrite.class, com.codename1.home.HomeError.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitWrite.class, com.codename1.home.HomeError.class, java.lang.String.class}, false); + return com.codename1.home.TraitWriteResult.failed((com.codename1.home.TraitWrite) adaptedArgs[0], (com.codename1.home.HomeError) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + } + throw unsupportedStatic(com.codename1.home.TraitWriteResult.class, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (target instanceof com.codename1.home.HomeConfigurationException) { + try { + return invoke0((com.codename1.home.HomeConfigurationException) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.Accessory) { + try { + return invoke1((com.codename1.home.Accessory) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.AccessoryService) { + try { + return invoke2((com.codename1.home.AccessoryService) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.DoorState) { + try { + return invoke3((com.codename1.home.DoorState) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HeatingCoolingMode) { + try { + return invoke4((com.codename1.home.HeatingCoolingMode) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeException) { + try { + return invoke5((com.codename1.home.HomeException) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeRoom) { + try { + return invoke6((com.codename1.home.HomeRoom) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeStructure) { + try { + return invoke7((com.codename1.home.HomeStructure) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeStructureEvent) { + try { + return invoke8((com.codename1.home.HomeStructureEvent) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeZone) { + try { + return invoke9((com.codename1.home.HomeZone) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.LockState) { + try { + return invoke10((com.codename1.home.LockState) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.Scene) { + try { + return invoke11((com.codename1.home.Scene) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.SceneAction) { + try { + return invoke12((com.codename1.home.SceneAction) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.SmartHome) { + try { + return invoke13((com.codename1.home.SmartHome) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.SubscriptionRequest) { + try { + return invoke14((com.codename1.home.SubscriptionRequest) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.Trait) { + try { + return invoke15((com.codename1.home.Trait) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitChangeBatch) { + try { + return invoke16((com.codename1.home.TraitChangeBatch) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitConstraint) { + try { + return invoke17((com.codename1.home.TraitConstraint) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitReadRequest) { + try { + return invoke18((com.codename1.home.TraitReadRequest) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitReading) { + try { + return invoke19((com.codename1.home.TraitReading) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitSubscription) { + try { + return invoke20((com.codename1.home.TraitSubscription) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitUnit) { + try { + return invoke21((com.codename1.home.TraitUnit) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitValue) { + try { + return invoke22((com.codename1.home.TraitValue) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitWrite) { + try { + return invoke23((com.codename1.home.TraitWrite) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.TraitWriteResult) { + try { + return invoke24((com.codename1.home.TraitWriteResult) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeChangeListener) { + try { + return invoke25((com.codename1.home.HomeChangeListener) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.HomeStructureListener) { + try { + return invoke26((com.codename1.home.HomeStructureListener) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + private static Object invoke0(com.codename1.home.HomeConfigurationException typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getError".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getError(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke1(com.codename1.home.Accessory typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getBridgeAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBridgeAccessoryId(); + } + } + if ("getCategory".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCategory(); + } + } + if ("getFirmwareVersion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getFirmwareVersion(); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getManufacturer".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getManufacturer(); + } + } + if ("getModel".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getModel(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getPrimaryService".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPrimaryService(); + } + } + if ("getRoomId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRoomId(); + } + } + if ("getService".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getService((java.lang.String) adaptedArgs[0]); + } + } + if ("getServices".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getServices(); + } + } + if ("getServicesSupporting".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class}, false); + return typedTarget.getServicesSupporting((com.codename1.home.Trait) adaptedArgs[0]); + } + } + if ("isBridged".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isBridged(); + } + } + if ("isReachable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isReachable(); + } + } + if ("supports".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class}, false); + return typedTarget.supports((com.codename1.home.Trait) adaptedArgs[0]); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke2(com.codename1.home.AccessoryService typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getConstraint".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class}, false); + return typedTarget.getConstraint((com.codename1.home.Trait) adaptedArgs[0]); + } + } + if ("getConstraints".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getConstraints(); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getTraits".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTraits(); + } + } + if ("getType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getType(); + } + } + if ("isPrimary".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isPrimary(); + } + } + if ("supports".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class}, false); + return typedTarget.supports((com.codename1.home.Trait) adaptedArgs[0]); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke3(com.codename1.home.DoorState typedTarget, String name, Object[] safeArgs) throws Exception { + if ("isWritable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isWritable(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke4(com.codename1.home.HeatingCoolingMode typedTarget, String name, Object[] safeArgs) throws Exception { + if ("isWritable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isWritable(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke5(com.codename1.home.HomeException typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getError".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getError(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke6(com.codename1.home.HomeRoom typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getStructureId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructureId(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke7(com.codename1.home.HomeStructure typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessories".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessories(); + } + } + if ("getAccessoriesInRoom".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getAccessoriesInRoom((java.lang.String) adaptedArgs[0]); + } + } + if ("getAccessoriesSupporting".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Trait.class}, false); + return typedTarget.getAccessoriesSupporting((com.codename1.home.Trait) adaptedArgs[0]); + } + } + if ("getAccessory".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getAccessory((java.lang.String) adaptedArgs[0]); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getRoom".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getRoom((java.lang.String) adaptedArgs[0]); + } + } + if ("getRooms".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRooms(); + } + } + if ("getScenes".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getScenes(); + } + } + if ("getZones".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getZones(); + } + } + if ("isOwner".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isOwner(); + } + } + if ("isPrimary".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isPrimary(); + } + } + if ("isSceneAuthoringSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSceneAuthoringSupported(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke8(com.codename1.home.HomeStructureEvent typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getKind".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getKind(); + } + } + if ("getStructureId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructureId(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke9(com.codename1.home.HomeZone typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getRoomIds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRoomIds(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke10(com.codename1.home.LockState typedTarget, String name, Object[] safeArgs) throws Exception { + if ("isWritable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isWritable(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke11(com.codename1.home.Scene typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getActions".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getActions(); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getStructureId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructureId(); + } + } + if ("getType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getType(); + } + } + if ("isExecutable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isExecutable(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke12(com.codename1.home.SceneAction typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getServiceId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getServiceId(); + } + } + if ("getTrait".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTrait(); + } + } + if ("getValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValue(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke13(com.codename1.home.SmartHome typedTarget, String name, Object[] safeArgs) throws Exception { + if ("addStructureListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeStructureListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeStructureListener.class}, false); + typedTarget.addStructureListener((com.codename1.home.HomeStructureListener) adaptedArgs[0]); return null; + } + } + if ("areIdsPersistent".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.areIdsPersistent(); + } + } + if ("createScene".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeStructure.class, java.lang.String.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeStructure.class, java.lang.String.class, java.util.List.class}, false); + return typedTarget.createScene((com.codename1.home.HomeStructure) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.util.List) adaptedArgs[2]); + } + } + if ("deleteScene".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Scene.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Scene.class}, false); + return typedTarget.deleteScene((com.codename1.home.Scene) adaptedArgs[0]); + } + } + if ("drainChanges".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.drainChanges(); + } + } + if ("executeScene".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Scene.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Scene.class}, false); + return typedTarget.executeScene((com.codename1.home.Scene) adaptedArgs[0]); + } + } + if ("findAccessory".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.findAccessory((java.lang.String) adaptedArgs[0]); + } + } + if ("getAuthorizationStatus".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAuthorizationStatus(); + } + } + if ("getAvailability".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAvailability(); + } + } + if ("getBackend".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBackend(); + } + } + if ("getCommissioner".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCommissioner(); + } + } + if ("getConfigurationProblems".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getConfigurationProblems(); + } + } + if ("getMaxReadBatchSize".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaxReadBatchSize(); + } + } + if ("getMaxWriteBatchSize".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaxWriteBatchSize(); + } + } + if ("getPrimaryStructure".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPrimaryStructure(); + } + } + if ("getStructures".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructures(); + } + } + if ("identify".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Accessory.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Accessory.class}, false); + return typedTarget.identify((com.codename1.home.Accessory) adaptedArgs[0]); + } + } + if ("isAutomationSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isAutomationSupported(); + } + } + if ("isSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSupported(); + } + } + if ("openEcosystemApp".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openEcosystemApp(); + } + } + if ("openHomeSettings".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openHomeSettings(); + } + } + if ("openProviderSetup".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openProviderSetup(); + } + } + if ("read".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitReadRequest.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitReadRequest.class}, false); + return typedTarget.read((com.codename1.home.TraitReadRequest) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class}, false); + return typedTarget.read((com.codename1.home.Accessory) adaptedArgs[0], (com.codename1.home.AccessoryService) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2]); + } + } + if ("refresh".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.refresh(); + } + } + if ("removeStructureListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeStructureListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeStructureListener.class}, false); + typedTarget.removeStructureListener((com.codename1.home.HomeStructureListener) adaptedArgs[0]); return null; + } + } + if ("requestAuthorization".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.requestAuthorization(); + } + } + if ("subscribe".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.SubscriptionRequest.class, com.codename1.home.HomeChangeListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.SubscriptionRequest.class, com.codename1.home.HomeChangeListener.class}, false); + return typedTarget.subscribe((com.codename1.home.SubscriptionRequest) adaptedArgs[0], (com.codename1.home.HomeChangeListener) adaptedArgs[1]); + } + } + if ("write".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitWrite.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitWrite.class}, false); + return typedTarget.write((com.codename1.home.TraitWrite) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.List.class}, false); + return typedTarget.write((java.util.List) adaptedArgs[0]); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke14(com.codename1.home.SubscriptionRequest typedTarget, String name, Object[] safeArgs) throws Exception { + if ("add".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class}, false); + return typedTarget.add((com.codename1.home.Accessory) adaptedArgs[0], (com.codename1.home.AccessoryService) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2]); + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class}, false); + return typedTarget.add((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2]); + } + } + if ("getAccessoryIds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryIds(); + } + } + if ("getMinIntervalMillis".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMinIntervalMillis(); + } + } + if ("getServiceIds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getServiceIds(); + } + } + if ("getTraits".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTraits(); + } + } + if ("isDeliverInitialValues".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDeliverInitialValues(); + } + } + if ("isEmpty".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEmpty(); + } + } + if ("setDeliverInitialValues".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.setDeliverInitialValues(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("setMinIntervalMillis".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.setMinIntervalMillis(toIntValue(adaptedArgs[0])); + } + } + if ("size".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.size(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke15(com.codename1.home.Trait typedTarget, String name, Object[] safeArgs) throws Exception { + if ("acceptsEnumValue".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return typedTarget.acceptsEnumValue((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + if ("acceptsEnumWrite".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return typedTarget.acceptsEnumWrite((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + if ("acceptsUnit".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitUnit.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitUnit.class}, false); + return typedTarget.acceptsUnit((com.codename1.home.TraitUnit) adaptedArgs[0]); + } + } + if ("enumValue".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.enumValue(toIntValue(adaptedArgs[0])); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getNominalMaximum".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNominalMaximum(); + } + } + if ("getNominalMinimum".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNominalMinimum(); + } + } + if ("getUnit".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getUnit(); + } + } + if ("getValueKind".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValueKind(); + } + } + if ("hasNominalRange".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hasNominalRange(); + } + } + if ("isReadOnly".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isReadOnly(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke16(com.codename1.home.TraitChangeBatch typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getReadings".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getReadings(); + } + } + if ("getSubscriptionId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSubscriptionId(); + } + } + if ("isEmpty".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEmpty(); + } + } + if ("isInitialDelivery".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isInitialDelivery(); + } + } + if ("isResyncRequired".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isResyncRequired(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke17(com.codename1.home.TraitConstraint typedTarget, String name, Object[] safeArgs) throws Exception { + if ("accepts".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitValue.class}, false); + return typedTarget.accepts((com.codename1.home.TraitValue) adaptedArgs[0]); + } + } + if ("getMaximum".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaximum(); + } + } + if ("getMinimum".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMinimum(); + } + } + if ("getStep".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStep(); + } + } + if ("getTrait".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTrait(); + } + } + if ("getValidOrdinals".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValidOrdinals(); + } + } + if ("hasRange".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hasRange(); + } + } + if ("isReadable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isReadable(); + } + } + if ("isWritable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isWritable(); + } + } + if ("notifiesOnChange".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.notifiesOnChange(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke18(com.codename1.home.TraitReadRequest typedTarget, String name, Object[] safeArgs) throws Exception { + if ("add".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class, com.codename1.home.Trait.class}, false); + return typedTarget.add((com.codename1.home.Accessory) adaptedArgs[0], (com.codename1.home.AccessoryService) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2]); + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.home.Trait.class}, false); + return typedTarget.add((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.home.Trait) adaptedArgs[2]); + } + } + if ("addAll".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.Accessory.class, com.codename1.home.AccessoryService.class}, false); + return typedTarget.addAll((com.codename1.home.Accessory) adaptedArgs[0], (com.codename1.home.AccessoryService) adaptedArgs[1]); + } + } + if ("getAccessoryIds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryIds(); + } + } + if ("getServiceIds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getServiceIds(); + } + } + if ("getTraits".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTraits(); + } + } + if ("isAllowCached".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isAllowCached(); + } + } + if ("isEmpty".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isEmpty(); + } + } + if ("setAllowCached".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.setAllowCached(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("size".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.size(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke19(com.codename1.home.TraitReading typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getError".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getError(); + } + } + if ("getErrorMessage".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getErrorMessage(); + } + } + if ("getServiceId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getServiceId(); + } + } + if ("getTimestampMillis".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTimestampMillis(); + } + } + if ("getTrait".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTrait(); + } + } + if ("getValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValue(); + } + } + if ("hasValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hasValue(); + } + } + if ("isFailed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isFailed(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke20(com.codename1.home.TraitSubscription typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("isActive".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isActive(); + } + } + if ("isPushDelivery".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isPushDelivery(); + } + } + if ("stop".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.stop(); return null; + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke21(com.codename1.home.TraitUnit typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getDimension".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDimension(); + } + } + if ("getWireId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getWireId(); + } + } + if ("isCompatibleWith".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitUnit.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitUnit.class}, false); + return typedTarget.isCompatibleWith((com.codename1.home.TraitUnit) adaptedArgs[0]); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke22(com.codename1.home.TraitValue typedTarget, String name, Object[] safeArgs) throws Exception { + if ("equals".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class}, false); + return typedTarget.equals((java.lang.Object) adaptedArgs[0]); + } + } + if ("getBoolean".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBoolean(); + } + } + if ("getColorTemperatureKelvin".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getColorTemperatureKelvin(); + } + } + if ("getDouble".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitUnit.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitUnit.class}, false); + return typedTarget.getDouble((com.codename1.home.TraitUnit) adaptedArgs[0]); + } + } + if ("getEnumName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEnumName(); + } + } + if ("getEnumOrdinal".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEnumOrdinal(); + } + } + if ("getInt".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getInt(); + } + } + if ("getKind".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getKind(); + } + } + if ("getRawDouble".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRawDouble(); + } + } + if ("getRawPlatformValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRawPlatformValue(); + } + } + if ("getString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getString(); + } + } + if ("getUnit".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getUnit(); + } + } + if ("hasRawPlatformValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hasRawPlatformValue(); + } + } + if ("hashCode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.hashCode(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + if ("withRawPlatformValue".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.withRawPlatformValue(toIntValue(adaptedArgs[0])); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke23(com.codename1.home.TraitWrite typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getAuthorizationData".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAuthorizationData(); + } + } + if ("getServiceId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getServiceId(); + } + } + if ("getTrait".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTrait(); + } + } + if ("getValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValue(); + } + } + if ("setAuthorizationData".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setAuthorizationData((java.lang.String) adaptedArgs[0]); + } + } + if ("toSceneAction".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toSceneAction(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke24(com.codename1.home.TraitWriteResult typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getError".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getError(); + } + } + if ("getErrorMessage".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getErrorMessage(); + } + } + if ("getWrite".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getWrite(); + } + } + if ("isApplied".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isApplied(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke25(com.codename1.home.HomeChangeListener typedTarget, String name, Object[] safeArgs) throws Exception { + if ("traitsChanged".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.TraitChangeBatch.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.TraitChangeBatch.class}, false); + typedTarget.traitsChanged((com.codename1.home.TraitChangeBatch) adaptedArgs[0]); return null; + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke26(com.codename1.home.HomeStructureListener typedTarget, String name, Object[] safeArgs) throws Exception { + if ("structureChanged".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeStructureEvent.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeStructureEvent.class}, false); + typedTarget.structureChanged((com.codename1.home.HomeStructureEvent) adaptedArgs[0]); return null; + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + if (type == com.codename1.home.AccessoryCategory.class) return getStaticField0(name); + if (type == com.codename1.home.AirQualityLevel.class) return getStaticField1(name); + if (type == com.codename1.home.AlarmState.class) return getStaticField2(name); + if (type == com.codename1.home.ChargingState.class) return getStaticField3(name); + if (type == com.codename1.home.DoorState.class) return getStaticField4(name); + if (type == com.codename1.home.FanMode.class) return getStaticField5(name); + if (type == com.codename1.home.HeatingCoolingMode.class) return getStaticField6(name); + if (type == com.codename1.home.HomeAuthorizationStatus.class) return getStaticField7(name); + if (type == com.codename1.home.HomeAvailability.class) return getStaticField8(name); + if (type == com.codename1.home.HomeBackend.class) return getStaticField9(name); + if (type == com.codename1.home.HomeError.class) return getStaticField10(name); + if (type == com.codename1.home.LockState.class) return getStaticField11(name); + if (type == com.codename1.home.PositionState.class) return getStaticField12(name); + if (type == com.codename1.home.SceneType.class) return getStaticField13(name); + if (type == com.codename1.home.ServiceType.class) return getStaticField14(name); + if (type == com.codename1.home.StructureChangeKind.class) return getStaticField15(name); + if (type == com.codename1.home.SubscriptionRequest.class) return getStaticField16(name); + if (type == com.codename1.home.Trait.class) return getStaticField17(name); + if (type == com.codename1.home.TraitUnit.class) return getStaticField18(name); + if (type == com.codename1.home.TraitUnitDimension.class) return getStaticField19(name); + if (type == com.codename1.home.TraitValueKind.class) return getStaticField20(name); + throw unsupportedStaticField(type, name); + } + + private static Object getStaticField0(String name) throws Exception { + if ("AIR_PURIFIER".equals(name)) return com.codename1.home.AccessoryCategory.AIR_PURIFIER; + if ("BRIDGE".equals(name)) return com.codename1.home.AccessoryCategory.BRIDGE; + if ("CAMERA".equals(name)) return com.codename1.home.AccessoryCategory.CAMERA; + if ("DOORBELL".equals(name)) return com.codename1.home.AccessoryCategory.DOORBELL; + if ("FAN".equals(name)) return com.codename1.home.AccessoryCategory.FAN; + if ("GARAGE_DOOR_OPENER".equals(name)) return com.codename1.home.AccessoryCategory.GARAGE_DOOR_OPENER; + if ("LIGHT".equals(name)) return com.codename1.home.AccessoryCategory.LIGHT; + if ("LOCK".equals(name)) return com.codename1.home.AccessoryCategory.LOCK; + if ("OTHER".equals(name)) return com.codename1.home.AccessoryCategory.OTHER; + if ("OUTLET".equals(name)) return com.codename1.home.AccessoryCategory.OUTLET; + if ("SECURITY_SYSTEM".equals(name)) return com.codename1.home.AccessoryCategory.SECURITY_SYSTEM; + if ("SENSOR".equals(name)) return com.codename1.home.AccessoryCategory.SENSOR; + if ("SPEAKER".equals(name)) return com.codename1.home.AccessoryCategory.SPEAKER; + if ("SWITCH".equals(name)) return com.codename1.home.AccessoryCategory.SWITCH; + if ("TELEVISION".equals(name)) return com.codename1.home.AccessoryCategory.TELEVISION; + if ("THERMOSTAT".equals(name)) return com.codename1.home.AccessoryCategory.THERMOSTAT; + if ("WINDOW_COVERING".equals(name)) return com.codename1.home.AccessoryCategory.WINDOW_COVERING; + throw unsupportedStaticField(com.codename1.home.AccessoryCategory.class, name); + } + + private static Object getStaticField1(String name) throws Exception { + if ("EXTREMELY_POOR".equals(name)) return com.codename1.home.AirQualityLevel.EXTREMELY_POOR; + if ("FAIR".equals(name)) return com.codename1.home.AirQualityLevel.FAIR; + if ("GOOD".equals(name)) return com.codename1.home.AirQualityLevel.GOOD; + if ("MODERATE".equals(name)) return com.codename1.home.AirQualityLevel.MODERATE; + if ("POOR".equals(name)) return com.codename1.home.AirQualityLevel.POOR; + if ("UNKNOWN".equals(name)) return com.codename1.home.AirQualityLevel.UNKNOWN; + if ("VERY_POOR".equals(name)) return com.codename1.home.AirQualityLevel.VERY_POOR; + throw unsupportedStaticField(com.codename1.home.AirQualityLevel.class, name); + } + + private static Object getStaticField2(String name) throws Exception { + if ("CRITICAL".equals(name)) return com.codename1.home.AlarmState.CRITICAL; + if ("NORMAL".equals(name)) return com.codename1.home.AlarmState.NORMAL; + if ("UNKNOWN".equals(name)) return com.codename1.home.AlarmState.UNKNOWN; + if ("WARNING".equals(name)) return com.codename1.home.AlarmState.WARNING; + throw unsupportedStaticField(com.codename1.home.AlarmState.class, name); + } + + private static Object getStaticField3(String name) throws Exception { + if ("CHARGING".equals(name)) return com.codename1.home.ChargingState.CHARGING; + if ("FULL".equals(name)) return com.codename1.home.ChargingState.FULL; + if ("NOT_CHARGEABLE".equals(name)) return com.codename1.home.ChargingState.NOT_CHARGEABLE; + if ("NOT_CHARGING".equals(name)) return com.codename1.home.ChargingState.NOT_CHARGING; + if ("UNKNOWN".equals(name)) return com.codename1.home.ChargingState.UNKNOWN; + throw unsupportedStaticField(com.codename1.home.ChargingState.class, name); + } + + private static Object getStaticField4(String name) throws Exception { + if ("CLOSED".equals(name)) return com.codename1.home.DoorState.CLOSED; + if ("CLOSING".equals(name)) return com.codename1.home.DoorState.CLOSING; + if ("OPEN".equals(name)) return com.codename1.home.DoorState.OPEN; + if ("OPENING".equals(name)) return com.codename1.home.DoorState.OPENING; + if ("STOPPED".equals(name)) return com.codename1.home.DoorState.STOPPED; + if ("UNKNOWN".equals(name)) return com.codename1.home.DoorState.UNKNOWN; + throw unsupportedStaticField(com.codename1.home.DoorState.class, name); + } + + private static Object getStaticField5(String name) throws Exception { + if ("AUTO".equals(name)) return com.codename1.home.FanMode.AUTO; + if ("HIGH".equals(name)) return com.codename1.home.FanMode.HIGH; + if ("LOW".equals(name)) return com.codename1.home.FanMode.LOW; + if ("MEDIUM".equals(name)) return com.codename1.home.FanMode.MEDIUM; + if ("OFF".equals(name)) return com.codename1.home.FanMode.OFF; + if ("ON".equals(name)) return com.codename1.home.FanMode.ON; + if ("SMART".equals(name)) return com.codename1.home.FanMode.SMART; + throw unsupportedStaticField(com.codename1.home.FanMode.class, name); + } + + private static Object getStaticField6(String name) throws Exception { + if ("AUTO".equals(name)) return com.codename1.home.HeatingCoolingMode.AUTO; + if ("COOL".equals(name)) return com.codename1.home.HeatingCoolingMode.COOL; + if ("HEAT".equals(name)) return com.codename1.home.HeatingCoolingMode.HEAT; + if ("OFF".equals(name)) return com.codename1.home.HeatingCoolingMode.OFF; + if ("OTHER".equals(name)) return com.codename1.home.HeatingCoolingMode.OTHER; + throw unsupportedStaticField(com.codename1.home.HeatingCoolingMode.class, name); + } + + private static Object getStaticField7(String name) throws Exception { + if ("AUTHORIZED".equals(name)) return com.codename1.home.HomeAuthorizationStatus.AUTHORIZED; + if ("DENIED".equals(name)) return com.codename1.home.HomeAuthorizationStatus.DENIED; + if ("NOT_DETERMINED".equals(name)) return com.codename1.home.HomeAuthorizationStatus.NOT_DETERMINED; + if ("RESTRICTED".equals(name)) return com.codename1.home.HomeAuthorizationStatus.RESTRICTED; + if ("UNKNOWN".equals(name)) return com.codename1.home.HomeAuthorizationStatus.UNKNOWN; + throw unsupportedStaticField(com.codename1.home.HomeAuthorizationStatus.class, name); + } + + private static Object getStaticField8(String name) throws Exception { + if ("AVAILABLE".equals(name)) return com.codename1.home.HomeAvailability.AVAILABLE; + if ("COMMISSIONING_ONLY".equals(name)) return com.codename1.home.HomeAvailability.COMMISSIONING_ONLY; + if ("LOCAL_ONLY".equals(name)) return com.codename1.home.HomeAvailability.LOCAL_ONLY; + if ("NOT_CONFIGURED".equals(name)) return com.codename1.home.HomeAvailability.NOT_CONFIGURED; + if ("NOT_STARTED".equals(name)) return com.codename1.home.HomeAvailability.NOT_STARTED; + if ("NOT_SUPPORTED".equals(name)) return com.codename1.home.HomeAvailability.NOT_SUPPORTED; + if ("PERMISSION_DENIED".equals(name)) return com.codename1.home.HomeAvailability.PERMISSION_DENIED; + if ("PERMISSION_REQUIRED".equals(name)) return com.codename1.home.HomeAvailability.PERMISSION_REQUIRED; + if ("PROVIDER_NOT_INSTALLED".equals(name)) return com.codename1.home.HomeAvailability.PROVIDER_NOT_INSTALLED; + if ("PROVIDER_UPDATE_REQUIRED".equals(name)) return com.codename1.home.HomeAvailability.PROVIDER_UPDATE_REQUIRED; + if ("RESTRICTED".equals(name)) return com.codename1.home.HomeAvailability.RESTRICTED; + if ("SIGN_IN_REQUIRED".equals(name)) return com.codename1.home.HomeAvailability.SIGN_IN_REQUIRED; + throw unsupportedStaticField(com.codename1.home.HomeAvailability.class, name); + } + + private static Object getStaticField9(String name) throws Exception { + if ("GOOGLE_HOME".equals(name)) return com.codename1.home.HomeBackend.GOOGLE_HOME; + if ("HOMEKIT".equals(name)) return com.codename1.home.HomeBackend.HOMEKIT; + if ("LOCAL".equals(name)) return com.codename1.home.HomeBackend.LOCAL; + if ("MATTER_COMMISSIONING_ONLY".equals(name)) return com.codename1.home.HomeBackend.MATTER_COMMISSIONING_ONLY; + if ("NONE".equals(name)) return com.codename1.home.HomeBackend.NONE; + throw unsupportedStaticField(com.codename1.home.HomeBackend.class, name); + } + + private static Object getStaticField10(String name) throws Exception { + if ("ACCESSORY_NOT_FOUND".equals(name)) return com.codename1.home.HomeError.ACCESSORY_NOT_FOUND; + if ("ACCESSORY_UNREACHABLE".equals(name)) return com.codename1.home.HomeError.ACCESSORY_UNREACHABLE; + if ("AUTHORIZATION_REQUIRED".equals(name)) return com.codename1.home.HomeError.AUTHORIZATION_REQUIRED; + if ("BUSY".equals(name)) return com.codename1.home.HomeError.BUSY; + if ("COMMISSIONING_FAILED".equals(name)) return com.codename1.home.HomeError.COMMISSIONING_FAILED; + if ("COMMISSIONING_UNAVAILABLE".equals(name)) return com.codename1.home.HomeError.COMMISSIONING_UNAVAILABLE; + if ("ECOSYSTEM_APP_MISSING".equals(name)) return com.codename1.home.HomeError.ECOSYSTEM_APP_MISSING; + if ("INVALID_ARGUMENT".equals(name)) return com.codename1.home.HomeError.INVALID_ARGUMENT; + if ("INVALID_DATA".equals(name)) return com.codename1.home.HomeError.INVALID_DATA; + if ("NOT_CONFIGURED".equals(name)) return com.codename1.home.HomeError.NOT_CONFIGURED; + if ("NOT_SUPPORTED".equals(name)) return com.codename1.home.HomeError.NOT_SUPPORTED; + if ("PIN_REJECTED".equals(name)) return com.codename1.home.HomeError.PIN_REJECTED; + if ("PIN_REQUIRED".equals(name)) return com.codename1.home.HomeError.PIN_REQUIRED; + if ("PROVIDER_UNAVAILABLE".equals(name)) return com.codename1.home.HomeError.PROVIDER_UNAVAILABLE; + if ("PROVIDER_UPDATE_REQUIRED".equals(name)) return com.codename1.home.HomeError.PROVIDER_UPDATE_REQUIRED; + if ("RATE_LIMITED".equals(name)) return com.codename1.home.HomeError.RATE_LIMITED; + if ("READ_ONLY_TRAIT".equals(name)) return com.codename1.home.HomeError.READ_ONLY_TRAIT; + if ("RESTRICTED".equals(name)) return com.codename1.home.HomeError.RESTRICTED; + if ("SIGN_IN_REQUIRED".equals(name)) return com.codename1.home.HomeError.SIGN_IN_REQUIRED; + if ("TIMEOUT".equals(name)) return com.codename1.home.HomeError.TIMEOUT; + if ("TRAIT_NOT_SUPPORTED".equals(name)) return com.codename1.home.HomeError.TRAIT_NOT_SUPPORTED; + if ("UNAUTHORIZED".equals(name)) return com.codename1.home.HomeError.UNAUTHORIZED; + if ("UNIT_MISMATCH".equals(name)) return com.codename1.home.HomeError.UNIT_MISMATCH; + if ("UNKNOWN".equals(name)) return com.codename1.home.HomeError.UNKNOWN; + if ("USER_CANCELED".equals(name)) return com.codename1.home.HomeError.USER_CANCELED; + if ("VALUE_OUT_OF_RANGE".equals(name)) return com.codename1.home.HomeError.VALUE_OUT_OF_RANGE; + if ("WRITE_ONLY_TRAIT".equals(name)) return com.codename1.home.HomeError.WRITE_ONLY_TRAIT; + throw unsupportedStaticField(com.codename1.home.HomeError.class, name); + } + + private static Object getStaticField11(String name) throws Exception { + if ("JAMMED".equals(name)) return com.codename1.home.LockState.JAMMED; + if ("PARTIALLY_LOCKED".equals(name)) return com.codename1.home.LockState.PARTIALLY_LOCKED; + if ("SECURED".equals(name)) return com.codename1.home.LockState.SECURED; + if ("UNKNOWN".equals(name)) return com.codename1.home.LockState.UNKNOWN; + if ("UNSECURED".equals(name)) return com.codename1.home.LockState.UNSECURED; + throw unsupportedStaticField(com.codename1.home.LockState.class, name); + } + + private static Object getStaticField12(String name) throws Exception { + if ("CLOSING".equals(name)) return com.codename1.home.PositionState.CLOSING; + if ("OPENING".equals(name)) return com.codename1.home.PositionState.OPENING; + if ("STOPPED".equals(name)) return com.codename1.home.PositionState.STOPPED; + if ("UNKNOWN".equals(name)) return com.codename1.home.PositionState.UNKNOWN; + throw unsupportedStaticField(com.codename1.home.PositionState.class, name); + } + + private static Object getStaticField13(String name) throws Exception { + if ("ARRIVAL".equals(name)) return com.codename1.home.SceneType.ARRIVAL; + if ("DEPARTURE".equals(name)) return com.codename1.home.SceneType.DEPARTURE; + if ("SLEEP".equals(name)) return com.codename1.home.SceneType.SLEEP; + if ("TRIGGER_OWNED".equals(name)) return com.codename1.home.SceneType.TRIGGER_OWNED; + if ("USER_DEFINED".equals(name)) return com.codename1.home.SceneType.USER_DEFINED; + if ("WAKE_UP".equals(name)) return com.codename1.home.SceneType.WAKE_UP; + throw unsupportedStaticField(com.codename1.home.SceneType.class, name); + } + + private static Object getStaticField14(String name) throws Exception { + if ("AIR_PURIFIER".equals(name)) return com.codename1.home.ServiceType.AIR_PURIFIER; + if ("AIR_QUALITY_SENSOR".equals(name)) return com.codename1.home.ServiceType.AIR_QUALITY_SENSOR; + if ("BATTERY".equals(name)) return com.codename1.home.ServiceType.BATTERY; + if ("CARBON_MONOXIDE_SENSOR".equals(name)) return com.codename1.home.ServiceType.CARBON_MONOXIDE_SENSOR; + if ("CONTACT_SENSOR".equals(name)) return com.codename1.home.ServiceType.CONTACT_SENSOR; + if ("DOOR".equals(name)) return com.codename1.home.ServiceType.DOOR; + if ("FAN".equals(name)) return com.codename1.home.ServiceType.FAN; + if ("GARAGE_DOOR_OPENER".equals(name)) return com.codename1.home.ServiceType.GARAGE_DOOR_OPENER; + if ("HUMIDITY_SENSOR".equals(name)) return com.codename1.home.ServiceType.HUMIDITY_SENSOR; + if ("LEAK_SENSOR".equals(name)) return com.codename1.home.ServiceType.LEAK_SENSOR; + if ("LIGHTBULB".equals(name)) return com.codename1.home.ServiceType.LIGHTBULB; + if ("LIGHT_SENSOR".equals(name)) return com.codename1.home.ServiceType.LIGHT_SENSOR; + if ("LOCK_MECHANISM".equals(name)) return com.codename1.home.ServiceType.LOCK_MECHANISM; + if ("MOTION_SENSOR".equals(name)) return com.codename1.home.ServiceType.MOTION_SENSOR; + if ("OCCUPANCY_SENSOR".equals(name)) return com.codename1.home.ServiceType.OCCUPANCY_SENSOR; + if ("OTHER".equals(name)) return com.codename1.home.ServiceType.OTHER; + if ("OUTLET".equals(name)) return com.codename1.home.ServiceType.OUTLET; + if ("SMOKE_SENSOR".equals(name)) return com.codename1.home.ServiceType.SMOKE_SENSOR; + if ("SPEAKER".equals(name)) return com.codename1.home.ServiceType.SPEAKER; + if ("SWITCH".equals(name)) return com.codename1.home.ServiceType.SWITCH; + if ("TEMPERATURE_SENSOR".equals(name)) return com.codename1.home.ServiceType.TEMPERATURE_SENSOR; + if ("THERMOSTAT".equals(name)) return com.codename1.home.ServiceType.THERMOSTAT; + if ("WINDOW_COVERING".equals(name)) return com.codename1.home.ServiceType.WINDOW_COVERING; + throw unsupportedStaticField(com.codename1.home.ServiceType.class, name); + } + + private static Object getStaticField15(String name) throws Exception { + if ("ACCESSORY_ADDED".equals(name)) return com.codename1.home.StructureChangeKind.ACCESSORY_ADDED; + if ("ACCESSORY_MOVED".equals(name)) return com.codename1.home.StructureChangeKind.ACCESSORY_MOVED; + if ("ACCESSORY_REMOVED".equals(name)) return com.codename1.home.StructureChangeKind.ACCESSORY_REMOVED; + if ("ACCESSORY_RENAMED".equals(name)) return com.codename1.home.StructureChangeKind.ACCESSORY_RENAMED; + if ("AVAILABILITY_CHANGED".equals(name)) return com.codename1.home.StructureChangeKind.AVAILABILITY_CHANGED; + if ("REACHABILITY_CHANGED".equals(name)) return com.codename1.home.StructureChangeKind.REACHABILITY_CHANGED; + if ("SCENES_CHANGED".equals(name)) return com.codename1.home.StructureChangeKind.SCENES_CHANGED; + if ("STRUCTURES_CHANGED".equals(name)) return com.codename1.home.StructureChangeKind.STRUCTURES_CHANGED; + throw unsupportedStaticField(com.codename1.home.StructureChangeKind.class, name); + } + + private static Object getStaticField16(String name) throws Exception { + if ("DEFAULT_MIN_INTERVAL_MILLIS".equals(name)) return com.codename1.home.SubscriptionRequest.DEFAULT_MIN_INTERVAL_MILLIS; + throw unsupportedStaticField(com.codename1.home.SubscriptionRequest.class, name); + } + + private static Object getStaticField17(String name) throws Exception { + if ("AIR_QUALITY".equals(name)) return com.codename1.home.Trait.AIR_QUALITY; + if ("BATTERY_CHARGING".equals(name)) return com.codename1.home.Trait.BATTERY_CHARGING; + if ("BATTERY_LEVEL".equals(name)) return com.codename1.home.Trait.BATTERY_LEVEL; + if ("BATTERY_LOW".equals(name)) return com.codename1.home.Trait.BATTERY_LOW; + if ("BRIGHTNESS".equals(name)) return com.codename1.home.Trait.BRIGHTNESS; + if ("CO2_LEVEL".equals(name)) return com.codename1.home.Trait.CO2_LEVEL; + if ("COLOR_TEMPERATURE".equals(name)) return com.codename1.home.Trait.COLOR_TEMPERATURE; + if ("CONTACT_DETECTED".equals(name)) return com.codename1.home.Trait.CONTACT_DETECTED; + if ("COVERING_MOTION".equals(name)) return com.codename1.home.Trait.COVERING_MOTION; + if ("COVERING_POSITION".equals(name)) return com.codename1.home.Trait.COVERING_POSITION; + if ("COVERING_TILT".equals(name)) return com.codename1.home.Trait.COVERING_TILT; + if ("CO_DETECTED".equals(name)) return com.codename1.home.Trait.CO_DETECTED; + if ("CO_LEVEL".equals(name)) return com.codename1.home.Trait.CO_LEVEL; + if ("CURRENT_HEATING_COOLING".equals(name)) return com.codename1.home.Trait.CURRENT_HEATING_COOLING; + if ("CURRENT_HUMIDITY".equals(name)) return com.codename1.home.Trait.CURRENT_HUMIDITY; + if ("CURRENT_LIGHT_LEVEL".equals(name)) return com.codename1.home.Trait.CURRENT_LIGHT_LEVEL; + if ("CURRENT_TEMPERATURE".equals(name)) return com.codename1.home.Trait.CURRENT_TEMPERATURE; + if ("DOOR_STATE".equals(name)) return com.codename1.home.Trait.DOOR_STATE; + if ("FAN_MODE".equals(name)) return com.codename1.home.Trait.FAN_MODE; + if ("FAN_SPEED".equals(name)) return com.codename1.home.Trait.FAN_SPEED; + if ("HUE".equals(name)) return com.codename1.home.Trait.HUE; + if ("LEAK_DETECTED".equals(name)) return com.codename1.home.Trait.LEAK_DETECTED; + if ("LOCK_STATE".equals(name)) return com.codename1.home.Trait.LOCK_STATE; + if ("MOTION_DETECTED".equals(name)) return com.codename1.home.Trait.MOTION_DETECTED; + if ("MUTE".equals(name)) return com.codename1.home.Trait.MUTE; + if ("OBSTRUCTION_DETECTED".equals(name)) return com.codename1.home.Trait.OBSTRUCTION_DETECTED; + if ("OCCUPANCY_DETECTED".equals(name)) return com.codename1.home.Trait.OCCUPANCY_DETECTED; + if ("ON_OFF".equals(name)) return com.codename1.home.Trait.ON_OFF; + if ("OUTLET_IN_USE".equals(name)) return com.codename1.home.Trait.OUTLET_IN_USE; + if ("PM10_DENSITY".equals(name)) return com.codename1.home.Trait.PM10_DENSITY; + if ("PM2_5_DENSITY".equals(name)) return com.codename1.home.Trait.PM2_5_DENSITY; + if ("SATURATION".equals(name)) return com.codename1.home.Trait.SATURATION; + if ("SMOKE_DETECTED".equals(name)) return com.codename1.home.Trait.SMOKE_DETECTED; + if ("TARGET_COOLING_TEMPERATURE".equals(name)) return com.codename1.home.Trait.TARGET_COOLING_TEMPERATURE; + if ("TARGET_COVERING_POSITION".equals(name)) return com.codename1.home.Trait.TARGET_COVERING_POSITION; + if ("TARGET_COVERING_TILT".equals(name)) return com.codename1.home.Trait.TARGET_COVERING_TILT; + if ("TARGET_DOOR_STATE".equals(name)) return com.codename1.home.Trait.TARGET_DOOR_STATE; + if ("TARGET_HEATING_COOLING".equals(name)) return com.codename1.home.Trait.TARGET_HEATING_COOLING; + if ("TARGET_HEATING_TEMPERATURE".equals(name)) return com.codename1.home.Trait.TARGET_HEATING_TEMPERATURE; + if ("TARGET_HUMIDITY".equals(name)) return com.codename1.home.Trait.TARGET_HUMIDITY; + if ("TARGET_LOCK_STATE".equals(name)) return com.codename1.home.Trait.TARGET_LOCK_STATE; + if ("TARGET_TEMPERATURE".equals(name)) return com.codename1.home.Trait.TARGET_TEMPERATURE; + if ("VOC_DENSITY".equals(name)) return com.codename1.home.Trait.VOC_DENSITY; + if ("VOLUME".equals(name)) return com.codename1.home.Trait.VOLUME; + throw unsupportedStaticField(com.codename1.home.Trait.class, name); + } + + private static Object getStaticField18(String name) throws Exception { + if ("ARC_DEGREE".equals(name)) return com.codename1.home.TraitUnit.ARC_DEGREE; + if ("CELSIUS".equals(name)) return com.codename1.home.TraitUnit.CELSIUS; + if ("FAHRENHEIT".equals(name)) return com.codename1.home.TraitUnit.FAHRENHEIT; + if ("LUX".equals(name)) return com.codename1.home.TraitUnit.LUX; + if ("MICROGRAM_PER_CUBIC_METER".equals(name)) return com.codename1.home.TraitUnit.MICROGRAM_PER_CUBIC_METER; + if ("MIRED".equals(name)) return com.codename1.home.TraitUnit.MIRED; + if ("NONE".equals(name)) return com.codename1.home.TraitUnit.NONE; + if ("PERCENT".equals(name)) return com.codename1.home.TraitUnit.PERCENT; + if ("PPB".equals(name)) return com.codename1.home.TraitUnit.PPB; + if ("PPM".equals(name)) return com.codename1.home.TraitUnit.PPM; + throw unsupportedStaticField(com.codename1.home.TraitUnit.class, name); + } + + private static Object getStaticField19(String name) throws Exception { + if ("ANGLE".equals(name)) return com.codename1.home.TraitUnitDimension.ANGLE; + if ("COLOR_TEMPERATURE".equals(name)) return com.codename1.home.TraitUnitDimension.COLOR_TEMPERATURE; + if ("CONCENTRATION_MASS".equals(name)) return com.codename1.home.TraitUnitDimension.CONCENTRATION_MASS; + if ("CONCENTRATION_PARTS".equals(name)) return com.codename1.home.TraitUnitDimension.CONCENTRATION_PARTS; + if ("DIMENSIONLESS".equals(name)) return com.codename1.home.TraitUnitDimension.DIMENSIONLESS; + if ("ILLUMINANCE".equals(name)) return com.codename1.home.TraitUnitDimension.ILLUMINANCE; + if ("RATIO".equals(name)) return com.codename1.home.TraitUnitDimension.RATIO; + if ("TEMPERATURE".equals(name)) return com.codename1.home.TraitUnitDimension.TEMPERATURE; + throw unsupportedStaticField(com.codename1.home.TraitUnitDimension.class, name); + } + + private static Object getStaticField20(String name) throws Exception { + if ("BOOLEAN".equals(name)) return com.codename1.home.TraitValueKind.BOOLEAN; + if ("DOUBLE".equals(name)) return com.codename1.home.TraitValueKind.DOUBLE; + if ("ENUM".equals(name)) return com.codename1.home.TraitValueKind.ENUM; + if ("INT".equals(name)) return com.codename1.home.TraitValueKind.INT; + if ("STRING".equals(name)) return com.codename1.home.TraitValueKind.STRING; + throw unsupportedStaticField(com.codename1.home.TraitValueKind.class, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home_commissioning.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home_commissioning.java new file mode 100644 index 00000000000..9b699890a5e --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home_commissioning.java @@ -0,0 +1,665 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_home_commissioning { + private GeneratedAccess_com_codename1_home_commissioning() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("Commissioner".equals(simpleName)) { + return com.codename1.home.commissioning.Commissioner.class; + } + if ("CommissioningRequest".equals(simpleName)) { + return com.codename1.home.commissioning.CommissioningRequest.class; + } + if ("CommissioningResult".equals(simpleName)) { + return com.codename1.home.commissioning.CommissioningResult.class; + } + if ("CommissioningStyle".equals(simpleName)) { + return com.codename1.home.commissioning.CommissioningStyle.class; + } + if ("SetupPayload".equals(simpleName)) { + return com.codename1.home.commissioning.SetupPayload.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.home.commissioning.CommissioningRequest.class) { + if (matches(safeArgs, new Class[0], false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[0], false); + return new com.codename1.home.commissioning.CommissioningRequest(); + } + } + if (type == com.codename1.home.commissioning.CommissioningResult.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class}, false); + return new com.codename1.home.commissioning.CommissioningResult((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue()); + } + } + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.home.commissioning.SetupPayload.class) return invokeStatic0(name, safeArgs); + throw unsupportedStatic(type, name, safeArgs); + } + + private static Object invokeStatic0(String name, Object[] safeArgs) throws Exception { + if ("isValid".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.home.commissioning.SetupPayload.isValid((java.lang.String) adaptedArgs[0]); + } + } + if ("parse".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.home.commissioning.SetupPayload.parse((java.lang.String) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.home.commissioning.SetupPayload.class, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (target instanceof com.codename1.home.commissioning.Commissioner) { + try { + return invoke0((com.codename1.home.commissioning.Commissioner) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.commissioning.CommissioningRequest) { + try { + return invoke1((com.codename1.home.commissioning.CommissioningRequest) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.commissioning.CommissioningResult) { + try { + return invoke2((com.codename1.home.commissioning.CommissioningResult) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.home.commissioning.SetupPayload) { + try { + return invoke3((com.codename1.home.commissioning.SetupPayload) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + private static Object invoke0(com.codename1.home.commissioning.Commissioner typedTarget, String name, Object[] safeArgs) throws Exception { + if ("commission".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.commissioning.CommissioningRequest.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.commissioning.CommissioningRequest.class}, false); + return typedTarget.commission((com.codename1.home.commissioning.CommissioningRequest) adaptedArgs[0]); + } + } + if ("getStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStyle(); + } + } + if ("isSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSupported(); + } + } + if ("openEcosystemApp".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openEcosystemApp(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke1(com.codename1.home.commissioning.CommissioningRequest typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getRawSetupPayload".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRawSetupPayload(); + } + } + if ("getRoomId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRoomId(); + } + } + if ("getSetupPayload".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSetupPayload(); + } + } + if ("getStructureId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructureId(); + } + } + if ("getSuggestedName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSuggestedName(); + } + } + if ("getTimeoutMillis".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTimeoutMillis(); + } + } + if ("isCommissionToThisApp".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isCommissionToThisApp(); + } + } + if ("setCommissionToThisApp".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + return typedTarget.setCommissionToThisApp(((Boolean) adaptedArgs[0]).booleanValue()); + } + } + if ("setRawSetupPayload".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setRawSetupPayload((java.lang.String) adaptedArgs[0]); + } + } + if ("setRoom".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeRoom.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeRoom.class}, false); + return typedTarget.setRoom((com.codename1.home.HomeRoom) adaptedArgs[0]); + } + } + if ("setRoomId".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setRoomId((java.lang.String) adaptedArgs[0]); + } + } + if ("setSetupPayload".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.commissioning.SetupPayload.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.commissioning.SetupPayload.class}, false); + return typedTarget.setSetupPayload((com.codename1.home.commissioning.SetupPayload) adaptedArgs[0]); + } + } + if ("setStructure".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.home.HomeStructure.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.home.HomeStructure.class}, false); + return typedTarget.setStructure((com.codename1.home.HomeStructure) adaptedArgs[0]); + } + } + if ("setStructureId".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setStructureId((java.lang.String) adaptedArgs[0]); + } + } + if ("setSuggestedName".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setSuggestedName((java.lang.String) adaptedArgs[0]); + } + } + if ("setTimeoutMillis".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return typedTarget.setTimeoutMillis(toIntValue(adaptedArgs[0])); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke2(com.codename1.home.commissioning.CommissioningResult typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getAccessoryId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryId(); + } + } + if ("getAccessoryName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAccessoryName(); + } + } + if ("getStructureId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructureId(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + if ("wasCommissionedToThisApp".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.wasCommissionedToThisApp(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke3(com.codename1.home.commissioning.SetupPayload typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getCustomFlow".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCustomFlow(); + } + } + if ("getDiscoveryCapabilities".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDiscoveryCapabilities(); + } + } + if ("getDiscriminator".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDiscriminator(); + } + } + if ("getPasscode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPasscode(); + } + } + if ("getProductId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getProductId(); + } + } + if ("getRaw".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRaw(); + } + } + if ("getVendorId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getVendorId(); + } + } + if ("getVersion".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getVersion(); + } + } + if ("isFromQrCode".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isFromQrCode(); + } + } + if ("isShortDiscriminator".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isShortDiscriminator(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + if (type == com.codename1.home.commissioning.CommissioningStyle.class) return getStaticField0(name); + if (type == com.codename1.home.commissioning.SetupPayload.class) return getStaticField1(name); + throw unsupportedStaticField(type, name); + } + + private static Object getStaticField0(String name) throws Exception { + if ("ECOSYSTEM_APP_HANDOFF".equals(name)) return com.codename1.home.commissioning.CommissioningStyle.ECOSYSTEM_APP_HANDOFF; + if ("NONE".equals(name)) return com.codename1.home.commissioning.CommissioningStyle.NONE; + if ("OS_OWNED_UI".equals(name)) return com.codename1.home.commissioning.CommissioningStyle.OS_OWNED_UI; + throw unsupportedStaticField(com.codename1.home.commissioning.CommissioningStyle.class, name); + } + + private static Object getStaticField1(String name) throws Exception { + if ("DISCOVERY_BLE".equals(name)) return com.codename1.home.commissioning.SetupPayload.DISCOVERY_BLE; + if ("DISCOVERY_ON_NETWORK".equals(name)) return com.codename1.home.commissioning.SetupPayload.DISCOVERY_ON_NETWORK; + if ("DISCOVERY_SOFT_AP".equals(name)) return com.codename1.home.commissioning.SetupPayload.DISCOVERY_SOFT_AP; + throw unsupportedStaticField(com.codename1.home.commissioning.SetupPayload.class, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home_spi.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home_spi.java new file mode 100644 index 00000000000..7a97754b885 --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_home_spi.java @@ -0,0 +1,580 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_home_spi { + private GeneratedAccess_com_codename1_home_spi() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("HomeBridge".equals(simpleName)) { + return com.codename1.home.spi.HomeBridge.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedStatic(type, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (target instanceof com.codename1.home.spi.HomeBridge) { + try { + return invoke0((com.codename1.home.spi.HomeBridge) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + private static Object invoke0(com.codename1.home.spi.HomeBridge typedTarget, String name, Object[] safeArgs) throws Exception { + if ("areIdsPersistent".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.areIdsPersistent(); + } + } + if ("commission".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Integer.class}, false); + typedTarget.commission(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (java.lang.String) adaptedArgs[3], (java.lang.String) adaptedArgs[4], toIntValue(adaptedArgs[5])); return null; + } + } + if ("createScene".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class, int[].class, double[].class, java.lang.String[].class, int[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class, int[].class, double[].class, java.lang.String[].class, int[].class}, false); + typedTarget.createScene(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], (java.lang.String[]) adaptedArgs[3], (java.lang.String[]) adaptedArgs[4], (java.lang.String[]) adaptedArgs[5], (int[]) adaptedArgs[6], (double[]) adaptedArgs[7], (java.lang.String[]) adaptedArgs[8], (int[]) adaptedArgs[9]); return null; + } + } + if ("deleteScene".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class}, false); + typedTarget.deleteScene(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("drainChanges".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.drainChanges(toIntValue(adaptedArgs[0])); return null; + } + } + if ("executeScene".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String.class}, false); + typedTarget.executeScene(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); return null; + } + } + if ("getAccessories".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getAccessories((java.lang.String) adaptedArgs[0]); + } + } + if ("getAuthorizationStatus".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAuthorizationStatus(); + } + } + if ("getAvailability".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getAvailability(); + } + } + if ("getBackendId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBackendId(); + } + } + if ("getCommissioningStyle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getCommissioningStyle(); + } + } + if ("getConfigurationProblems".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getConfigurationProblems(); + } + } + if ("getMaxReadBatchSize".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaxReadBatchSize(); + } + } + if ("getMaxWriteBatchSize".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getMaxWriteBatchSize(); + } + } + if ("getRooms".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getRooms((java.lang.String) adaptedArgs[0]); + } + } + if ("getSceneActions".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + return typedTarget.getSceneActions((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + } + if ("getScenes".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getScenes((java.lang.String) adaptedArgs[0]); + } + } + if ("getServices".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getServices((java.lang.String) adaptedArgs[0]); + } + } + if ("getStructures".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getStructures(); + } + } + if ("getTraits".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + return typedTarget.getTraits((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + } + if ("getZones".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getZones((java.lang.String) adaptedArgs[0]); + } + } + if ("identify".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class}, false); + typedTarget.identify(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1]); return null; + } + } + if ("isPushDelivery".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isPushDelivery(); + } + } + if ("isSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isSupported(); + } + } + if ("openEcosystemApp".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openEcosystemApp(); + } + } + if ("openHomeSettings".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openHomeSettings(); + } + } + if ("openProviderSetup".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.openProviderSetup(); + } + } + if ("readTraits".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class, java.lang.Boolean.class}, false); + typedTarget.readTraits(toIntValue(adaptedArgs[0]), (java.lang.String[]) adaptedArgs[1], (java.lang.String[]) adaptedArgs[2], (java.lang.String[]) adaptedArgs[3], ((Boolean) adaptedArgs[4]).booleanValue()); return null; + } + } + if ("refresh".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.refresh(toIntValue(adaptedArgs[0])); return null; + } + } + if ("requestAuthorization".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.requestAuthorization(toIntValue(adaptedArgs[0])); return null; + } + } + if ("start".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.start(toIntValue(adaptedArgs[0])); return null; + } + } + if ("stop".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.stop(); return null; + } + } + if ("subscribe".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class}, false); + typedTarget.subscribe(toIntValue(adaptedArgs[0]), (java.lang.String) adaptedArgs[1], (java.lang.String[]) adaptedArgs[2], (java.lang.String[]) adaptedArgs[3], (java.lang.String[]) adaptedArgs[4]); return null; + } + } + if ("unsubscribe".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.unsubscribe((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("writeTraits".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class, int[].class, double[].class, java.lang.String[].class, int[].class, java.lang.String[].class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.String[].class, java.lang.String[].class, java.lang.String[].class, int[].class, double[].class, java.lang.String[].class, int[].class, java.lang.String[].class}, false); + typedTarget.writeTraits(toIntValue(adaptedArgs[0]), (java.lang.String[]) adaptedArgs[1], (java.lang.String[]) adaptedArgs[2], (java.lang.String[]) adaptedArgs[3], (int[]) adaptedArgs[4], (double[]) adaptedArgs[5], (java.lang.String[]) adaptedArgs[6], (int[]) adaptedArgs[7], (java.lang.String[]) adaptedArgs[8]); return null; + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + throw unsupportedStaticField(type, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_intents.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_intents.java new file mode 100644 index 00000000000..64145d54a8f --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_intents.java @@ -0,0 +1,1168 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_intents { + private GeneratedAccess_com_codename1_intents() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("AppEntity".equals(simpleName)) { + return com.codename1.intents.AppEntity.class; + } + if ("DynamicIntent".equals(simpleName)) { + return com.codename1.intents.DynamicIntent.class; + } + if ("EntitySelectionHandler".equals(simpleName)) { + return com.codename1.intents.EntitySelectionHandler.class; + } + if ("Exposure".equals(simpleName)) { + return com.codename1.intents.Exposure.class; + } + if ("IntentCompletion".equals(simpleName)) { + return com.codename1.intents.IntentCompletion.class; + } + if ("IntentContext".equals(simpleName)) { + return com.codename1.intents.IntentContext.class; + } + if ("IntentDates".equals(simpleName)) { + return com.codename1.intents.IntentDates.class; + } + if ("IntentDeclaration".equals(simpleName)) { + return com.codename1.intents.IntentDeclaration.class; + } + if ("IntentDispatcher".equals(simpleName)) { + return com.codename1.intents.IntentDispatcher.class; + } + if ("IntentParameterInfo".equals(simpleName)) { + return com.codename1.intents.IntentParameterInfo.class; + } + if ("IntentParameterType".equals(simpleName)) { + return com.codename1.intents.IntentParameterType.class; + } + if ("IntentResult".equals(simpleName)) { + return com.codename1.intents.IntentResult.class; + } + if ("IntentSerializer".equals(simpleName)) { + return com.codename1.intents.IntentSerializer.class; + } + if ("IntentSource".equals(simpleName)) { + return com.codename1.intents.IntentSource.class; + } + if ("Intents".equals(simpleName)) { + return com.codename1.intents.Intents.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.intents.AppEntity.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + return new com.codename1.intents.AppEntity((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + } + if (type == com.codename1.intents.DynamicIntent.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false); + return new com.codename1.intents.DynamicIntent((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + } + if (type == com.codename1.intents.IntentContext.class) { + if (matches(safeArgs, new Class[]{com.codename1.intents.IntentSource.class, java.lang.Boolean.class, java.lang.Long.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.IntentSource.class, java.lang.Boolean.class, java.lang.Long.class}, false); + return new com.codename1.intents.IntentContext((com.codename1.intents.IntentSource) adaptedArgs[0], ((Boolean) adaptedArgs[1]).booleanValue(), ((Number) adaptedArgs[2]).longValue()); + } + } + if (type == com.codename1.intents.IntentDeclaration.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.String.class, java.lang.Integer.class, java.util.List.class, java.util.List.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.Boolean.class, java.lang.String.class, java.lang.Integer.class, java.util.List.class, java.util.List.class, java.util.List.class}, false); + return new com.codename1.intents.IntentDeclaration((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue(), ((Boolean) adaptedArgs[4]).booleanValue(), ((Boolean) adaptedArgs[5]).booleanValue(), (java.lang.String) adaptedArgs[6], toIntValue(adaptedArgs[7]), (java.util.List) adaptedArgs[8], (java.util.List) adaptedArgs[9], (java.util.List) adaptedArgs[10]); + } + } + if (type == com.codename1.intents.IntentParameterInfo.class) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.intents.IntentParameterType.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.intents.IntentParameterType.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.util.List.class}, false); + return new com.codename1.intents.IntentParameterInfo((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.intents.IntentParameterType) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue(), (java.lang.String) adaptedArgs[4], (java.lang.String) adaptedArgs[5], (java.util.List) adaptedArgs[6]); + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.intents.IntentParameterType.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.util.List.class, java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, com.codename1.intents.IntentParameterType.class, java.lang.Boolean.class, java.lang.String.class, java.lang.String.class, java.util.List.class, java.lang.Integer.class}, false); + return new com.codename1.intents.IntentParameterInfo((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (com.codename1.intents.IntentParameterType) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue(), (java.lang.String) adaptedArgs[4], (java.lang.String) adaptedArgs[5], (java.util.List) adaptedArgs[6], toIntValue(adaptedArgs[7])); + } + } + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.intents.IntentDates.class) return invokeStatic0(name, safeArgs); + if (type == com.codename1.intents.IntentResult.class) return invokeStatic1(name, safeArgs); + if (type == com.codename1.intents.IntentSerializer.class) return invokeStatic2(name, safeArgs); + if (type == com.codename1.intents.Intents.class) return invokeStatic3(name, safeArgs); + throw unsupportedStatic(type, name, safeArgs); + } + + private static Object invokeStatic0(String name, Object[] safeArgs) throws Exception { + if ("parse".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class}, false); + return com.codename1.intents.IntentDates.parse((java.lang.Object) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.intents.IntentDates.class, name, safeArgs); + } + + private static Object invokeStatic1(String name, Object[] safeArgs) throws Exception { + if ("entity".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.AppEntity.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.AppEntity.class}, false); + return com.codename1.intents.IntentResult.entity((com.codename1.intents.AppEntity) adaptedArgs[0]); + } + } + if ("failed".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.intents.IntentResult.failed((java.lang.String) adaptedArgs[0]); + } + } + if ("ok".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.IntentResult.ok(); + } + } + if ("opens".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.intents.IntentResult.opens((java.lang.String) adaptedArgs[0]); + } + } + if ("spoken".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.intents.IntentResult.spoken((java.lang.String) adaptedArgs[0]); + } + } + if ("value".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Object.class}, false); + return com.codename1.intents.IntentResult.value((java.lang.Object) adaptedArgs[0]); + } + } + throw unsupportedStatic(com.codename1.intents.IntentResult.class, name, safeArgs); + } + + private static Object invokeStatic2(String name, Object[] safeArgs) throws Exception { + if ("mergeParams".equals(name)) { + if (matches(safeArgs, new Class[]{java.util.Map.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.Map.class, java.lang.String.class}, false); + return com.codename1.intents.IntentSerializer.mergeParams((java.util.Map) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + } + if ("parsePayload".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.intents.IntentSerializer.parsePayload((java.lang.String) adaptedArgs[0]); + } + } + if ("serializeDeclarations".equals(name)) { + if (matches(safeArgs, new Class[]{java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.List.class}, false); + return com.codename1.intents.IntentSerializer.serializeDeclarations((java.util.List) adaptedArgs[0]); + } + } + if ("serializeEntities".equals(name)) { + if (matches(safeArgs, new Class[]{java.util.List.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.List.class, java.util.Map.class}, false); + return com.codename1.intents.IntentSerializer.serializeEntities((java.util.List) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); + } + if (matches(safeArgs, new Class[]{java.util.List.class, java.util.Map.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.List.class, java.util.Map.class, java.lang.Boolean.class}, false); + return com.codename1.intents.IntentSerializer.serializeEntities((java.util.List) adaptedArgs[0], (java.util.Map) adaptedArgs[1], ((Boolean) adaptedArgs[2]).booleanValue()); + } + } + if ("serializeEntityRef".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + return com.codename1.intents.IntentSerializer.serializeEntityRef((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + } + if ("serializeParams".equals(name)) { + if (matches(safeArgs, new Class[]{java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.Map.class}, false); + return com.codename1.intents.IntentSerializer.serializeParams((java.util.Map) adaptedArgs[0]); + } + } + if ("serializeResult".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.IntentResult.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.IntentResult.class, java.util.Map.class}, false); + return com.codename1.intents.IntentSerializer.serializeResult((com.codename1.intents.IntentResult) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); + } + } + throw unsupportedStatic(com.codename1.intents.IntentSerializer.class, name, safeArgs); + } + + private static Object invokeStatic3(String name, Object[] safeArgs) throws Exception { + if ("areIntentsSupported".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.areIntentsSupported(); + } + } + if ("asTools".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.asTools(); + } + } + if ("clearIndex".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + com.codename1.intents.Intents.clearIndex((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("dispatchInvocation".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class, com.codename1.intents.IntentSource.class, java.lang.Boolean.class, com.codename1.intents.IntentCompletion.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class, com.codename1.intents.IntentSource.class, java.lang.Boolean.class, com.codename1.intents.IntentCompletion.class}, false); + com.codename1.intents.Intents.dispatchInvocation((java.lang.String) adaptedArgs[0], (java.util.Map) adaptedArgs[1], (com.codename1.intents.IntentSource) adaptedArgs[2], ((Boolean) adaptedArgs[3]).booleanValue(), (com.codename1.intents.IntentCompletion) adaptedArgs[4]); return null; + } + } + if ("dispatchSpotlightSelection".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + com.codename1.intents.Intents.dispatchSpotlightSelection((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("dispatchUserActivity".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false); + return com.codename1.intents.Intents.dispatchUserActivity((java.lang.String) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); + } + } + if ("donate".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false); + com.codename1.intents.Intents.donate((java.lang.String) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); return null; + } + } + if ("getDeclaration".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.intents.Intents.getDeclaration((java.lang.String) adaptedArgs[0]); + } + } + if ("getDeclarations".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.getDeclarations(); + } + } + if ("getDefaultTimeout".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.getDefaultTimeout(); + } + } + if ("getDynamicIntent".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return com.codename1.intents.Intents.getDynamicIntent((java.lang.String) adaptedArgs[0]); + } + } + if ("index".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.AppEntity.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.AppEntity.class}, false); + com.codename1.intents.Intents.index((com.codename1.intents.AppEntity) adaptedArgs[0]); return null; + } + if (matches(safeArgs, new Class[]{java.util.List.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.List.class}, false); + com.codename1.intents.Intents.index((java.util.List) adaptedArgs[0]); return null; + } + } + if ("invoke".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false); + return com.codename1.intents.Intents.invoke((java.lang.String) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); + } + } + if ("isHeadlessExecutionSupported".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.isHeadlessExecutionSupported(); + } + } + if ("isIndexingSupported".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.isIndexingSupported(); + } + } + if ("isVoiceInvocationSupported".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.intents.Intents.isVoiceInvocationSupported(); + } + } + if ("publishPendingDeclarations".equals(name)) { + if (safeArgs.length == 0) { + com.codename1.intents.Intents.publishPendingDeclarations(); return null; + } + } + if ("queryEntities".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false); + return com.codename1.intents.Intents.queryEntities((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + } + if ("registerDynamicIntent".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.DynamicIntent.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.DynamicIntent.class}, false); + com.codename1.intents.Intents.registerDynamicIntent((com.codename1.intents.DynamicIntent) adaptedArgs[0]); return null; + } + } + if ("removeFromIndex".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + com.codename1.intents.Intents.removeFromIndex((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); return null; + } + } + if ("setBridge".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.spi.IntentBridge.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.spi.IntentBridge.class}, false); + com.codename1.intents.Intents.setBridge((com.codename1.intents.spi.IntentBridge) adaptedArgs[0]); return null; + } + } + if ("setDefaultTimeout".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + com.codename1.intents.Intents.setDefaultTimeout(toIntValue(adaptedArgs[0])); return null; + } + } + if ("setDispatcher".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.IntentDispatcher.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.IntentDispatcher.class}, false); + com.codename1.intents.Intents.setDispatcher((com.codename1.intents.IntentDispatcher) adaptedArgs[0]); return null; + } + } + if ("setSelectionHandler".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.EntitySelectionHandler.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.EntitySelectionHandler.class}, false); + com.codename1.intents.Intents.setSelectionHandler((com.codename1.intents.EntitySelectionHandler) adaptedArgs[0]); return null; + } + } + throw unsupportedStatic(com.codename1.intents.Intents.class, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (target instanceof com.codename1.intents.AppEntity) { + try { + return invoke0((com.codename1.intents.AppEntity) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.DynamicIntent) { + try { + return invoke1((com.codename1.intents.DynamicIntent) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.IntentContext) { + try { + return invoke2((com.codename1.intents.IntentContext) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.IntentDeclaration) { + try { + return invoke3((com.codename1.intents.IntentDeclaration) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.IntentParameterInfo) { + try { + return invoke4((com.codename1.intents.IntentParameterInfo) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.IntentResult) { + try { + return invoke5((com.codename1.intents.IntentResult) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.EntitySelectionHandler) { + try { + return invoke6((com.codename1.intents.EntitySelectionHandler) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.IntentCompletion) { + try { + return invoke7((com.codename1.intents.IntentCompletion) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (target instanceof com.codename1.intents.IntentDispatcher) { + try { + return invoke8((com.codename1.intents.IntentDispatcher) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + private static Object invoke0(com.codename1.intents.AppEntity typedTarget, String name, Object[] safeArgs) throws Exception { + if ("addKeywords".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String[].class}, true)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String[].class}, true); + java.lang.String[] varArgs = new java.lang.String[adaptedArgs.length - 0]; + for (int i = 0; i < adaptedArgs.length; i++) { + varArgs[i - 0] = (java.lang.String) adaptedArgs[i]; + } + return typedTarget.addKeywords(varArgs); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getImage".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getImage(); + } + } + if ("getKeywords".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getKeywords(); + } + } + if ("getSubtitle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSubtitle(); + } + } + if ("getTitle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTitle(); + } + } + if ("getType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getType(); + } + } + if ("setImage".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.EncodedImage.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.EncodedImage.class}, false); + return typedTarget.setImage((com.codename1.ui.EncodedImage) adaptedArgs[0]); + } + } + if ("setSubtitle".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setSubtitle((java.lang.String) adaptedArgs[0]); + } + } + if ("setTitle".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.setTitle((java.lang.String) adaptedArgs[0]); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke1(com.codename1.intents.DynamicIntent typedTarget, String name, Object[] safeArgs) throws Exception { + if ("bind".equals(name)) { + if (matches(safeArgs, new Class[]{java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.Map.class}, false); + return typedTarget.bind((java.util.Map) adaptedArgs[0]); + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Object.class}, false); + return typedTarget.bind((java.lang.String) adaptedArgs[0], (java.lang.Object) adaptedArgs[1]); + } + } + if ("getBaseIntentId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBaseIntentId(); + } + } + if ("getBoundParameters".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getBoundParameters(); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getTitle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTitle(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke2(com.codename1.intents.IntentContext typedTarget, String name, Object[] safeArgs) throws Exception { + if ("cancel".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.cancel(); return null; + } + } + if ("getDeadline".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDeadline(); + } + } + if ("getRemainingTime".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getRemainingTime(); + } + } + if ("getSource".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSource(); + } + } + if ("isCancelled".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isCancelled(); + } + } + if ("isHeadless".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHeadless(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke3(com.codename1.intents.IntentDeclaration typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getDescription".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDescription(); + } + } + if ("getExposure".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getExposure(); + } + } + if ("getId".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getId(); + } + } + if ("getOpensRoute".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOpensRoute(); + } + } + if ("getParameter".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.getParameter((java.lang.String) adaptedArgs[0]); + } + } + if ("getParameters".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getParameters(); + } + } + if ("getPhrases".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getPhrases(); + } + } + if ("getTimeoutSeconds".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTimeoutSeconds(); + } + } + if ("getTitle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTitle(); + } + } + if ("isDestructive".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDestructive(); + } + } + if ("isDiscoverable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDiscoverable(); + } + } + if ("isExposedTo".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.Exposure.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.Exposure.class}, false); + return typedTarget.isExposedTo((com.codename1.intents.Exposure) adaptedArgs[0]); + } + } + if ("isHeadless".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHeadless(); + } + } + if ("runsHeadless".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.runsHeadless(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke4(com.codename1.intents.IntentParameterInfo typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getDefaultValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDefaultValue(); + } + } + if ("getEntityType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEntityType(); + } + } + if ("getName".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getName(); + } + } + if ("getNumericWidthBits".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getNumericWidthBits(); + } + } + if ("getOptions".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOptions(); + } + } + if ("getTitle".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTitle(); + } + } + if ("getType".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getType(); + } + } + if ("isRequired".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isRequired(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke5(com.codename1.intents.IntentResult typedTarget, String name, Object[] safeArgs) throws Exception { + if ("getDialog".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getDialog(); + } + } + if ("getEntity".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getEntity(); + } + } + if ("getErrorMessage".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getErrorMessage(); + } + } + if ("getOpenUrl".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getOpenUrl(); + } + } + if ("getSnippet".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getSnippet(); + } + } + if ("getValue".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getValue(); + } + } + if ("isFailed".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isFailed(); + } + } + if ("toString".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.toString(); + } + } + if ("withDialog".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.withDialog((java.lang.String) adaptedArgs[0]); + } + } + if ("withOpenUrl".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.withOpenUrl((java.lang.String) adaptedArgs[0]); + } + } + if ("withSnippet".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.surfaces.SurfaceNode.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.surfaces.SurfaceNode.class}, false); + return typedTarget.withSnippet((com.codename1.surfaces.SurfaceNode) adaptedArgs[0]); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke6(com.codename1.intents.EntitySelectionHandler typedTarget, String name, Object[] safeArgs) throws Exception { + if ("onEntitySelected".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.AppEntity.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.AppEntity.class}, false); + typedTarget.onEntitySelected((com.codename1.intents.AppEntity) adaptedArgs[0]); return null; + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke7(com.codename1.intents.IntentCompletion typedTarget, String name, Object[] safeArgs) throws Exception { + if ("onIntentResult".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.intents.IntentResult.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.intents.IntentResult.class}, false); + typedTarget.onIntentResult((com.codename1.intents.IntentResult) adaptedArgs[0]); return null; + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke8(com.codename1.intents.IntentDispatcher typedTarget, String name, Object[] safeArgs) throws Exception { + if ("describe".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.describe(); + } + } + if ("invoke".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class, com.codename1.intents.IntentContext.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class, com.codename1.intents.IntentContext.class}, false); + return typedTarget.invoke((java.lang.String) adaptedArgs[0], (java.util.Map) adaptedArgs[1], (com.codename1.intents.IntentContext) adaptedArgs[2]); + } + } + if ("queryEntities".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.lang.String.class}, false); + return typedTarget.queryEntities((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + if (type == com.codename1.intents.Exposure.class) return getStaticField0(name); + if (type == com.codename1.intents.IntentParameterType.class) return getStaticField1(name); + if (type == com.codename1.intents.IntentSource.class) return getStaticField2(name); + throw unsupportedStaticField(type, name); + } + + private static Object getStaticField0(String name) throws Exception { + if ("ASSISTANT".equals(name)) return com.codename1.intents.Exposure.ASSISTANT; + if ("MODEL".equals(name)) return com.codename1.intents.Exposure.MODEL; + throw unsupportedStaticField(com.codename1.intents.Exposure.class, name); + } + + private static Object getStaticField1(String name) throws Exception { + if ("BOOLEAN".equals(name)) return com.codename1.intents.IntentParameterType.BOOLEAN; + if ("DATE".equals(name)) return com.codename1.intents.IntentParameterType.DATE; + if ("ENTITY".equals(name)) return com.codename1.intents.IntentParameterType.ENTITY; + if ("INTEGER".equals(name)) return com.codename1.intents.IntentParameterType.INTEGER; + if ("NUMBER".equals(name)) return com.codename1.intents.IntentParameterType.NUMBER; + if ("STRING".equals(name)) return com.codename1.intents.IntentParameterType.STRING; + throw unsupportedStaticField(com.codename1.intents.IntentParameterType.class, name); + } + + private static Object getStaticField2(String name) throws Exception { + if ("IN_APP".equals(name)) return com.codename1.intents.IntentSource.IN_APP; + if ("MODEL".equals(name)) return com.codename1.intents.IntentSource.MODEL; + if ("SHORTCUT".equals(name)) return com.codename1.intents.IntentSource.SHORTCUT; + if ("SPOTLIGHT".equals(name)) return com.codename1.intents.IntentSource.SPOTLIGHT; + if ("UNKNOWN".equals(name)) return com.codename1.intents.IntentSource.UNKNOWN; + if ("VOICE".equals(name)) return com.codename1.intents.IntentSource.VOICE; + if ("WIDGET".equals(name)) return com.codename1.intents.IntentSource.WIDGET; + throw unsupportedStaticField(com.codename1.intents.IntentSource.class, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_intents_spi.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_intents_spi.java new file mode 100644 index 00000000000..2e8a929336f --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_intents_spi.java @@ -0,0 +1,446 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_intents_spi { + private GeneratedAccess_com_codename1_intents_spi() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("IntentBridge".equals(simpleName)) { + return com.codename1.intents.spi.IntentBridge.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedStatic(type, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (target instanceof com.codename1.intents.spi.IntentBridge) { + try { + return invoke0((com.codename1.intents.spi.IntentBridge) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + private static Object invoke0(com.codename1.intents.spi.IntentBridge typedTarget, String name, Object[] safeArgs) throws Exception { + if ("areIntentsSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.areIntentsSupported(); + } + } + if ("clearIndex".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.clearIndex((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("completeInvocation".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, java.util.Map.class}, false); + typedTarget.completeInvocation((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.util.Map) adaptedArgs[2]); return null; + } + } + if ("donate".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + typedTarget.donate((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); return null; + } + } + if ("index".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.util.Map.class}, false); + typedTarget.index((java.lang.String) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); return null; + } + } + if ("isHeadlessExecutionSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHeadlessExecutionSupported(); + } + } + if ("isIndexingSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isIndexingSupported(); + } + } + if ("isVoiceInvocationSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isVoiceInvocationSupported(); + } + } + if ("registerIntents".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.registerIntents((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("removeFromIndex".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.removeFromIndex((java.lang.String) adaptedArgs[0]); return null; + } + } + if ("requestForeground".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.requestForeground(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + throw unsupportedStaticField(type, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security.java index db3d7b1425c..97249086235 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security.java @@ -121,6 +121,9 @@ private static Class findClassChunk0(String simpleName) { if ("Signature".equals(simpleName)) { return com.codename1.security.Signature.class; } + if ("TapjackingPolicy".equals(simpleName)) { + return com.codename1.security.TapjackingPolicy.class; + } return null; } public static Object construct(Class type, Object[] args) throws Exception { @@ -244,6 +247,12 @@ private static Object invokeStatic2(String name, Object[] safeArgs) throws Excep } private static Object invokeStatic3(String name, Object[] safeArgs) throws Exception { + if ("addTapjackingListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + com.codename1.security.DeviceIntegrity.addTapjackingListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } if ("confirmAttestation".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -260,6 +269,11 @@ private static Object invokeStatic3(String name, Object[] safeArgs) throws Excep return com.codename1.security.DeviceIntegrity.getEnabledAccessibilityServices(); } } + if ("getTapjackingPolicy".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.security.DeviceIntegrity.getTapjackingPolicy(); + } + } if ("hasUntrustedAccessibilityService".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String[].class}, true)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String[].class}, true); @@ -280,6 +294,22 @@ private static Object invokeStatic3(String name, Object[] safeArgs) throws Excep return com.codename1.security.DeviceIntegrity.isDeviceCompromised(); } } + if ("isHideOverlayWindowsSupported".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.security.DeviceIntegrity.isHideOverlayWindowsSupported(); + } + } + if ("isScreenObscured".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.security.DeviceIntegrity.isScreenObscured(); + } + } + if ("removeTapjackingListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + com.codename1.security.DeviceIntegrity.removeTapjackingListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } if ("requestIntegrityToken".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -291,12 +321,24 @@ private static Object invokeStatic3(String name, Object[] safeArgs) throws Excep com.codename1.security.DeviceIntegrity.resetAttestation(); return null; } } + if ("setHideOverlayWindows".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + com.codename1.security.DeviceIntegrity.setHideOverlayWindows(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } if ("setSecureScreen".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); com.codename1.security.DeviceIntegrity.setSecureScreen(((Boolean) adaptedArgs[0]).booleanValue()); return null; } } + if ("setTapjackingProtection".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.security.TapjackingPolicy.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.security.TapjackingPolicy.class}, false); + com.codename1.security.DeviceIntegrity.setTapjackingProtection((com.codename1.security.TapjackingPolicy) adaptedArgs[0]); return null; + } + } throw unsupportedStatic(com.codename1.security.DeviceIntegrity.class, name, safeArgs); } @@ -722,6 +764,13 @@ public static Object invoke(Object target, String name, Object[] args) throws Ex unsupported = ex; } } + if (target instanceof com.codename1.security.TapjackingPolicy) { + try { + return invoke12((com.codename1.security.TapjackingPolicy) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } if (unsupported != null) { throw unsupported; } @@ -1100,6 +1149,12 @@ private static Object invoke10(com.codename1.security.KeyPair typedTarget, Strin } private static Object invoke11(com.codename1.security.SecureStorage typedTarget, String name, Object[] safeArgs) throws Exception { + if ("entryState".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.entryState((java.lang.String) adaptedArgs[0]); + } + } if ("get".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -1130,6 +1185,12 @@ private static Object invoke11(com.codename1.security.SecureStorage typedTarget, return typedTarget.set((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1], (java.lang.String) adaptedArgs[2]); } } + if ("setIfAbsent".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + return typedTarget.setIfAbsent((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); + } + } if ("setKeychainAccessGroup".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -1139,6 +1200,21 @@ private static Object invoke11(com.codename1.security.SecureStorage typedTarget, throw unsupportedInstance(typedTarget, name, safeArgs); } + private static Object invoke12(com.codename1.security.TapjackingPolicy typedTarget, String name, Object[] safeArgs) throws Exception { + if ("blocks".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class, java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class, java.lang.Boolean.class}, false); + return typedTarget.blocks(((Boolean) adaptedArgs[0]).booleanValue(), ((Boolean) adaptedArgs[1]).booleanValue()); + } + } + if ("isDetecting".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDetecting(); + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + public static Object getStaticField(Class type, String name) throws Exception { if (type == com.codename1.security.BiometricError.class) return getStaticField0(name); if (type == com.codename1.security.BiometricType.class) return getStaticField1(name); @@ -1146,7 +1222,9 @@ public static Object getStaticField(Class type, String name) throws Exception if (type == com.codename1.security.Hash.class) return getStaticField3(name); if (type == com.codename1.security.Jwt.class) return getStaticField4(name); if (type == com.codename1.security.PublicKey.class) return getStaticField5(name); - if (type == com.codename1.security.Signature.class) return getStaticField6(name); + if (type == com.codename1.security.SecureStorage.class) return getStaticField6(name); + if (type == com.codename1.security.Signature.class) return getStaticField7(name); + if (type == com.codename1.security.TapjackingPolicy.class) return getStaticField8(name); throw unsupportedStaticField(type, name); } @@ -1214,6 +1292,13 @@ private static Object getStaticField5(String name) throws Exception { } private static Object getStaticField6(String name) throws Exception { + if ("ENTRY_ABSENT".equals(name)) return com.codename1.security.SecureStorage.ENTRY_ABSENT; + if ("ENTRY_PRESENT".equals(name)) return com.codename1.security.SecureStorage.ENTRY_PRESENT; + if ("ENTRY_UNKNOWN".equals(name)) return com.codename1.security.SecureStorage.ENTRY_UNKNOWN; + throw unsupportedStaticField(com.codename1.security.SecureStorage.class, name); + } + + private static Object getStaticField7(String name) throws Exception { if ("SHA256_WITH_ECDSA".equals(name)) return com.codename1.security.Signature.SHA256_WITH_ECDSA; if ("SHA256_WITH_RSA".equals(name)) return com.codename1.security.Signature.SHA256_WITH_RSA; if ("SHA384_WITH_ECDSA".equals(name)) return com.codename1.security.Signature.SHA384_WITH_ECDSA; @@ -1223,6 +1308,14 @@ private static Object getStaticField6(String name) throws Exception { throw unsupportedStaticField(com.codename1.security.Signature.class, name); } + private static Object getStaticField8(String name) throws Exception { + if ("BLOCK".equals(name)) return com.codename1.security.TapjackingPolicy.BLOCK; + if ("OFF".equals(name)) return com.codename1.security.TapjackingPolicy.OFF; + if ("REPORT".equals(name)) return com.codename1.security.TapjackingPolicy.REPORT; + if ("STRICT".equals(name)) return com.codename1.security.TapjackingPolicy.STRICT; + throw unsupportedStaticField(com.codename1.security.TapjackingPolicy.class, name); + } + public static Object getField(Object target, String name) throws Exception { throw unsupportedField(target, name); } diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_hardening.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_hardening.java new file mode 100644 index 00000000000..b5c220de968 --- /dev/null +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_hardening.java @@ -0,0 +1,394 @@ +/* + * 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 bsh.cn1.gen; + +import bsh.cn1.CN1AccessException; + +public final class GeneratedAccess_com_codename1_security_hardening { + private GeneratedAccess_com_codename1_security_hardening() { + } + + public static Class findClass(String name) { + if (name == null) { + return null; + } + int dot = name.lastIndexOf('.'); + int dollar = name.lastIndexOf('$'); + int sep = dot > dollar ? dot : dollar; + if (sep < 0 || sep == name.length() - 1) { + return null; + } + return findClassBySimpleName(name.substring(sep + 1)); + } + + public static Class findClassBySimpleName(String simpleName) { + Class found0 = findClassChunk0(simpleName); + if (found0 != null) { + return found0; + } + return null; + } + + + private static Class findClassChunk0(String simpleName) { + if ("Hardening".equals(simpleName)) { + return com.codename1.security.hardening.Hardening.class; + } + return null; + } + public static Object construct(Class type, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + throw unsupportedConstruct(type, safeArgs); + } + + public static Object invokeStatic(Class type, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + if (type == com.codename1.security.hardening.Hardening.class) return invokeStatic0(name, safeArgs); + throw unsupportedStatic(type, name, safeArgs); + } + + private static Object invokeStatic0(String name, Object[] safeArgs) throws Exception { + if ("getLevel".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.security.hardening.Hardening.getLevel(); + } + } + if ("getMappingId".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.security.hardening.Hardening.getMappingId(); + } + } + if ("isHardened".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.security.hardening.Hardening.isHardened(); + } + } + throw unsupportedStatic(com.codename1.security.hardening.Hardening.class, name, safeArgs); + } + + public static Object invoke(Object target, String name, Object[] args) throws Exception { + Object[] safeArgs = safeArgs(args); + CN1AccessException unsupported = null; + if (unsupported != null) { + throw unsupported; + } + throw unsupportedInstance(target, name, safeArgs); + } + + public static Object getStaticField(Class type, String name) throws Exception { + throw unsupportedStaticField(type, name); + } + + public static Object getField(Object target, String name) throws Exception { + throw unsupportedField(target, name); + } + + public static void setStaticField(Class type, String name, Object value) throws Exception { + throw unsupportedStaticFieldWrite(type, name, value); + } + + public static void setField(Object target, String name, Object value) throws Exception { + throw unsupportedFieldWrite(target, name, value); + } + + private static Object[] safeArgs(Object[] args) { + return args == null ? new Object[0] : args; + } + + private static Object[] adaptArgs(Object[] args, Class[] paramTypes, boolean varArgs) { + if (args == null || args.length == 0) { + return args == null ? new Object[0] : args; + } + Object[] adapted = args.clone(); + if (!varArgs) { + for (int i = 0; i < Math.min(adapted.length, paramTypes.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + return adapted; + } + if (paramTypes.length == 0) { + return adapted; + } + int fixedCount = paramTypes.length - 1; + for (int i = 0; i < Math.min(fixedCount, adapted.length); i++) { + adapted[i] = adaptValue(adapted[i], paramTypes[i]); + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < adapted.length; i++) { + adapted[i] = adaptValue(adapted[i], componentType); + } + return adapted; + } + + private static boolean isSamInterface(Class type) { + if (type == com.codename1.util.OnComplete.class) { + return true; + } + if (type == com.codename1.util.SuccessCallback.class) { + return true; + } + if (type == com.codename1.util.FailureCallback.class) { + return true; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return true; + } + if (type == java.lang.Runnable.class) { + return true; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return true; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return true; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return true; + } + return false; + } + + private static Object adaptLambdaValue(final bsh.cn1.CN1LambdaSupport.LambdaValue lambda, Class type) { + if (type == com.codename1.util.OnComplete.class) { + return new com.codename1.util.OnComplete() { + public void completed(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.SuccessCallback.class) { + return new com.codename1.util.SuccessCallback() { + public void onSucess(java.lang.Object arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.util.FailureCallback.class) { + return new com.codename1.util.FailureCallback() { + public void onError(java.lang.Object arg0, java.lang.Throwable arg1, int arg2, java.lang.String arg3) { + try { + lambda.invoke(new Object[]{arg0, arg1, arg2, arg3}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.ActionListener.class) { + return new com.codename1.ui.events.ActionListener() { + public void actionPerformed(com.codename1.ui.events.ActionEvent arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == java.lang.Runnable.class) { + return new java.lang.Runnable() { + public void run() { + try { + lambda.invoke(new Object[0]); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.DataChangedListener.class) { + return new com.codename1.ui.events.DataChangedListener() { + public void dataChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.ui.events.SelectionListener.class) { + return new com.codename1.ui.events.SelectionListener() { + public void selectionChanged(int arg0, int arg1) { + try { + lambda.invoke(new Object[]{arg0, arg1}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + if (type == com.codename1.printing.PrintResultListener.class) { + return new com.codename1.printing.PrintResultListener() { + public void onResult(com.codename1.printing.PrintResult arg0) { + try { + lambda.invoke(new Object[]{arg0}); + } catch (bsh.EvalError ex) { + throw new RuntimeException(ex); + } + } + }; + } + return lambda; + } + + private static Object adaptValue(Object value, Class type) { + if (!(value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue)) { + return value; + } + // Direct fit when LambdaValue already implements the target SAM + // (Runnable, Function, Comparator, ...). + if (type.isInstance(value)) { + return value; + } + return adaptLambdaValue((bsh.cn1.CN1LambdaSupport.LambdaValue) value, type); + } + + private static int toIntValue(Object value) { + if (value instanceof Number) return ((Number) value).intValue(); + if (value instanceof Character) return (int) ((Character) value).charValue(); + throw new ClassCastException("Cannot coerce " + + (value == null ? "null" : value.getClass().getName()) + " to int"); + } + + private static boolean matches(Object[] args, Class[] paramTypes, boolean varArgs) { + if (!varArgs) { + if (args.length != paramTypes.length) { + return false; + } + for (int i = 0; i < paramTypes.length; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + return true; + } + if (paramTypes.length == 0) { + return true; + } + int fixedCount = paramTypes.length - 1; + if (args.length < fixedCount) { + return false; + } + for (int i = 0; i < fixedCount; i++) { + if (!matchesType(args[i], paramTypes[i])) { + return false; + } + } + Class componentType = paramTypes[paramTypes.length - 1].getComponentType(); + for (int i = fixedCount; i < args.length; i++) { + if (!matchesType(args[i], componentType)) { + return false; + } + } + return true; + } + + private static boolean matchesType(Object value, Class type) { + if (type == Object.class) { + return true; + } + if (value == null) { + return !type.isPrimitive(); + } + if (type.isArray()) { + return type.isInstance(value); + } + if ("boolean".equals(type.getName()) || type == Boolean.class) { + return value instanceof Boolean; + } + if ("char".equals(type.getName()) || type == Character.class) { + return value instanceof Character; + } + if ("byte".equals(type.getName()) || type == Byte.class || "short".equals(type.getName()) || type == Short.class + || "int".equals(type.getName()) || type == Integer.class || "long".equals(type.getName()) || type == Long.class + || "float".equals(type.getName()) || type == Float.class || "double".equals(type.getName()) || type == Double.class) { + // Java widens char to int implicitly, so accept Character + // for any int-or-larger numeric slot. + return value instanceof Number || value instanceof Character; + } + if (value instanceof bsh.cn1.CN1LambdaSupport.LambdaValue) { + // LambdaValue implements common SAMs directly (Runnable, + // Function, Predicate, Comparator, ...). Also accept any + // CN1 SAM the listener-bridge knows how to wrap. + return type.isInstance(value) || isSamInterface(type); + } + return type.isInstance(value); + } + + private static CN1AccessException unsupportedConstruct(Class type, Object[] args) { + return new CN1AccessException("Generated constructor dispatch not implemented for " + type.getName() + describeArgs(args)); + } + + private static CN1AccessException unsupportedStatic(Class type, String name, Object[] args) { + return new CN1AccessException("Generated static dispatch not implemented for " + type.getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedInstance(Object target, String name, Object[] args) { + return new CN1AccessException("Generated instance dispatch not implemented for " + target.getClass().getName() + "." + name + describeArgs(args)); + } + + private static CN1AccessException unsupportedStaticField(Class type, String name) { + return new CN1AccessException("Generated static field access not implemented for " + type.getName() + "." + name); + } + + private static CN1AccessException unsupportedField(Object target, String name) { + return new CN1AccessException("Generated field access not implemented for " + target.getClass().getName() + "." + name); + } + + private static CN1AccessException unsupportedStaticFieldWrite(Class type, String name, Object value) { + return new CN1AccessException("Generated static field write not implemented for " + type.getName() + "." + name + " value=" + describeValue(value)); + } + + private static CN1AccessException unsupportedFieldWrite(Object target, String name, Object value) { + return new CN1AccessException("Generated field write not implemented for " + target.getClass().getName() + "." + name + " value=" + describeValue(value)); + } + + private static String describeArgs(Object[] args) { + if (args == null || args.length == 0) { + return "()"; + } + StringBuilder sb = new StringBuilder("("); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(describeValue(args[i])); + } + sb.append(')'); + return sb.toString(); + } + + private static String describeValue(Object value) { + return value == null ? "null" : value.getClass().getName(); + } +} diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_shield.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_shield.java index b6dcf961c6d..744c2b3b7e0 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_shield.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_security_shield.java @@ -756,6 +756,7 @@ private static Object getStaticField5(String name) throws Exception { if ("JAILBREAK".equals(name)) return com.codename1.security.shield.ShieldSignal.JAILBREAK; if ("REPACKAGED".equals(name)) return com.codename1.security.shield.ShieldSignal.REPACKAGED; if ("ROOT".equals(name)) return com.codename1.security.shield.ShieldSignal.ROOT; + if ("TAPJACK".equals(name)) return com.codename1.security.shield.ShieldSignal.TAPJACK; throw unsupportedStaticField(com.codename1.security.shield.ShieldSignal.class, name); } diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_surfaces.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_surfaces.java index 44fa1d8ba18..6f0261e1232 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_surfaces.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_surfaces.java @@ -323,6 +323,12 @@ private static Object invokeStatic3(String name, Object[] safeArgs) throws Excep return com.codename1.surfaces.SurfaceSerializer.serializeLiveActivity((com.codename1.surfaces.LiveActivityDescriptor) adaptedArgs[0], (java.util.Map) adaptedArgs[1], (java.util.Map) adaptedArgs[2]); } } + if ("serializeNodeToMap".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.surfaces.SurfaceNode.class, java.util.Map.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.surfaces.SurfaceNode.class, java.util.Map.class}, false); + return com.codename1.surfaces.SurfaceSerializer.serializeNodeToMap((com.codename1.surfaces.SurfaceNode) adaptedArgs[0], (java.util.Map) adaptedArgs[1]); + } + } if ("serializeState".equals(name)) { if (matches(safeArgs, new Class[]{java.util.Map.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.Map.class}, false); diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui.java index fedfd2b97e8..4dab6087e1c 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui.java @@ -13139,6 +13139,12 @@ private static Object invoke4(com.codename1.ui.CodeEditor typedTarget, String na typedTarget.addPointerReleasedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } + if ("addProtectedEditListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addProtectedEditListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } if ("addPullToRefresh".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Runnable.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Runnable.class}, false); @@ -14437,6 +14443,12 @@ private static Object invoke4(com.codename1.ui.CodeEditor typedTarget, String na typedTarget.removePointerReleasedListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } + if ("removeProtectedEditListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeProtectedEditListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } if ("removeReadyListener".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); @@ -14591,6 +14603,12 @@ private static Object invoke4(com.codename1.ui.CodeEditor typedTarget, String na typedTarget.setCursor(toIntValue(adaptedArgs[0])); return null; } } + if ("setCursorPosition".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + typedTarget.setCursorPosition(toIntValue(adaptedArgs[0])); return null; + } + } if ("setDiagnostics".equals(name)) { if (matches(safeArgs, new Class[]{java.util.List.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.util.List.class}, false); @@ -14871,6 +14889,12 @@ private static Object invoke4(com.codename1.ui.CodeEditor typedTarget, String na return typedTarget.setPropertyValue((java.lang.String) adaptedArgs[0], (java.lang.Object) adaptedArgs[1]); } } + if ("setProtectedRegionMarkers".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + typedTarget.setProtectedRegionMarkers((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); return null; + } + } if ("setPullToRefresh".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Runnable.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Runnable.class}, false); @@ -73790,6 +73814,12 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name typedTarget.addPostureListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } + if ("addTapjackingListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.addTapjackingListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } if ("addVirtualKeyboardListener".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); @@ -74030,6 +74060,24 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.createThread((java.lang.Runnable) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); } } + if ("databaseIdentityForEngineFile".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.databaseIdentityForEngineFile((java.lang.String) adaptedArgs[0]); + } + } + if ("databaseManagedKeyIdentity".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.databaseManagedKeyIdentity((java.lang.String) adaptedArgs[0]); + } + } + if ("databaseRegistryIdentity".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.databaseRegistryIdentity((java.lang.String) adaptedArgs[0]); + } + } if ("delete".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -74336,6 +74384,11 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.getHealth(); } } + if ("getHomeBridge".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getHomeBridge(); + } + } if ("getImageIO".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getImageIO(); @@ -74355,6 +74408,11 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.getInitialWindowSizeHintPercent(); } } + if ("getIntentBridge".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getIntentBridge(); + } + } if ("getInvisibleAreaUnderVKB".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getInvisibleAreaUnderVKB(); @@ -74545,6 +74603,11 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.getSurfaceBridge(); } } + if ("getTapjackingPolicy".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.getTapjackingPolicy(); + } + } if ("getUdid".equals(name)) { if (safeArgs.length == 0) { return typedTarget.getUdid(); @@ -74709,6 +74772,11 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.isBidiAlgorithm(); } } + if ("isBlobQueryParameterSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isBlobQueryParameterSupported(); + } + } if ("isBoldTextEnabled".equals(name)) { if (safeArgs.length == 0) { return typedTarget.isBoldTextEnabled(); @@ -74760,6 +74828,22 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.isDatabaseCustomPathSupported(); } } + if ("isDatabaseEncryptionSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDatabaseEncryptionSupported(); + } + } + if ("isDatabaseFileEncrypted".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.isDatabaseFileEncrypted((java.lang.String) adaptedArgs[0]); + } + } + if ("isDatabaseManagedKeyHardwareBacked".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isDatabaseManagedKeyHardwareBacked(); + } + } if ("isDebuggableBuild".equals(name)) { if (safeArgs.length == 0) { return typedTarget.isDebuggableBuild(); @@ -74841,6 +74925,11 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.isGrayscaleEnabled(); } } + if ("isHideOverlayWindowsSupported".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isHideOverlayWindowsSupported(); + } + } if ("isHighContrastEnabled".equals(name)) { if (safeArgs.length == 0) { return typedTarget.isHighContrastEnabled(); @@ -74988,11 +75077,21 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name return typedTarget.isReduceTransparencyEnabled(); } } + if ("isRelativeAttachmentNameResolvable".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isRelativeAttachmentNameResolvable(); + } + } if ("isRightMouseButtonDown".equals(name)) { if (safeArgs.length == 0) { return typedTarget.isRightMouseButtonDown(); } } + if ("isScreenObscured".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isScreenObscured(); + } + } if ("isScreenReaderEnabled".equals(name)) { if (safeArgs.length == 0) { return typedTarget.isScreenReaderEnabled(); @@ -75133,6 +75232,12 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name typedTarget.onEditingComplete((com.codename1.ui.Component) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); return null; } } + if ("openDatabaseConnections".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.openDatabaseConnections((java.lang.String) adaptedArgs[0]); + } + } if ("openFileChooser".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class, java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class, java.lang.String.class}, false); @@ -75166,6 +75271,16 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); return typedTarget.openOrCreate((java.lang.String) adaptedArgs[0]); } + if (matches(safeArgs, new Class[]{java.lang.String.class, com.codename1.db.DatabaseConfig.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, com.codename1.db.DatabaseConfig.class}, false); + return typedTarget.openOrCreate((java.lang.String) adaptedArgs[0], (com.codename1.db.DatabaseConfig) adaptedArgs[1]); + } + } + if ("openOrCreateForRekey".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.openOrCreateForRekey((java.lang.String) adaptedArgs[0]); + } } if ("platformUsesInputMode".equals(name)) { if (safeArgs.length == 0) { @@ -75289,6 +75404,12 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name typedTarget.removePostureListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; } } + if ("removeTapjackingListener".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); + typedTarget.removeTapjackingListener((com.codename1.ui.events.ActionListener) adaptedArgs[0]); return null; + } + } if ("removeVirtualKeyboardListener".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.events.ActionListener.class}, false); @@ -75461,6 +75582,12 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name typedTarget.setFramerate(toIntValue(adaptedArgs[0])); return null; } } + if ("setHideOverlayWindows".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); + typedTarget.setHideOverlayWindows(((Boolean) adaptedArgs[0]).booleanValue()); return null; + } + } if ("setInitialWindowSizeHintPercent".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.ui.geom.Dimension.class}, false); @@ -75551,6 +75678,12 @@ private static Object invoke37(com.codename1.ui.Display typedTarget, String name typedTarget.setShowVirtualKeyboard(((Boolean) adaptedArgs[0]).booleanValue()); return null; } } + if ("setTapjackingProtection".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.security.TapjackingPolicy.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.security.TapjackingPolicy.class}, false); + typedTarget.setTapjackingProtection((com.codename1.security.TapjackingPolicy) adaptedArgs[0]); return null; + } + } if ("setThirdSoftButton".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Boolean.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Boolean.class}, false); @@ -90559,12 +90692,27 @@ private static Object invoke66(com.codename1.ui.EditField typedTarget, String na return typedTarget.containsOrOwns(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); } } + if ("copySelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.copySelection(); return null; + } + } if ("createStyleAnimation".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false); return typedTarget.createStyleAnimation((java.lang.String) adaptedArgs[0], toIntValue(adaptedArgs[1])); } } + if ("cutSelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.cutSelection(); return null; + } + } + if ("deleteBackward".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.deleteBackward(); return null; + } + } if ("deleteSurroundingText".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); @@ -91452,6 +91600,11 @@ private static Object invoke66(com.codename1.ui.EditField typedTarget, String na typedTarget.paintShadows((com.codename1.ui.Graphics) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2])); return null; } } + if ("pasteClipboard".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.pasteClipboard(); return null; + } + } if ("performRedo".equals(name)) { if (safeArgs.length == 0) { typedTarget.performRedo(); return null; diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui_editor.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui_editor.java index d7e7785051d..888fec5b64d 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui_editor.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_ui_editor.java @@ -675,12 +675,27 @@ private static Object invoke1(com.codename1.ui.editor.CodeView typedTarget, Stri return typedTarget.containsOrOwns(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); } } + if ("copySelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.copySelection(); return null; + } + } if ("createStyleAnimation".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false); return typedTarget.createStyleAnimation((java.lang.String) adaptedArgs[0], toIntValue(adaptedArgs[1])); } } + if ("cutSelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.cutSelection(); return null; + } + } + if ("deleteBackward".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.deleteBackward(); return null; + } + } if ("deleteSurroundingText".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); @@ -1532,6 +1547,11 @@ private static Object invoke1(com.codename1.ui.editor.CodeView typedTarget, Stri typedTarget.paintShadows((com.codename1.ui.Graphics) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2])); return null; } } + if ("pasteClipboard".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.pasteClipboard(); return null; + } + } if ("performRedo".equals(name)) { if (safeArgs.length == 0) { typedTarget.performRedo(); return null; @@ -2082,6 +2102,12 @@ private static Object invoke1(com.codename1.ui.editor.CodeView typedTarget, Stri return typedTarget.setPropertyValue((java.lang.String) adaptedArgs[0], (java.lang.Object) adaptedArgs[1]); } } + if ("setProtectedRegionMarkers".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class}, false); + typedTarget.setProtectedRegionMarkers((java.lang.String) adaptedArgs[0], (java.lang.String) adaptedArgs[1]); return null; + } + } if ("setPullToRefresh".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Runnable.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Runnable.class}, false); @@ -2508,12 +2534,27 @@ private static Object invoke3(com.codename1.ui.editor.RichView typedTarget, Stri return typedTarget.containsOrOwns(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); } } + if ("copySelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.copySelection(); return null; + } + } if ("createStyleAnimation".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false); return typedTarget.createStyleAnimation((java.lang.String) adaptedArgs[0], toIntValue(adaptedArgs[1])); } } + if ("cutSelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.cutSelection(); return null; + } + } + if ("deleteBackward".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.deleteBackward(); return null; + } + } if ("deleteSurroundingText".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); @@ -3408,6 +3449,11 @@ private static Object invoke3(com.codename1.ui.editor.RichView typedTarget, Stri typedTarget.paintShadows((com.codename1.ui.Graphics) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2])); return null; } } + if ("pasteClipboard".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.pasteClipboard(); return null; + } + } if ("performRedo".equals(name)) { if (safeArgs.length == 0) { typedTarget.performRedo(); return null; @@ -4478,12 +4524,27 @@ private static Object invoke5(com.codename1.ui.editor.EditorView typedTarget, St return typedTarget.containsOrOwns(toIntValue(adaptedArgs[0]), toIntValue(adaptedArgs[1])); } } + if ("copySelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.copySelection(); return null; + } + } if ("createStyleAnimation".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Integer.class}, false); return typedTarget.createStyleAnimation((java.lang.String) adaptedArgs[0], toIntValue(adaptedArgs[1])); } } + if ("cutSelection".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.cutSelection(); return null; + } + } + if ("deleteBackward".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.deleteBackward(); return null; + } + } if ("deleteSurroundingText".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class, java.lang.Integer.class}, false); @@ -5330,6 +5391,11 @@ private static Object invoke5(com.codename1.ui.editor.EditorView typedTarget, St typedTarget.paintShadows((com.codename1.ui.Graphics) adaptedArgs[0], toIntValue(adaptedArgs[1]), toIntValue(adaptedArgs[2])); return null; } } + if ("pasteClipboard".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.pasteClipboard(); return null; + } + } if ("performRedo".equals(name)) { if (safeArgs.length == 0) { typedTarget.performRedo(); return null; diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_util.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_util.java index acf718001d3..db52a07e0d8 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_util.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_util.java @@ -1528,6 +1528,16 @@ private static Object invoke9(com.codename1.util.EasyThread typedTarget, String typedTarget.addErrorListener((com.codename1.util.EasyThread.ErrorListener) adaptedArgs[0]); return null; } } + if ("awaitFinished".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.awaitFinished(); return null; + } + } + if ("isFinished".equals(name)) { + if (safeArgs.length == 0) { + return typedTarget.isFinished(); + } + } if ("isThisIt".equals(name)) { if (safeArgs.length == 0) { return typedTarget.isThisIt(); @@ -1538,6 +1548,11 @@ private static Object invoke9(com.codename1.util.EasyThread typedTarget, String typedTarget.kill(); return null; } } + if ("killWhenIdle".equals(name)) { + if (safeArgs.length == 0) { + typedTarget.killWhenIdle(); return null; + } + } if ("removeErrorListener".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.util.EasyThread.ErrorListener.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.util.EasyThread.ErrorListener.class}, false); diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_wearable.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_wearable.java index 4de75de0b11..15a09249c0c 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_wearable.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_com_codename1_wearable.java @@ -55,6 +55,9 @@ private static Class findClassChunk0(String simpleName) { if ("WearableConnection".equals(simpleName)) { return com.codename1.wearable.WearableConnection.class; } + if ("DroppedDeliveryHandler".equals(simpleName)) { + return com.codename1.wearable.WearableConnection.DroppedDeliveryHandler.class; + } if ("WearableDataListener".equals(simpleName)) { return com.codename1.wearable.WearableDataListener.class; } @@ -133,18 +136,38 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Runnable.class}, false); return com.codename1.wearable.WearableConnection.deliverDataChangedTracked((java.lang.String) adaptedArgs[0], (byte[]) adaptedArgs[1], (java.lang.Runnable) adaptedArgs[2]); } + if (matches(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Runnable.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Runnable.class, java.lang.Runnable.class}, false); + return com.codename1.wearable.WearableConnection.deliverDataChangedTracked((java.lang.String) adaptedArgs[0], (byte[]) adaptedArgs[1], (java.lang.Runnable) adaptedArgs[2], (java.lang.Runnable) adaptedArgs[3]); + } } if ("deliverDataRemoved".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); com.codename1.wearable.WearableConnection.deliverDataRemoved((java.lang.String) adaptedArgs[0]); return null; } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class}, false); + com.codename1.wearable.WearableConnection.deliverDataRemoved((java.lang.String) adaptedArgs[0], (java.lang.Runnable) adaptedArgs[1]); return null; + } + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class, java.lang.Runnable.class}, false); + com.codename1.wearable.WearableConnection.deliverDataRemoved((java.lang.String) adaptedArgs[0], (java.lang.Runnable) adaptedArgs[1], (java.lang.Runnable) adaptedArgs[2]); return null; + } } if ("deliverMessage".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Integer.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Integer.class}, false); com.codename1.wearable.WearableConnection.deliverMessage((java.lang.String) adaptedArgs[0], (byte[]) adaptedArgs[1], toIntValue(adaptedArgs[2])); return null; } + if (matches(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Integer.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Integer.class, java.lang.Runnable.class}, false); + com.codename1.wearable.WearableConnection.deliverMessage((java.lang.String) adaptedArgs[0], (byte[]) adaptedArgs[1], toIntValue(adaptedArgs[2]), (java.lang.Runnable) adaptedArgs[3]); return null; + } + if (matches(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Integer.class, java.lang.Runnable.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, byte[].class, java.lang.Integer.class, java.lang.Runnable.class, java.lang.Runnable.class}, false); + com.codename1.wearable.WearableConnection.deliverMessage((java.lang.String) adaptedArgs[0], (byte[]) adaptedArgs[1], toIntValue(adaptedArgs[2]), (java.lang.Runnable) adaptedArgs[3], (java.lang.Runnable) adaptedArgs[4]); return null; + } } if ("deliverReply".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Integer.class, byte[].class, java.lang.String.class}, false)) { @@ -168,6 +191,22 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep return com.codename1.wearable.WearableConnection.getDataPaths(); } } + if ("hasDataListener".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.wearable.WearableConnection.hasDataListener(); + } + } + if ("hasMessageListener".equals(name)) { + if (safeArgs.length == 0) { + return com.codename1.wearable.WearableConnection.hasMessageListener(); + } + } + if ("hasPendingReply".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.Integer.class}, false); + return com.codename1.wearable.WearableConnection.hasPendingReply(toIntValue(adaptedArgs[0])); + } + } if ("isCompanionAppInstalled".equals(name)) { if (safeArgs.length == 0) { return com.codename1.wearable.WearableConnection.isCompanionAppInstalled(); @@ -223,6 +262,23 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep com.codename1.wearable.WearableConnection.removeStateListener((com.codename1.wearable.WearableStateListener) adaptedArgs[0]); return null; } } + if ("requestReplayAfterDrain".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class}, false); + com.codename1.wearable.WearableConnection.requestReplayAfterDrain((java.lang.String) adaptedArgs[0], (java.lang.Runnable) adaptedArgs[1]); return null; + } + } + if ("resetForReload".equals(name)) { + if (safeArgs.length == 0) { + com.codename1.wearable.WearableConnection.resetForReload(); return null; + } + } + if ("runWhenListenerRegisters".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.Runnable.class}, false); + com.codename1.wearable.WearableConnection.runWhenListenerRegisters((java.lang.String) adaptedArgs[0], (java.lang.Runnable) adaptedArgs[1]); return null; + } + } if ("sendMessage".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.wearable.WearableMessage.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.wearable.WearableMessage.class}, false); @@ -233,6 +289,12 @@ private static Object invokeStatic0(String name, Object[] safeArgs) throws Excep com.codename1.wearable.WearableConnection.sendMessage((com.codename1.wearable.WearableMessage) adaptedArgs[0], (com.codename1.wearable.WearableReplyHandler) adaptedArgs[1]); return null; } } + if ("setDroppedDeliveryHandler".equals(name)) { + if (matches(safeArgs, new Class[]{com.codename1.wearable.WearableConnection.DroppedDeliveryHandler.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.wearable.WearableConnection.DroppedDeliveryHandler.class}, false); + com.codename1.wearable.WearableConnection.setDroppedDeliveryHandler((com.codename1.wearable.WearableConnection.DroppedDeliveryHandler) adaptedArgs[0]); return null; + } + } if ("transferFile".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, byte[].class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class, java.lang.String.class, byte[].class}, false); @@ -269,30 +331,37 @@ public static Object invoke(Object target, String name, Object[] args) throws Ex unsupported = ex; } } + if (target instanceof com.codename1.wearable.WearableConnection.DroppedDeliveryHandler) { + try { + return invoke2((com.codename1.wearable.WearableConnection.DroppedDeliveryHandler) target, name, safeArgs); + } catch (CN1AccessException ex) { + unsupported = ex; + } + } if (target instanceof com.codename1.wearable.WearableDataListener) { try { - return invoke2((com.codename1.wearable.WearableDataListener) target, name, safeArgs); + return invoke3((com.codename1.wearable.WearableDataListener) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.wearable.WearableMessageListener) { try { - return invoke3((com.codename1.wearable.WearableMessageListener) target, name, safeArgs); + return invoke4((com.codename1.wearable.WearableMessageListener) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.wearable.WearableReplyHandler) { try { - return invoke4((com.codename1.wearable.WearableReplyHandler) target, name, safeArgs); + return invoke5((com.codename1.wearable.WearableReplyHandler) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } } if (target instanceof com.codename1.wearable.WearableStateListener) { try { - return invoke5((com.codename1.wearable.WearableStateListener) target, name, safeArgs); + return invoke6((com.codename1.wearable.WearableStateListener) target, name, safeArgs); } catch (CN1AccessException ex) { unsupported = ex; } @@ -419,7 +488,17 @@ private static Object invoke1(com.codename1.wearable.WearableNode typedTarget, S throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke2(com.codename1.wearable.WearableDataListener typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke2(com.codename1.wearable.WearableConnection.DroppedDeliveryHandler typedTarget, String name, Object[] safeArgs) throws Exception { + if ("deliveryDropped".equals(name)) { + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + typedTarget.deliveryDropped((java.lang.String) adaptedArgs[0]); return null; + } + } + throw unsupportedInstance(typedTarget, name, safeArgs); + } + + private static Object invoke3(com.codename1.wearable.WearableDataListener typedTarget, String name, Object[] safeArgs) throws Exception { if ("dataChanged".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.wearable.WearableMessage.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.wearable.WearableMessage.class}, false); @@ -435,7 +514,7 @@ private static Object invoke2(com.codename1.wearable.WearableDataListener typedT throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke3(com.codename1.wearable.WearableMessageListener typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke4(com.codename1.wearable.WearableMessageListener typedTarget, String name, Object[] safeArgs) throws Exception { if ("messageReceived".equals(name)) { if (matches(safeArgs, new Class[]{com.codename1.wearable.WearableMessage.class, java.lang.Boolean.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{com.codename1.wearable.WearableMessage.class, java.lang.Boolean.class}, false); @@ -445,7 +524,7 @@ private static Object invoke3(com.codename1.wearable.WearableMessageListener typ throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke4(com.codename1.wearable.WearableReplyHandler typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke5(com.codename1.wearable.WearableReplyHandler typedTarget, String name, Object[] safeArgs) throws Exception { if ("replyFailed".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); @@ -461,7 +540,7 @@ private static Object invoke4(com.codename1.wearable.WearableReplyHandler typedT throw unsupportedInstance(typedTarget, name, safeArgs); } - private static Object invoke5(com.codename1.wearable.WearableStateListener typedTarget, String name, Object[] safeArgs) throws Exception { + private static Object invoke6(com.codename1.wearable.WearableStateListener typedTarget, String name, Object[] safeArgs) throws Exception { if ("connectionStateChanged".equals(name)) { if (safeArgs.length == 0) { typedTarget.connectionStateChanged(); return null; diff --git a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_java_io.java b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_java_io.java index 57a729dedf9..6c3406ee5bc 100644 --- a/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_java_io.java +++ b/scripts/cn1playground/common/src/main/java/bsh/cn1/gen/GeneratedAccess_java_io.java @@ -479,6 +479,10 @@ private static Object invoke1(java.io.ByteArrayOutputStream typedTarget, String if (safeArgs.length == 0) { return typedTarget.toString(); } + if (matches(safeArgs, new Class[]{java.lang.String.class}, false)) { + Object[] adaptedArgs = adaptArgs(safeArgs, new Class[]{java.lang.String.class}, false); + return typedTarget.toString((java.lang.String) adaptedArgs[0]); + } } if ("write".equals(name)) { if (matches(safeArgs, new Class[]{java.lang.Integer.class}, false)) { diff --git a/scripts/cn1playground/common/src/main/java/com/codenameone/playground/CN1Playground.java b/scripts/cn1playground/common/src/main/java/com/codenameone/playground/CN1Playground.java index f36d522986d..fe635fae6ba 100644 --- a/scripts/cn1playground/common/src/main/java/com/codenameone/playground/CN1Playground.java +++ b/scripts/cn1playground/common/src/main/java/com/codenameone/playground/CN1Playground.java @@ -55,7 +55,12 @@ import java.util.ArrayList; import java.util.Hashtable; import java.util.List; +import com.codename1.annotations.buildhints.*; +@Android(themeMode = AndroidThemeMode.MODERN) +@Build(nativeTheme = NativeThemeMode.MODERN) +@Ios(newStorageLocation = true, themeMode = IosThemeMode.MODERN) +@IosPrivacy(cameraUsageDescription = "Some functionality of the application requires your camera") public class CN1Playground extends Lifecycle { private static final boolean DEFAULT_DARK_MODE = true; private static final String THEME_ROLE = "playgroundThemeRole"; diff --git a/scripts/fidelity-app/common/codenameone_settings.properties b/scripts/fidelity-app/common/codenameone_settings.properties index d3f6f26ad8e..18061a29110 100644 --- a/scripts/fidelity-app/common/codenameone_settings.properties +++ b/scripts/fidelity-app/common/codenameone_settings.properties @@ -3,11 +3,7 @@ codename1.android.keystore=/Users/shai/dev/cn4/CodenameOne/scripts/fidelity-app/android/../common/androidCerts/KeyChain.ks codename1.android.keystoreAlias=androidKey codename1.android.keystorePassword=password -codename1.arg.android.gradleDep=implementation 'com.google.android.material\:material\:1.12.0' -codename1.arg.android.useAndroidX=true codename1.arg.ios.metal=true -codename1.arg.ios.newStorageLocation=true -codename1.arg.ios.uiscene=true codename1.arg.java.version=17 codename1.cssTheme=true codename1.displayName=Fidelity diff --git a/scripts/fidelity-app/common/src/main/java/com/codenameone/fidelity/FidelityApp.java b/scripts/fidelity-app/common/src/main/java/com/codenameone/fidelity/FidelityApp.java index 739b0c98598..53f5f3ac844 100644 --- a/scripts/fidelity-app/common/src/main/java/com/codenameone/fidelity/FidelityApp.java +++ b/scripts/fidelity-app/common/src/main/java/com/codenameone/fidelity/FidelityApp.java @@ -1,11 +1,11 @@ /* * Copyright (c) 2012, 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 + * published by the Free Software Foundation. Codename One designates this * particular file as subject to the "Classpath" exception as provided - * by Codename One in the LICENSE file that accompanied this code. + * 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 @@ -23,6 +23,7 @@ package com.codenameone.fidelity; import com.codename1.system.Lifecycle; +import com.codename1.annotations.buildhints.*; /** * Entry point for the native-theme fidelity test app. It is not an interactive @@ -31,6 +32,8 @@ * screenshots to the host over the CN1SS WebSocket, then prints * CN1SS:SUITE:FINISHED and exits. */ +@Android(gradleDep = {"implementation 'com.google.android.material:material:1.12.0'"}, useAndroidX = true) +@Ios(newStorageLocation = true, uiscene = true) public class FidelityApp extends Lifecycle { @Override public void runApp() { diff --git a/scripts/gamebuilder/common/codenameone_settings.properties b/scripts/gamebuilder/common/codenameone_settings.properties index f38391dcdd3..40645679eea 100644 --- a/scripts/gamebuilder/common/codenameone_settings.properties +++ b/scripts/gamebuilder/common/codenameone_settings.properties @@ -7,11 +7,5 @@ codename1.secondaryTitle=Game Builder codename1.icon=icon.png codename1.cssTheme=true codename1.arg.java.version=17 -codename1.arg.nativeTheme=modern -codename1.arg.ios.themeMode=modern -codename1.arg.and.themeMode=modern -codename1.arg.desktop.width=1280 -codename1.arg.desktop.height=800 -# native window chrome: OS title bar + native macOS/Windows menu bar (File/Edit/View…) -codename1.arg.desktop.titleBar=native +# native window chrome: OS title bar + native macOS/Windows menu bar (File/Edit/View…) codename1.kotlin=false diff --git a/scripts/gamebuilder/common/pom.xml b/scripts/gamebuilder/common/pom.xml index a07d212aad8..d22977aef1d 100644 --- a/scripts/gamebuilder/common/pom.xml +++ b/scripts/gamebuilder/common/pom.xml @@ -115,6 +115,7 @@ bytecode-compliance css + process-annotations diff --git a/scripts/gamebuilder/common/src/main/java/com/codename1/gamebuilder/GameBuilder.java b/scripts/gamebuilder/common/src/main/java/com/codename1/gamebuilder/GameBuilder.java index 7dcfcd8c72e..315f0637232 100644 --- a/scripts/gamebuilder/common/src/main/java/com/codename1/gamebuilder/GameBuilder.java +++ b/scripts/gamebuilder/common/src/main/java/com/codename1/gamebuilder/GameBuilder.java @@ -75,6 +75,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import com.codename1.annotations.buildhints.*; /// The Codename One game builder: a visual level / map editor for the /// `com.codename1.gaming` engine, adapted from the "GameForge" design. @@ -82,6 +83,10 @@ /// Every control is wired; the live preview plays in-place (toggle, no navigation) so /// there is never a dead-end screen. Behavior and structure are covered by tests /// (EditorControllerTest, GameBuilderStructureHarness). +@Android(themeMode = AndroidThemeMode.MODERN) +@Build(nativeTheme = NativeThemeMode.MODERN) +@Desktop(height = 800, titleBar = DesktopTitleBar.NATIVE, width = 1280) +@Ios(themeMode = IosThemeMode.MODERN) public class GameBuilder extends Lifecycle { private EditorController controller; diff --git a/scripts/gen-build-hint-annotations.sh b/scripts/gen-build-hint-annotations.sh new file mode 100755 index 00000000000..2f92a12542b --- /dev/null +++ b/scripts/gen-build-hint-annotations.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +# +# Regenerates the build hint annotations in +# CodenameOne/src/com/codename1/annotations/buildhints from the catalog in +# maven/build-hint-catalog, along with the BuildHintAnnotationBinding table the +# annotation processor reads back. +# +# scripts/gen-build-hint-annotations.sh # write into the tree +# scripts/gen-build-hint-annotations.sh --check # fail if anything changed +# +# The output is checked in. CodenameOne/src is compiled by the Maven core +# module, the Ant/NetBeans project and the IDE projects alike, and only the +# first would see sources generated into target/ -- the others would quietly +# build a codenameone-core.jar without the annotations in it. Checking the +# sources in also means @Ios( completes in the IDE, which is the point. +set -euo pipefail + +SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" +REPO_ROOT="$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)" +CATALOG="$REPO_ROOT/maven/build-hint-catalog" +CLASSES="$CATALOG/target/classes" +ANN_ROOT="$REPO_ROOT/CodenameOne/src" +CATALOG_SRC="$CATALOG/src/main/java" + +check=0 +[ "${1:-}" = "--check" ] && check=1 + +# Always rebuild. Skipping when the class merely exists meant that editing a +# BuildHints*.java source and rerunning this script regenerated every view from +# the previous build's bytecode -- reporting success while silently ignoring the +# edit, and in --check mode passing a tree that is genuinely out of date. +echo "gen-build-hint-annotations: building the catalog" >&2 +(cd "$REPO_ROOT/maven" && mvn -q -B -pl build-hint-catalog package -DskipTests) + +JAVASE_SRC="$REPO_ROOT/Ports/JavaSE/src" +GUIDE_TABLE="$REPO_ROOT/docs/developer-guide/_generated-build-hints.adoc" + +java -cp "$CLASSES" com.codename1.build.shared.BuildHintCodeGenerator \ + "$ANN_ROOT" "$CATALOG_SRC" "$JAVASE_SRC" "$GUIDE_TABLE" + +if [ "$check" -eq 1 ]; then + # The developer guide's table is deliberately absent: it is not checked in, so + # there is nothing for it to drift FROM. scripts/gen-build-hint-table.sh + # renders it during the doc build instead, and this script still writes it for + # a local asciidoctor run -- gitignored, so that copy is never reviewed. + targets=("CodenameOne/src/com/codename1/annotations/buildhints" + "maven/build-hint-catalog/src/main/java/com/codename1/build/shared/BuildHintAnnotationBinding.java" + "Ports/JavaSE/src/com/codename1/impl/javase/BuildHintCatalogDefaults.java") + if ! git -C "$REPO_ROOT" diff --quiet -- "${targets[@]}" \ + || [ -n "$(git -C "$REPO_ROOT" ls-files --others --exclude-standard -- "${targets[@]}")" ]; then + echo "::error::Generated build hint annotations are out of date." >&2 + echo "Run scripts/gen-build-hint-annotations.sh and commit the result." >&2 + git -C "$REPO_ROOT" --no-pager diff -- "${targets[@]}" >&2 || true + git -C "$REPO_ROOT" ls-files --others --exclude-standard -- "${targets[@]}" >&2 || true + exit 1 + fi + echo "gen-build-hint-annotations: generated sources are up to date" +fi diff --git a/scripts/gen-build-hint-table.sh b/scripts/gen-build-hint-table.sh new file mode 100755 index 00000000000..1cbab70f6a3 --- /dev/null +++ b/scripts/gen-build-hint-table.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# Renders the developer guide's build hint table from the catalog. +# +# The table is NOT checked in. It is generated from maven/build-hint-catalog +# every time the guide is rendered, so it cannot drift from the catalog and a +# hand edit has nothing to survive in -- which is what a generated file that +# lives in git always eventually invites. +# +# Both renderers call this first: the developer-guide-docs workflow and +# scripts/website/build.sh. Asciidoctor resolves the include relative to the +# including document, so the file has to land beside it. +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +OUT="${1:-$REPO_ROOT/docs/developer-guide/_generated-build-hints.adoc}" + +echo "gen-build-hint-table: building the catalog" >&2 +(cd "$REPO_ROOT/maven" && mvn -q -B -pl build-hint-catalog package -DskipTests) + +CLASSES="$REPO_ROOT/maven/build-hint-catalog/target/classes" +java -cp "$CLASSES" com.codename1.build.shared.BuildHintCodeGenerator --table-only "$OUT" +echo "gen-build-hint-table: wrote $OUT" >&2 diff --git a/scripts/guibuilder/common/codenameone_settings.properties b/scripts/guibuilder/common/codenameone_settings.properties index 0722854a1c0..75cad311745 100644 --- a/scripts/guibuilder/common/codenameone_settings.properties +++ b/scripts/guibuilder/common/codenameone_settings.properties @@ -5,8 +5,3 @@ codename1.version=1.0 codename1.vendor=Codename One codename1.cssTheme=true codename1.arg.java.version=17 -codename1.arg.nativeTheme=modern -codename1.arg.desktop.width=1440 -codename1.arg.desktop.height=900 -codename1.arg.desktop.titleBar=native -codename1.arg.desktop.interactiveScrollbars=true diff --git a/scripts/guibuilder/common/src/main/java/com/codename1/guibuilder/CodenameOneGUIBuilder.java b/scripts/guibuilder/common/src/main/java/com/codename1/guibuilder/CodenameOneGUIBuilder.java index 113ff6259df..7ce5d7759bc 100644 --- a/scripts/guibuilder/common/src/main/java/com/codename1/guibuilder/CodenameOneGUIBuilder.java +++ b/scripts/guibuilder/common/src/main/java/com/codename1/guibuilder/CodenameOneGUIBuilder.java @@ -82,7 +82,10 @@ import java.util.List; import java.util.Map; import java.util.Set; +import com.codename1.annotations.buildhints.*; +@Build(nativeTheme = NativeThemeMode.MODERN) +@Desktop(height = 900, interactiveScrollbars = true, titleBar = DesktopTitleBar.NATIVE, width = 1440) public class CodenameOneGUIBuilder extends Lifecycle { private static CodenameOneGUIBuilder active; private ProjectBinding binding; diff --git a/scripts/hellocodenameone/common/codenameone_settings.properties b/scripts/hellocodenameone/common/codenameone_settings.properties index 1fbf5370aeb..aac7c5faf7b 100644 --- a/scripts/hellocodenameone/common/codenameone_settings.properties +++ b/scripts/hellocodenameone/common/codenameone_settings.properties @@ -7,15 +7,8 @@ codename1.arg.android.androidAuto.poi=true codename1.arg.android.health.privacyPolicyUrl=https\://www.codenameone.com/privacy-policy.html codename1.arg.android.health.read=steps,heart_rate codename1.arg.android.health.write=steps -codename1.arg.android.useAndroidX=true -codename1.arg.ios.applicationQueriesSchemes=cydia codename1.arg.ios.carplay.audio=true codename1.arg.ios.maps.provider=apple -codename1.arg.ios.newStorageLocation=true -codename1.arg.ios.NSCameraUsageDescription=Used by the CI smoke test to verify the com.codename1.camera native bridge compiles. The app never opens a camera session. -codename1.arg.ios.NSHealthShareUsageDescription=Used by the CI smoke test to verify the com.codename1.health native bridge compiles. The app never reads real health data. -codename1.arg.ios.NSHealthUpdateUsageDescription=Used by the CI smoke test to verify the com.codename1.health write path compiles. The app never writes real health data. -codename1.arg.ios.uiscene=true codename1.arg.java.version=17 codename1.cssTheme=true codename1.displayName=HelloCodenameOne diff --git a/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/HelloCodenameOne.kt b/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/HelloCodenameOne.kt index 5855a688185..fb53dc11160 100644 --- a/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/HelloCodenameOne.kt +++ b/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/HelloCodenameOne.kt @@ -38,7 +38,11 @@ import com.codename1.ui.Display import com.codenameone.examples.hellocodenameone.tests.Cn1ssDeviceRunner import com.codenameone.examples.hellocodenameone.tests.Cn1ssDeviceRunnerReporter import com.codenameone.examples.hellocodenameone.tests.KotlinUiTest +import com.codename1.annotations.buildhints.* +@Android(useAndroidX = true) +@Ios(applicationQueriesSchemes = ["cydia"], newStorageLocation = true, uiscene = true) +@IosPrivacy(cameraUsageDescription = "Used by the CI smoke test to verify the com.codename1.camera native bridge compiles. The app never opens a camera session.", healthShareUsageDescription = "Used by the CI smoke test to verify the com.codename1.health native bridge compiles. The app never reads real health data.", healthUpdateUsageDescription = "Used by the CI smoke test to verify the com.codename1.health write path compiles. The app never writes real health data.") open class HelloCodenameOne : Lifecycle() { override fun init(context: Any?) { super.init(context) diff --git a/scripts/initializr/common/src/main/resources/skill/references/android-to-cn1.md b/scripts/initializr/common/src/main/resources/skill/references/android-to-cn1.md index 59da1f79451..73f16aef281 100644 --- a/scripts/initializr/common/src/main/resources/skill/references/android-to-cn1.md +++ b/scripts/initializr/common/src/main/resources/skill/references/android-to-cn1.md @@ -116,7 +116,7 @@ The EDT/UI-thread rule is identical in spirit to Android: never touch a componen | `Retrofit` / `OkHttp` | Not in the JDK subset. | `Rest.get/post(...).fetchAsJsonMap(...)` — see `references/java-api-subset.md`. | | `Coroutines` / `RxJava` | No coroutines runtime; no RxJava in the subset. | `Display.startThread(...)` + `Display.callSerially(...)`; chain callbacks. | | `R.string.xxx`, `R.drawable.xxx` | No resources system. | `UIManager.getInstance().localize("name", "default")` for strings (reads `messages.properties` bundles); load images by file name `Image.createImage("/foo.png")`. | -| `Permission` manifest entries | Different mechanism. | `Display.requestPermission(...)` at runtime + `codename1.arg.android.xPermissions` build hint (see `references/build-hints.md`). | +| `Permission` manifest entries | Different mechanism. | `Display.requestPermission(...)` at runtime + `codename1.arg.android.xpermissions` build hint (see `references/build-hints.md`). | | `Activity onCreate/onResume/onPause` | No Activity lifecycle. | Override `Lifecycle.init/start/stop` (app-level) and react to `Form.show()` (per-screen). | | `AsyncTask` | Deprecated upstream too. | `Display.startThread(...)` + `callSerially(...)`. | | `BroadcastReceiver` | No analog at the CN1 level. | For lifecycle-related events (`Lifecycle.start()` etc.) use the CN1 lifecycle. For external system events use a native interface. | diff --git a/scripts/initializr/common/src/main/resources/skill/references/build-and-run.md b/scripts/initializr/common/src/main/resources/skill/references/build-and-run.md index c09042332e7..7965ce7a0a9 100644 --- a/scripts/initializr/common/src/main/resources/skill/references/build-and-run.md +++ b/scripts/initializr/common/src/main/resources/skill/references/build-and-run.md @@ -199,13 +199,11 @@ codename1.packageName=com.example.myapp codename1.mainName=MyAppName codename1.displayName=My App Name codename1.arg.java.version=17 # Required: routes the build to the Java 17 build server -codename1.arg.android.googlePlayVersion=true codename1.arg.ios.includePush=false codename1.kotlin=false -codename1.arg.android.xPermissions=... +codename1.arg.android.xpermissions=... codename1.arg.ios.deployment_target=14.0 codename1.arg.ios.teamId=ABCDEF1234 -codename1.arg.build.compile=true # ahead-of-time compile (recommended for iOS) ``` Anything prefixed `codename1.arg..` is forwarded to the build server. See [`build-hints.md`](build-hints.md) for the curated index of build hints. The complete reference is in the Codename One Developer Guide at . diff --git a/scripts/initializr/common/src/main/resources/skill/references/build-hints.md b/scripts/initializr/common/src/main/resources/skill/references/build-hints.md index 3ed3c1b6580..d5f9d31023c 100644 --- a/scripts/initializr/common/src/main/resources/skill/references/build-hints.md +++ b/scripts/initializr/common/src/main/resources/skill/references/build-hints.md @@ -15,8 +15,6 @@ When in doubt, search the developer guide for the exact key name — there are h | Hint | Effect | | --- | --- | | `codename1.arg.java.version=17` | **Required.** Picks the JDK 17 build server toolchain. | -| `codename1.arg.build.compile=true` | Run the ahead-of-time / bytecode-to-native compile (recommended for iOS, smaller binaries). | -| `codename1.arg.build.timeout=180` | Build server timeout in minutes. Bump for very large apps. | | `codename1.arg.var.=...` | Define a custom variable referenced as `${var.name}` elsewhere in hints. | ## iOS @@ -46,12 +44,10 @@ When in doubt, search the developer guide for the exact key name — there are h | Hint | Effect | | --- | --- | -| `codename1.arg.android.googlePlayVersion=true` | Build the Google Play–compatible APK/AAB variant. | -| `codename1.arg.android.sdkVersion=34` | Compile-time Android SDK. | | `codename1.arg.android.targetSDKVersion=34` | Target SDK in the manifest (drives Play Store acceptance). | -| `codename1.arg.android.minSdkVersion=24` | Minimum Android API level. | -| `codename1.arg.android.buildToolsVersion=34.0.0` | Android build-tools version. | -| `codename1.arg.android.xPermissions=` | Inject extra `` lines into the manifest. | +| `codename1.arg.android.min_sdk_version=24` | Minimum Android API level. | +| `codename1.arg.android.buildToolsVersion=34.0.0` | Android build-tools version. Also selects the compile SDK — there is no separate compile-SDK hint. | +| `codename1.arg.android.xpermissions=` | Inject extra `` lines into the manifest. | | `codename1.arg.android.xapplication=` | Inject XML inside the manifest's `` element. | | `codename1.arg.android.activity.launchMode=singleTask` | Launch mode for the main activity. | | `codename1.arg.android.statusbar_hidden=true` | Hide the Android status bar. | @@ -112,8 +108,6 @@ This is an advanced, issuer-only feature — most apps never need it. The compil | `codename1.arg.javascript.proxy.allowedTargets=...` | Restrict the generated proxy to comma-separated origins, hosts, or wildcard subdomains. | | `codename1.arg.javascript.proxy.url=...` | Use an externally hosted proxy URL. This suppresses generated packaging unless `javascript.proxy.target` is also explicit. | | `codename1.arg.javascript.inject_proxy=false` | Disable proxy generation and proxy URL injection. | -| `codename1.arg.javascript.html5=true` | Emit modern ES output. | -| `codename1.arg.javascript.bundleResources=true` | Inline `theme.res` into the bundle (faster cold start). | ## Variable substitution diff --git a/scripts/initializr/common/src/main/resources/skill/references/mobile-adaptability.md b/scripts/initializr/common/src/main/resources/skill/references/mobile-adaptability.md index 39310e63e20..219c2f8abe4 100644 --- a/scripts/initializr/common/src/main/resources/skill/references/mobile-adaptability.md +++ b/scripts/initializr/common/src/main/resources/skill/references/mobile-adaptability.md @@ -222,6 +222,6 @@ The CN1 simulator has a "Skin" menu — pick "iPhone 15 Pro", "Pixel 8", "iPad", ## What CN1 explicitly does NOT do - Dark mode is opt-in: write a `@media (prefers-color-scheme: dark) { ... }` block in `theme.css` to recolor UIIDs (see `references/css.md`). For runtime overrides — toggling dark mode in-app regardless of system preference — call `Display.getInstance().setDarkMode(Boolean)`; read the current state with `Display.getInstance().isDarkMode()`. -- Orientation lock at runtime — call `Display.getInstance().lockOrientation(boolean portrait)` to pin the orientation while the app is running; `unlockOrientation()` releases it. Check `canForceOrientation()` first (some browsers / JavaScript runtimes don't allow it outside full-screen mode). The old `codename1.arg.ios.orientation` / `codename1.arg.android.screenOrientation` build hints are **discouraged** — `lockOrientation` works portably and dynamically across all platforms. +- Orientation lock at runtime — call `Display.getInstance().lockOrientation(boolean portrait)` to pin the orientation while the app is running; `unlockOrientation()` releases it. Check `canForceOrientation()` first (some browsers / JavaScript runtimes don't allow it outside full-screen mode). The `codename1.arg.ios.interface_orientation` build hint is **discouraged** (and Android has no equivalent hint) — `lockOrientation` works portably and dynamically across all platforms. - No automatic "iPad split view" support (the macOS-style split view) — design master/detail manually with `BorderLayout`. - No `vh` / `vw` units in CSS. Use percent insets in `LayeredLayoutConstraint`. diff --git a/scripts/initializr/common/src/main/resources/skill/references/native-interfaces.md b/scripts/initializr/common/src/main/resources/skill/references/native-interfaces.md index 37edc5cfceb..75d16576b02 100644 --- a/scripts/initializr/common/src/main/resources/skill/references/native-interfaces.md +++ b/scripts/initializr/common/src/main/resources/skill/references/native-interfaces.md @@ -147,10 +147,10 @@ public class GpsBridgeImpl { } ``` -Permissions in the Android manifest are injected via `codename1.arg.android.xPermissions`. For example: +Permissions in the Android manifest are injected via `codename1.arg.android.xpermissions`. For example: ```properties -codename1.arg.android.xPermissions= +codename1.arg.android.xpermissions= ``` Extra Gradle dependencies go in `codename1.arg.android.gradleDep`. See `references/build-hints.md`. @@ -299,6 +299,6 @@ navigator.geolocation.watchPosition(function(pos) { - **Method signature mismatch between the interface and the stub** — happens after you edit the Java interface but forget to regenerate. Re-run `mvn cn1:generate-native-interfaces -Dcn1.generateNativeInterfaces.overwrite=true` and re-apply your platform code. - **Returning Java objects** — not supported by the bridge marshaler. Return primitives, `String`, `byte[]`, or `PeerComponent` only. - **`PeerComponent` on iOS without ARC** — peer-component implementations can dangle if you treat the bridge like an ARC-managed Swift method. Retain natively, or wrap returned views in a static holder. -- **Permissions / Info.plist** — the build server happily accepts a native interface that calls a privacy-protected API, but the App Store / Play Store reject it. Set `codename1.arg.ios.plistInject` and `codename1.arg.android.xPermissions` (see `references/build-hints.md`). +- **Permissions / Info.plist** — the build server happily accepts a native interface that calls a privacy-protected API, but the App Store / Play Store reject it. Set `codename1.arg.ios.plistInject` and `codename1.arg.android.xpermissions` (see `references/build-hints.md`). - **Forgetting `isSupported()` return** — defaults to `false`, so the Java side thinks the bridge isn't available. Always override. - **`NativeLookup.create()` returns null in the simulator only** — usually means the `javase/` impl class is missing or in the wrong package. diff --git a/scripts/purchase-test-app/app/common/codenameone_settings.properties b/scripts/purchase-test-app/app/common/codenameone_settings.properties index 7f40d6a6f7e..d495510cbea 100644 --- a/scripts/purchase-test-app/app/common/codenameone_settings.properties +++ b/scripts/purchase-test-app/app/common/codenameone_settings.properties @@ -3,12 +3,6 @@ codename1.android.keystore=/Users/shai/dev/cn2/CodenameOne/scripts/purchase-test-app/app/android/../common/androidCerts/KeyChain.ks codename1.android.keystoreAlias=androidKey codename1.android.keystorePassword=password -codename1.arg.android.licenseKey=CN1TESTPLACEHOLDERKEYNOTFORPRODUCTIONxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxIDAQAB -codename1.arg.android.useAndroidX=true -codename1.arg.ios.applicationQueriesSchemes=cydia -codename1.arg.ios.newStorageLocation=true -codename1.arg.ios.NSCameraUsageDescription=Used by the CI smoke test to verify the com.codename1.camera native bridge compiles. The app never opens a camera session. -codename1.arg.ios.uiscene=true codename1.arg.java.version=17 codename1.cssTheme=true codename1.displayName=CN1PurchaseTest diff --git a/scripts/purchase-test-app/app/common/src/main/java/com/codenameone/examples/purchasetest/PurchaseTestApp.java b/scripts/purchase-test-app/app/common/src/main/java/com/codenameone/examples/purchasetest/PurchaseTestApp.java index 09847217a58..f4453c9d921 100644 --- a/scripts/purchase-test-app/app/common/src/main/java/com/codenameone/examples/purchasetest/PurchaseTestApp.java +++ b/scripts/purchase-test-app/app/common/src/main/java/com/codenameone/examples/purchasetest/PurchaseTestApp.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2012, 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.examples.purchasetest; import com.codename1.payment.Purchase; @@ -5,6 +27,7 @@ import com.codename1.ui.Form; import com.codename1.ui.Label; import com.codename1.ui.layouts.BoxLayout; +import com.codename1.annotations.buildhints.*; /** * Minimal Codename One app dedicated to the In-App-Purchase e2e tests. @@ -16,6 +39,9 @@ * purchase reached the store. Kept separate from the hellocodenameone sample so * IAP wiring never ripples into the screenshot/notification CI workflows. */ +@Android(licenseKey = "CN1TESTPLACEHOLDERKEYNOTFORPRODUCTIONxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxIDAQAB", useAndroidX = true) +@Ios(applicationQueriesSchemes = {"cydia"}, newStorageLocation = true, uiscene = true) +@IosPrivacy(cameraUsageDescription = "Used by the CI smoke test to verify the com.codename1.camera native bridge compiles. The app never opens a camera session.") public class PurchaseTestApp extends Lifecycle { @Override public void init(Object context) { diff --git a/scripts/run-javase-cef-ffmpeg-smoke.py b/scripts/run-javase-cef-ffmpeg-smoke.py index 342268286f0..7208bf848fc 100644 --- a/scripts/run-javase-cef-ffmpeg-smoke.py +++ b/scripts/run-javase-cef-ffmpeg-smoke.py @@ -61,6 +61,11 @@ def tail_text(path: Path, max_lines: int = 60) -> str: # and a non-resolvable import POM included. _TRANSFER_FAILURE = re.compile( r"Could not transfer artifact" + # Maven's wording when it reaches the repository but cannot read the POM it + # needs to resolve a dependency. Also a fetch failure, and it is what a + # Central hiccup during copy-dependencies actually prints -- a shape that + # made a green build red without a retry because nothing here named it. + r"|Failed to read artifact descriptor" r"|transfer failed for" r"|status code: (?:40[38]|409|425|429|5\d\d)" r"|Too Many Requests" diff --git a/scripts/settings/common/codenameone_settings.properties b/scripts/settings/common/codenameone_settings.properties index 847d5d3097c..97b9c23a22e 100644 --- a/scripts/settings/common/codenameone_settings.properties +++ b/scripts/settings/common/codenameone_settings.properties @@ -6,10 +6,3 @@ codename1.vendor=Codename One codename1.icon=icon.png codename1.cssTheme=true codename1.arg.java.version=17 -codename1.arg.nativeTheme=modern -codename1.arg.ios.themeMode=modern -codename1.arg.and.themeMode=modern -codename1.arg.desktop.width=1260 -codename1.arg.desktop.height=820 -codename1.arg.desktop.titleBar=native -codename1.arg.desktop.interactiveScrollbars=true diff --git a/scripts/settings/common/pom.xml b/scripts/settings/common/pom.xml index c595ad73e9a..81d376242bb 100644 --- a/scripts/settings/common/pom.xml +++ b/scripts/settings/common/pom.xml @@ -8,9 +8,17 @@ cn1-settings-common jar + + + true + cn1-settings-common + + com.codenameone + codenameone-build-hint-catalog + com.codenameone codenameone-core @@ -74,13 +82,6 @@ ${project.basedir}/src/main/resources - - ${project.basedir}/../../../docs/developer-guide - - Advanced-Topics-Under-The-Hood.asciidoc - - com/codename1/settings/hints - @@ -131,7 +132,10 @@ org.apache.maven.plugins maven-surefire-plugin - true + + ${cn1.settings.skipTests} diff --git a/scripts/settings/common/src/main/java/com/codename1/settings/CodenameOneSettings.java b/scripts/settings/common/src/main/java/com/codename1/settings/CodenameOneSettings.java index 6c230eeca6d..b88faa8b799 100644 --- a/scripts/settings/common/src/main/java/com/codename1/settings/CodenameOneSettings.java +++ b/scripts/settings/common/src/main/java/com/codename1/settings/CodenameOneSettings.java @@ -80,7 +80,12 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.codename1.annotations.buildhints.*; +@Android(themeMode = AndroidThemeMode.MODERN) +@Build(nativeTheme = NativeThemeMode.MODERN) +@Desktop(height = 820, interactiveScrollbars = true, titleBar = DesktopTitleBar.NATIVE, width = 1260) +@Ios(themeMode = IosThemeMode.MODERN) public class CodenameOneSettings extends Lifecycle { public enum Section { BASIC, BUILD_HINTS, EXTENSIONS, ADVANCED } @@ -90,7 +95,10 @@ public enum Section { BASIC, BUILD_HINTS, EXTENSIONS, ADVANCED } private ProjectBinding binding; private SettingsProperties settings; - private BuildHintCatalog buildHints = BuildHintCatalog.fallback(); + private BuildHintCatalog buildHints = BuildHintCatalog.load(); + /// hint name -> the annotation attribute that declares it, e.g. "@Ios(pods)". + /// Empty when the project has not been built, or declares none. + private java.util.Map annotationOwnedHints = new java.util.HashMap<>(); private Section section = Section.BASIC; private Form form; private Container page; @@ -221,38 +229,8 @@ private void loadProject() { } catch (Exception ex) { Log.e(ex); } - buildHints = loadBuildHints(binding.buildHintsDoc()); - } - } - - private BuildHintCatalog loadBuildHints(String docPath) { - InputStream in = null; - if (docPath != null && docPath.length() > 0) { - try { - String url = ProjectIO.fsUrl(docPath); - FileSystemStorage fs = FileSystemStorage.getInstance(); - if (fs.exists(url)) { - in = fs.openInputStream(url); - return BuildHintCatalog.fromAsciiDoc(Util.readToString(in, "UTF-8")); - } - } catch (Exception ex) { - Log.e(ex); - } finally { - Util.cleanup(in); - in = null; - } - } - try { - in = getClass().getResourceAsStream("/com/codename1/settings/hints/Advanced-Topics-Under-The-Hood.asciidoc"); - if (in == null) { - return BuildHintCatalog.fallback(); - } - return BuildHintCatalog.fromAsciiDoc(Util.readToString(in, "UTF-8")); - } catch (Exception ex) { - Log.e(ex); - return BuildHintCatalog.fallback(); - } finally { - Util.cleanup(in); + buildHints = BuildHintCatalog.load(); + annotationOwnedHints = loadAnnotationOwnedHints(); } } @@ -638,6 +616,20 @@ private Component customHintRow() { ToastBar.showErrorMessage("Enter a build hint name."); return; } + // The same ownership rule as the catalog rows. Withholding the row's + // controls and leaving this form open is no protection at all: typing + // ios.teamId here -- or any alias of it -- writes exactly the second + // declaration the row was hiding, and the next build refuses the + // project. Canonical, so an alias of an annotation-owned hint is + // caught too. + String ownedBy = annotationOwnedHints.get( + com.codename1.build.shared.BuildHints.canonicalName(k)); + if (ownedBy != null) { + ToastBar.showErrorMessage(k + " is set by " + ownedBy + + " on the main class. Change it there -- declaring it here as well " + + "fails the build."); + return; + } settings.setBuildHint(k, value.getText() == null ? "" : value.getText()); key.setText(""); value.setText(""); @@ -681,6 +673,13 @@ private void animatePage() { private Component hintRow(BuildHintMetadata meta) { Container row = new Container(BoxLayout.y()); row.setUIID(uiid("SettingsRow")); + // Look the hint up by its canonical name: a deprecated alias configures the + // same effective setting, so cn1.androidTheme is owned whenever an + // annotation owns and.themeMode. Matching on the exact name left the alias + // row offering Add, which would create the second declaration the next + // build refuses through the alias conflict check. + String ownedBy = annotationOwnedHints.get( + com.codename1.build.shared.BuildHints.canonicalName(meta.name())); boolean active = hasBuildHint(meta.name()); String value = active ? settings.getBuildHint(meta.name()) : ""; BuildHintType effectiveType = effectiveHintType(meta, value); @@ -693,26 +692,101 @@ private Component hintRow(BuildHintMetadata meta) { if (active) { metaLine.add(new Label("Active", uiid("SettingsActiveBadge"))); } + if (ownedBy != null) { + metaLine.add(new Label(ownedBy, uiid("SettingsRowMeta"))); + } text.add(name).add(metaLine); - if (active) { + if (ownedBy != null) { + // Set by an annotation on the main class. Editing it here would write a + // second declaration and the next build would refuse the project, so the + // value is shown and the editor is withheld. + boolean duplicate = active; + TextArea owned = new TextArea(duplicate + ? "Declared BOTH here and by " + ownedBy + " on the main class. The next " + + "build refuses that. Remove the properties declaration with the button " + + "on the right, or delete the annotation attribute." + : "Set by " + ownedBy + " on the main class. " + + "Change it there -- declaring it here as well fails the build."); + owned.setUIID(uiid("SettingsRowText")); + owned.setEditable(false); + owned.setFocusable(false); + text.add(owned); + if (duplicate) { + // The properties declaration exists AND an annotation owns the + // hint, so this row is the build failure. Withholding every + // control left the tool able to report the problem and unable to + // fix it; the value stays uneditable -- editing it would only + // move the conflict -- but removing it is exactly the resolution, + // so that button stays. + Container header = new Container(new BorderLayout()); + header.add(BorderLayout.CENTER, text); + header.add(BorderLayout.EAST, removeHintButton(meta)); + row.add(header); + } else { + row.add(text); + } + } else if (active) { text.add(activeHintEditor(meta, value, effectiveType)); } else { Container controls = new Container(new FlowLayout(Component.LEFT, Component.CENTER)); controls.setUIID(uiid("SettingsHintEditor")); Button add = new Button("Add", uiid("SettingsOutline")); add.setMaterialIcon(FontImage.MATERIAL_ADD, 1.2f); - add.addActionListener(e -> { - settings.setBuildHint(meta.name(), defaultHintValue(meta)); - renderBuildHintsList(); - animatePage(); - }); - controls.add(add); + String seed = defaultHintValue(meta); + if (seed != null) { + add.addActionListener(e -> { + settings.setBuildHint(meta.name(), seed); + renderBuildHintsList(); + animatePage(); + }); + controls.add(add); + } else { + // Nothing safe to seed. The build decides this hint's value + // itself when the line is ABSENT -- android.targetSDKVersion is + // computed from the installed platforms -- so writing a + // placeholder does not create an unset hint, it overrides the + // computation with a value nobody chose. `0` there selects the + // legacy android-14 target and emits targetSdkVersion="0"; an + // empty string is no better for a hint whose presence is the + // switch, which is how facebook.appId=\"\" would enable Facebook + // with no ID. + // + // So the row asks for a value and writes nothing until it has + // one. Add is what reveals the field, not what saves. + TextField pending = new TextField("", "value"); + pending.setUIID(uiid("SettingsField")); + configureHintField(pending, meta); + Button save = new Button("Save", uiid("SettingsOutline")); + save.addActionListener(e -> { + String typed = pending.getText() == null ? "" : pending.getText().trim(); + if (typed.length() == 0) { + ToastBar.showErrorMessage(meta.name() + + " has no default -- enter the value you want."); + return; + } + if (!isValidHintValue(meta, typed)) { + ToastBar.showErrorMessage(typed + " is not a valid value for " + + meta.name() + "."); + return; + } + settings.setBuildHint(meta.name(), canonicalHintValue(meta, typed)); + renderBuildHintsList(); + animatePage(); + }); + add.addActionListener(e -> { + controls.removeAll(); + controls.add(pending).add(save); + controls.getComponentForm().revalidate(); + pending.startEditingAsync(); + }); + controls.add(add); + } Container header = new Container(new BorderLayout()); header.add(BorderLayout.CENTER, text); header.add(BorderLayout.EAST, controls); row.add(header); } - if (active) { + if (active && ownedBy == null) { row.add(text); } TextArea details = new TextArea(meta.description()); @@ -743,7 +817,13 @@ private Component activeHintEditor(BuildHintMetadata meta, String value, BuildHi valueField.addDataChangedListener((type, index) -> { String next = valueField.getText() == null ? "" : valueField.getText().trim(); if (isValidHintValue(meta, next)) { - settings.setBuildHint(meta.name(), next); + // Stored in the domain's own spelling. Accepting `INTERNALONLY` + // and writing it back verbatim marked the value valid and then + // failed the Android build, because the builder copies it into + // the case-sensitive android:installLocation attribute. What + // the developer meant is unambiguous, and only one spelling of + // it works everywhere. + settings.setBuildHint(meta.name(), canonicalHintValue(meta, next)); valueField.setUIID(uiid("SettingsField")); } else { valueField.setUIID(uiid("SettingsFieldError")); @@ -752,14 +832,7 @@ private Component activeHintEditor(BuildHintMetadata meta, String value, BuildHi }); controls.add(BorderLayout.CENTER, valueField); } - Button remove = new Button("", uiid("SettingsSmallIconButton")); - remove.setMaterialIcon(FontImage.MATERIAL_DELETE, 2.2f); - remove.addActionListener(e -> { - settings.removeBuildHint(meta.name()); - renderBuildHintsList(); - animatePage(); - }); - controls.add(BorderLayout.EAST, remove); + controls.add(BorderLayout.EAST, removeHintButton(meta)); editor.add(editorLayout.createConstraint(0, 0).widthPercentage(72), new Container()); editor.add(editorLayout.createConstraint(0, 1).widthPercentage(28), controls); return editor; @@ -778,14 +851,45 @@ private boolean hasBuildHint(String key) { return settings.keys().contains(SettingsProperties.fullBuildHintKey(key)); } + /// Deletes this hint's properties declaration. + /// + /// One implementation, used by the ordinary editor and by the conflict row: + /// removing the declaration is the resolution in both, and the second copy + /// this replaced was the reason the conflict row had no way out at all. + private Button removeHintButton(BuildHintMetadata meta) { + Button remove = new Button("", uiid("SettingsSmallIconButton")); + remove.setMaterialIcon(FontImage.MATERIAL_DELETE, 2.2f); + remove.addActionListener(e -> { + settings.removeBuildHint(meta.name()); + renderBuildHintsList(); + animatePage(); + }); + return remove; + } + + /// The value Add should write, or null when there is nothing safe to write. + /// + /// The builder's OWN default when the catalog records one: seeding a + /// type-wide placeholder instead writes a value the project did not have -- + /// android.NotificationChannel.importance defaults to 2, and Add persisting 0 + /// silences the channel before the user has typed anything. Adding a hint + /// should start from what the build already does. + /// + /// Null when it records none, because for those the ABSENCE of the line is + /// itself the configuration -- android.targetSDKVersion is computed from the + /// installed platforms when unset, and a placeholder overrides that + /// computation rather than leaving it alone. A boolean is the one exception: + /// its two values are the whole domain, so `true` is a real choice and is + /// what adding the hint means. private String defaultHintValue(BuildHintMetadata meta) { + String catalogDefault = meta.defaultValue(); + if (catalogDefault != null && catalogDefault.length() > 0) { + return catalogDefault; + } if (meta.type() == BuildHintType.BOOLEAN) { return "true"; } - if (meta.type() == BuildHintType.INTEGER) { - return "0"; - } - return ""; + return null; } private int descriptionRows(String text) { @@ -812,11 +916,54 @@ private void configureHintField(TextField field, BuildHintMetadata meta) { } } + /// `value` in the spelling the catalog declares, or `value` when the domain + /// is open or does not recognise it. + /// + /// Only the spelling changes, never the choice: an accepted alias resolves to + /// the canonical value it names, which is the one every reader accepts. + private String canonicalHintValue(BuildHintMetadata meta, String value) { + if (value == null || value.length() == 0 || meta.values().isEmpty()) { + return value; + } + com.codename1.build.shared.BuildHints.Hint hint = + com.codename1.build.shared.BuildHints.byName(meta.name()); + if (hint == null || hint.values().isEmpty()) { + return value; + } + String canonical = hint.canonicalValue(value); + return canonical == null ? value : canonical; + } + private boolean isValidHintValue(BuildHintMetadata meta, String value) { if (value == null || value.trim().length() == 0) { return true; } String v = value.trim(); + // A closed value domain is the one case where a wrong value is certain to + // be wrong: the builder compares against these strings and silently uses + // its default when it recognises none of them. + // + // Through the catalog's own canonicalisation rather than the picklist, + // because a domain can accept spellings that are not offered as choices: + // ios.themeMode=flat and and.themeMode=material are what the runtime + // compares against, and rejecting them told a developer that a working + // configuration was invalid and then refused to save the edit. + if (!meta.values().isEmpty()) { + com.codename1.build.shared.BuildHints.Hint hint = + com.codename1.build.shared.BuildHints.byName(meta.name()); + if (hint != null && !hint.values().isEmpty()) { + return hint.canonicalValue(v) != null; + } + for (String allowed : meta.values()) { + if (allowed.equalsIgnoreCase(v)) { + return true; + } + } + return false; + } + if (meta.type() == BuildHintType.BOOLEAN) { + return "true".equalsIgnoreCase(v) || "false".equalsIgnoreCase(v); + } if (meta.type() == BuildHintType.INTEGER) { return isDigits(v); } @@ -1544,9 +1691,6 @@ private void renderAdvanced() { Container c = card("Files"); actionRow(c, "Settings file", binding.settings(), () -> Display.getInstance().execute(ProjectIO.fsUrl(binding.settings()))); actionRow(c, "Common POM", binding.pom(), () -> Display.getInstance().execute(ProjectIO.fsUrl(binding.pom()))); - if (binding.buildHintsDoc() != null && binding.buildHintsDoc().length() > 0) { - actionRow(c, "Build-hints source", binding.buildHintsDoc(), () -> Display.getInstance().execute(ProjectIO.fsUrl(binding.buildHintsDoc()))); - } page.add(c); } @@ -2064,4 +2208,2362 @@ public boolean isScrollableY() { return false; } } + + /// Reads the hints the main class's annotations declare. + /// + /// The annotation processor writes this file into `target/classes` on every + /// build and deletes it when the last annotation goes away, so it is the + /// authoritative statement of what the annotations currently declare -- and + /// it carries `cn1.buildHints.origin.`, which names the attribute. + /// + /// This matters because a hint declared by an annotation must not also be + /// written into `codenameone_settings.properties`: the next build fails with + /// the duplicate-declaration error. Without this the Add button would create + /// exactly that, silently, for any hint the generated project ships as an + /// annotation. + /// + /// An unbuilt project has no file and no annotation-owned hints, which is the + /// same conservative answer this tool gave before. + private java.util.Map loadAnnotationOwnedHints() { + java.util.Map out = new java.util.HashMap<>(); + if (binding == null || binding.projectDir() == null) { + return out; + } + String path = binding.projectDir() + "/target/classes/META-INF/codenameone/build-hints.properties"; + InputStream in = null; + try { + // Always start from the source, because it is the only current + // statement of what the annotations declare. The manifest is a build + // artifact and goes stale in both directions: absent right after + // cn1:migrate-build-hints, and out of date the moment an attribute is + // added to a project that was built earlier. Trusting it alone left + // the newly annotated hint looking unowned, and Add then wrote the + // duplicate declaration the next build refuses. + // + // The manifest supplies origins, but it cannot ADD ownership the + // source does not show. An attribute deleted from the main class and + // not yet rebuilt is exactly that case: the source is right, the + // manifest is a build old, and taking the union kept Add and the + // editor hidden for a hint nothing owns any more -- until the user + // happened to rebuild, with nothing to suggest that was the fix. + java.util.Map fromSource = annotationOwnedHintsFromSource(); + if (fromSource != null) { + out.putAll(fromSource); + } + + String url = ProjectIO.fsUrl(path); + FileSystemStorage fs = FileSystemStorage.getInstance(); + if (!fs.exists(url)) { + return out; + } + in = fs.openInputStream(url); + String text = Util.readToString(in, "ISO-8859-1"); + String originPrefix = "cn1.buildHints.origin."; + for (String line : com.codename1.util.StringUtil.tokenize(text, "\n")) { + String t = line.trim(); + if (!t.startsWith(originPrefix)) { + continue; + } + int eq = t.indexOf('='); + if (eq > originPrefix.length()) { + String hint = t.substring(originPrefix.length(), eq).trim(); + String canonical = + com.codename1.build.shared.BuildHints.canonicalName(hint); + // Only for a hint the source still declares -- unless there + // was no source to read, where the manifest is all there is + // and is better than nothing. + if (fromSource == null || fromSource.containsKey(canonical)) { + out.put(canonical, t.substring(eq + 1).trim()); + } + } + } + } catch (Exception ex) { + Log.e(ex); + } finally { + Util.cleanup(in); + } + return out; + } + + /// Reads the build hint annotations straight off the main class. + /// + /// Only the attribute *names* are needed -- what each hint is set to does not + /// matter, only that an annotation owns it -- so this scans the annotation + /// list above the class declaration for `name =` at the top level of each + /// annotation's parentheses and maps those to hint names through the catalog. + /// Values are skipped wholesale, so a comma or bracket inside a string cannot + /// confuse it. + /// The hints the main class's SOURCE declares, or null when no source file + /// for it could be read at all. + private java.util.Map annotationOwnedHintsFromSource() { + java.util.Map out = new java.util.HashMap<>(); + String main = settings == null ? null : settings.get("codename1.mainName"); + String pkg = settings == null ? null : settings.get("codename1.packageName"); + if (binding == null || binding.projectDir() == null || main == null || main.isEmpty()) { + return out; + } + String rel = (pkg == null || pkg.isEmpty() ? "" : pkg.replace('.', '/') + "/") + main; + for (String ext : new String[]{".java", ".kt"}) { + for (String root : new String[]{"/src/main/java/", "/src/main/kotlin/", "/src/"}) { + String path = binding.projectDir() + root + rel + ext; + String text = readIfPresent(path); + if (text != null && ext.equals(".java")) { + text = decodeUnicodeEscapes(text); + } + // The conventional path has to DECLARE the class, not merely + // exist. Moving a Kotlin main class into a differently named file + // can leave the old Main.kt behind holding something else, and + // returning on its mere existence skipped the search below -- + // reporting the annotated hints as unowned, which is the state + // that lets Add write the duplicate. + if (text == null || !declaresClass(text, main, pkg, ext.equals(".kt"))) { + continue; + } + collectOwnedHints(text, out, ext.equals(".kt"), + otherProjectSources(binding.projectDir(), path)); + return out; + } + } + // Those three roots are a convention, not the truth: a module can add a + // source root, and Kotlin does not require a file to be named after the + // class it declares. Falling straight through to null here let the caller + // trust a stale manifest -- which is the bug the source scan was added to + // fix, reappearing for anyone whose layout is merely unusual. So look + // properly before giving up. + String found = findMainClassSource(binding.projectDir(), main, pkg); + if (found != null) { + collectOwnedHints(found, out, lastSourceWasKotlin, + otherProjectSources(binding.projectDir(), lastSourcePath)); + return out; + } + // Genuinely no source. Distinct from "found and declares nothing", and + // the caller has to tell them apart before letting the source overrule + // the manifest. + return null; + } + + /// Set by findMainClassSource, since it decides the language by what it finds. + private boolean lastSourceWasKotlin; + + /// The path findMainClassSource read, so it can be left out of the sweep for + /// declarations made elsewhere. + private String lastSourcePath; + + /// The directories a module's MAIN sources are compiled from, by + /// convention, as candidates to be filtered by what exists. + /// + /// An allow-list rather than a walk of the whole project with exclusions. + /// The exclusions were never going to be complete -- `src/test` was + /// followed by `src/testFixtures`, then `src/main/resources`, then + /// `src/main/templates` and `src/main/proto` -- because "not a source root" + /// is not a property of a directory's name. Naming the roots instead makes + /// every one of those wrong by construction. + /// + /// `target/generated-sources` is a root: Maven plugins add it, so a + /// declaration there is one the compiler sees. Nothing else under an output + /// directory is reachable, which also retires the `build` special case -- + /// starting inside a source root means com.codename1.build.shared is walked + /// as the package it is, with no rule needed to tell it from an output + /// directory. + /// + /// The flat `src` is a candidate only where there is no `src/main`, since + /// that is the layout it belongs to; in a Maven layout it would drag the + /// test sets back in. + /// + /// KNOWN LIMIT, and the reason it is acceptable: a module that configures a + /// custom root in its POM is not covered, because this tool has no resolved + /// project to ask and its POM handling is deliberately string surgery rather + /// than an XML model. Missing a peer means a shadowing type goes unseen, so + /// a hint reads as annotation-owned and its editor stays hidden -- annoying, + /// but it cannot write the duplicate declaration that fails the next build, + /// which is what including a non-source directory could. + static java.util.List candidateSourceRoots(String projectDir, boolean hasSrcMain) { + java.util.List out = new java.util.ArrayList<>(); + if (projectDir == null) { + return out; + } + out.add(projectDir + "/src/main/java"); + out.add(projectDir + "/src/main/kotlin"); + if (!hasSrcMain) { + out.add(projectDir + "/src"); + } + out.add(projectDir + "/target/generated-sources"); + out.add(projectDir + "/build/generated-sources"); + return out; + } + + /// The roots a POM declares: ``, and the source lists the + /// Kotlin and build-helper plugins take. + /// + /// A string read, like the rest of this tool's POM handling. It is looking + /// for plain elements, and what it cannot resolve -- a `${property}` path -- + /// it leaves alone rather than guessing. + /// + /// A declared root under a test tree is dropped: those are configured + /// through the same elements, and one of them shadowing a production type is + /// the failure this list exists to avoid. + static java.util.List declaredSourceRoots(String pomText) { + java.util.List out = new java.util.ArrayList<>(); + for (String active : activeConfiguration(pomText)) { + collectDeclaredRoots(active, out); + } + return out; + } + + /// The parts of a POM whose configuration is in effect without being asked + /// for: the document with its `` removed, and any profile that + /// says it is active by default. + /// + /// A profile this reader cannot evaluate is left out rather than merged in. + /// An inactive `src/preview` was being + /// read as a production root, so a type kept there shadowed the real + /// annotation -- and activation depends on properties, files, the JDK and + /// the OS, none of which this tool has a model for. + static java.util.List activeConfiguration(String pomText) { + java.util.List out = new java.util.ArrayList<>(); + if (pomText == null) { + return out; + } + out.add(withoutElement(pomText, "profiles")); + int at = pomText.indexOf(""); + while (at >= 0) { + int close = pomText.indexOf("", at); + if (close < 0) { + break; + } + String profile = pomText.substring(at, close); + if (profile.indexOf("true") >= 0) { + out.add(profile); + } + at = pomText.indexOf("", close); + } + return out; + } + + private static void collectDeclaredRoots(String pomText, java.util.List out) { + // Scoped to the elements that actually declare a compile root. + // `` and `` are ordinary words: another plugin + // naming src/main/templates in one of them is not saying it is + // compiled, and treating it as a root put the templates back in the + // sweep that the root list had just taken them out of. + collectRoots(elementValues(pomText, "sourceDirectory"), out); + collectRoots(compileGoalConfiguration(pluginBlock(pomText, "kotlin-maven-plugin"), + "compile"), "sourceDir", out); + String helper = pluginBlock(pomText, "build-helper-maven-plugin"); + if (helper != null) { + // add-test-source uses the same element, so an execution that adds + // TEST sources is passed over -- the same distinction the Kotlin + // plugin's compile and test-compile executions need. + collectRoots(compileGoalConfiguration(helper, "add-source"), "source", out); + } + } + + /// The parts of a plugin element whose configuration applies to the MAIN + /// compilation: its executions bound to `goal`, or the whole element when it + /// declares no executions, since plugin-level configuration applies to every + /// goal including that one. + /// + /// The test goals use the same elements -- `test-compile` for Kotlin, + /// `add-test-source` for build-helper -- and a test directory whose name + /// does not look like one, `fixtures` say, is otherwise read as production + /// code and shadows a real annotation. + private static java.util.List compileGoalConfiguration(String pluginBlock, + String goal) { + java.util.List out = new java.util.ArrayList<>(); + if (pluginBlock == null) { + return out; + } + // Plugin-level configuration applies to every execution, so it counts + // whether or not there are any -- returning only the matching executions + // dropped a `` written once outside them, and a main class + // compiled from there became invisible. + int executions = pluginBlock.indexOf(""); + int endOfExecutions = pluginBlock.indexOf(""); + out.add(executions >= 0 && endOfExecutions > executions + ? pluginBlock.substring(0, executions) + + pluginBlock.substring(endOfExecutions) + : pluginBlock); + int at = pluginBlock.indexOf(""); + while (at >= 0) { + int close = pluginBlock.indexOf("", at); + if (close < 0) { + break; + } + String execution = pluginBlock.substring(at, close); + // The goal as an ELEMENT: `test-compile` contains `compile`, so a + // substring test takes exactly the executions it must not. + if (execution.indexOf("" + goal + "") >= 0) { + out.add(execution); + } + at = pluginBlock.indexOf("", close); + } + return out; + } + + private static void collectRoots(java.util.List blocks, String element, + java.util.List out) { + for (String block : blocks) { + collectRoots(elementValues(block, element), out); + } + } + + private static void collectRoots(java.util.List values, java.util.List out) { + for (String value : values) { + String path = value.trim().replace('\\', '/'); + // A `${project.basedir}` prefix is deterministic and common; only + // an expression this reader cannot resolve makes the path unusable. + if (path.isEmpty() || expandProjectPaths(path, "/probe") == null + || looksLikeATestRoot(path)) { + continue; + } + if (!out.contains(path)) { + out.add(path); + } + } + } + + + /// `path` with the project-directory expressions Maven resolves the same way + /// every time applied, or null when an expression is left that this reader + /// cannot resolve. + static String expandProjectPaths(String path, String projectDir) { + return expandProjectPaths(path, projectDir, null); + } + + /// As above; `buildDirectory` is what the POM configures, when it configures + /// one. + /// + /// `${project.build.directory}` is `target` by default and whatever + /// `` says otherwise -- hard-coding `target` sent the + /// search to a directory a project that overrides it does not compile from. + static String expandProjectPaths(String path, String projectDir, String buildDirectory) { + String build = buildDirectory == null || buildDirectory.trim().isEmpty() + ? projectDir + "/target" : buildDirectory.trim().replace('\\', '/'); + if (!build.startsWith("/") && build.indexOf(':') != 1) { + build = projectDir + "/" + build; + } + String out = path; + out = replaceLiteral(out, "${project.basedir}", projectDir); + out = replaceLiteral(out, "${project.baseDir}", projectDir); + out = replaceLiteral(out, "${basedir}", projectDir); + out = replaceLiteral(out, "${pom.basedir}", projectDir); + out = replaceLiteral(out, "${project.build.directory}", build); + return out.indexOf('$') >= 0 ? null : out; + } + + /// The `` the POM's `` element configures, or null. + /// + /// A DIRECT child: `` and the plugin sections carry + /// `` elements of their own, and taking the first one in the + /// build element would read a resource directory as the output directory. + static String configuredBuildDirectory(String pomText) { + if (pomText == null) { + return null; + } + int at = pomText.indexOf(""); + if (at < 0) { + return null; + } + int close = pomText.indexOf("", at); + String build = close < 0 ? pomText.substring(at) : pomText.substring(at, close); + for (String nested : new String[] {"resources", "testResources", "plugins", + "pluginManagement", "filters", "extensions"}) { + build = withoutElement(build, nested); + } + return elementValue(build, "directory"); + } + + private static String withoutElement(String xml, String name) { + String open = "<" + name + ">"; + String shut = ""; + StringBuilder out = new StringBuilder(); + int at = 0; + while (true) { + int hit = xml.indexOf(open, at); + if (hit < 0) { + out.append(xml.substring(at)); + return out.toString(); + } + out.append(xml, at, hit); + int close = xml.indexOf(shut, hit); + if (close < 0) { + return out.toString(); + } + at = close + shut.length(); + } + } + + private static String replaceLiteral(String text, String find, String with) { + StringBuilder out = new StringBuilder(); + int at = 0; + while (true) { + int hit = text.indexOf(find, at); + if (hit < 0) { + out.append(text.substring(at)); + return out.toString(); + } + out.append(text, at, hit).append(with); + at = hit + find.length(); + } + } + + /// Whether a declared path is a test tree, by the same convention the source + /// sets follow: a `test` segment, or one that says test the way + /// `testFixtures` and `integrationTest` do. + private static boolean looksLikeATestRoot(String path) { + for (String segment : com.codename1.util.StringUtil.tokenize(path, "/")) { + if ("test".equals(segment) + || (segment.length() > 4 && segment.startsWith("test") + && Character.isUpperCase(segment.charAt(4))) + || segment.endsWith("Test") || segment.endsWith("Tests")) { + return true; + } + } + return false; + } + + private static java.util.List elementValues(String xml, String name) { + java.util.List out = new java.util.ArrayList<>(); + if (xml == null) { + return out; + } + String open = "<" + name + ">"; + String shut = ""; + int at = xml.indexOf(open); + while (at >= 0) { + int close = xml.indexOf(shut, at + open.length()); + if (close < 0) { + break; + } + out.add(xml.substring(at + open.length(), close)); + at = xml.indexOf(open, close + shut.length()); + } + return out; + } + + /// Those of them that are there, plus whatever the POM declares. + private java.util.List mainSourceRoots(String projectDir) { + FileSystemStorage fs = FileSystemStorage.getInstance(); + // What the launcher resolved, when it did. Reading the POM is guesswork + // by comparison -- it cannot evaluate a profile activation, follow an + // inherited or expand an arbitrary property -- so + // where Maven has already answered, that answer is used. + java.util.List resolved = new java.util.ArrayList<>(); + for (String root : splitRoots(binding == null ? null : binding.sourceRoots())) { + if (fs.isDirectory(ProjectIO.fsUrl(root))) { + resolved.add(root); + } + } + if (!resolved.isEmpty()) { + return resolved; + } + boolean hasSrcMain = projectDir != null + && fs.isDirectory(ProjectIO.fsUrl(projectDir + "/src/main")); + java.util.List candidates = + new java.util.ArrayList<>(candidateSourceRoots(projectDir, hasSrcMain)); + // A module may put its sources somewhere else entirely, and the main + // class is the one file this list cannot afford to miss: without it + // nothing knows which hints an annotation owns, and Add writes the + // duplicate the next build refuses. + // The whole chain: Maven inherits and plugin + // configuration from the parent, and a relative one resolves against + // THIS module rather than the module that declared it. + for (String pom : pomChain()) { + for (String declared : declaredSourceRoots(pom)) { + String expanded = expandProjectPaths(declared, projectDir, buildDirectory(projectDir)); + if (expanded == null) { + continue; + } + String path = expanded.startsWith("/") || expanded.indexOf(':') == 1 + ? normalizePath(expanded) : normalizePath(projectDir + "/" + expanded); + if (!candidates.contains(path)) { + candidates.add(path); + } + } + } + java.util.List out = new java.util.ArrayList<>(); + for (String candidate : candidates) { + if (fs.isDirectory(ProjectIO.fsUrl(candidate))) { + out.add(candidate); + } + } + return out; + } + + /// The bound POM and its ancestors, nearest first. + /// + /// Bounded: a parent chain is short, and this walks the filesystem. + private java.util.List pomChain() { + java.util.List out = new java.util.ArrayList<>(); + String path = binding == null ? null : binding.pom(); + String text = pomText(); + for (int depth = 0; depth < 8 && path != null && text != null; depth++) { + out.add(text); + String parent = parentPomPath(path, text); + if (parent == null || parent.equals(path)) { + break; + } + path = parent; + text = readIfPresentRaw(path); + } + return out; + } + + /// Where `pomText`'s parent POM is, given that it lives at `pomPath`. + /// + /// `` when it says, `../pom.xml` when it does not, which is + /// Maven's own default. Null when the POM declares no parent at all. + static String parentPomPath(String pomPath, String pomText) { + if (pomPath == null || pomText == null || pomText.indexOf("") < 0) { + return null; + } + String relative = elementValue( + pomText.substring(pomText.indexOf("")), "relativePath"); + if (relative == null) { + relative = "../pom.xml"; + } + relative = relative.trim().replace('\\', '/'); + if (relative.isEmpty()) { + // An empty relativePath means "resolve from the repository", which + // this reader cannot do. + return null; + } + if (!relative.endsWith(".xml")) { + relative = relative + "/pom.xml"; + } + int slash = pomPath.replace('\\', '/').lastIndexOf('/'); + String dir = slash < 0 ? "" : pomPath.replace('\\', '/').substring(0, slash); + return normalizePath(dir + "/" + relative); + } + + /// A path with its `.` and `..` segments applied. + static String normalizePath(String path) { + java.util.List parts = new java.util.ArrayList<>(); + boolean absolute = path.startsWith("/"); + for (String segment : com.codename1.util.StringUtil.tokenize(path, "/")) { + if (segment.isEmpty() || ".".equals(segment)) { + continue; + } + if ("..".equals(segment)) { + if (!parts.isEmpty() && !"..".equals(parts.get(parts.size() - 1))) { + parts.remove(parts.size() - 1); + continue; + } + if (absolute) { + continue; + } + } + parts.add(segment); + } + StringBuilder out = new StringBuilder(absolute ? "/" : ""); + for (int i = 0; i < parts.size(); i++) { + if (i > 0) { + out.append('/'); + } + out.append(parts.get(i)); + } + return out.toString(); + } + + /// The roots a binding line names, or empty when it names none. + /// + /// Path-separated, since a comma is legal in a directory name. Both + /// separators are accepted so a binding written on one platform can be read + /// on another, and a bare drive letter is rejoined rather than read as a + /// root of its own. + static java.util.List splitRoots(String joined) { + java.util.List out = new java.util.ArrayList<>(); + if (joined == null || joined.trim().isEmpty()) { + return out; + } + for (String piece : com.codename1.util.StringUtil.tokenize(joined, ":;")) { + String root = piece.trim(); + if (root.isEmpty()) { + continue; + } + // Character.isLetter is outside the Codename One API subset this + // class compiles against, the same reason the name predicate and the + // hex reader are hand-rolled; a drive letter is ASCII anyway. + char first = root.charAt(0); + if (root.length() == 1 + && ((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z'))) { + // `C:/x` tokenizes as `C` then `/x`: the drive letter belongs to + // the path that follows it. + out.add(root + ":"); + continue; + } + if (!out.isEmpty() && out.get(out.size() - 1).endsWith(":")) { + out.set(out.size() - 1, out.get(out.size() - 1) + root); + continue; + } + out.add(root); + } + return out; + } + + /// The build directory the POM chain configures, nearest first, or null for + /// Maven's own default. + private String buildDirectory(String projectDir) { + for (String pom : pomChain()) { + for (String active : activeConfiguration(pom)) { + String configured = configuredBuildDirectory(active); + if (configured == null || configured.trim().isEmpty()) { + continue; + } + // `${project.basedir}/out` is legal and + // resolvable -- discarding it sent the search to `target` for a + // project that compiles somewhere else. Only the basedir family + // is applied here: the value being read IS the build directory, + // so expanding a reference to it would be circular. + String expanded = expandBasedir(configured.trim(), projectDir); + if (expanded != null) { + return expanded; + } + } + } + return null; + } + + /// The basedir family only, which is what a build directory may name. + /// + /// Not `${project.build.directory}`: the value being read IS the build + /// directory, so expanding a reference to it would be circular -- and the + /// general expander resolves that one to `target`, which would quietly make + /// a self-reference mean the default. + static String expandBasedir(String value, String projectDir) { + String out = value; + out = replaceLiteral(out, "${project.basedir}", projectDir); + out = replaceLiteral(out, "${project.baseDir}", projectDir); + out = replaceLiteral(out, "${basedir}", projectDir); + out = replaceLiteral(out, "${pom.basedir}", projectDir); + return out.indexOf('$') >= 0 ? null : out; + } + + /// The bound POM's text, read once per session. + private String pomText() { + if (!pomTextRead) { + pomTextRead = true; + if (binding != null && binding.pom() != null && !binding.pom().isEmpty()) { + pomText = readIfPresentRaw(binding.pom()); + } + } + return pomText; + } + + private boolean pomTextRead; + private String pomText; + + /// The text of every OTHER source in the project, bounded. + /// + /// For the declarations that are not file-scoped and so can decide what a + /// name in the main source means: a `typealias` naming one of our + /// annotations, and a type whose name shadows an on-demand import of one. + /// Java as well as Kotlin, because the second of those is a Java rule too -- + /// a `p/Ios.java` beside the main class is what `@Ios` means there, + /// whatever the wildcard import says. + /// + /// Bounded in files read and in directories walked, because this runs when + /// the tool opens a project and a source tree is not a search index; a + /// project past the bound simply keeps the earlier behaviour for whatever + /// was declared in a file nobody reached. + private java.util.List otherProjectSources(String projectDir, String exclude) { + java.util.List out = new java.util.ArrayList<>(); + if (projectDir == null) { + return out; + } + java.util.List queue = new java.util.ArrayList<>(mainSourceRoots(projectDir)); + for (int i = 0; i < queue.size() && i < 4000 && out.size() < 200; i++) { + String dir = queue.get(i); + String[] children; + try { + children = FileSystemStorage.getInstance().listFiles(ProjectIO.fsUrl(dir)); + } catch (Exception ex) { + continue; + } + if (children == null) { + continue; + } + for (String child : children) { + String name = child.endsWith("/") ? child.substring(0, child.length() - 1) : child; + String path = dir + "/" + name; + if (FileSystemStorage.getInstance().isDirectory(ProjectIO.fsUrl(path))) { + if (!name.startsWith(".")) { + queue.add(path); + } + continue; + } + if (!name.endsWith(".kt") && !name.endsWith(".java")) { + continue; + } + if (path.equals(exclude) || out.size() >= 200) { + continue; + } + String text = readIfPresent(path); + if (text != null) { + boolean kotlinPeer = name.endsWith(".kt"); + // Java's escapes are translated before anything is + // tokenized, so a peer declaring an escaped package name is + // in the package it decodes to -- and reading it literally + // put it in another one, where it shadows nothing. + out.add(new PeerSource( + kotlinPeer ? text : decodeUnicodeEscapes(text), kotlinPeer)); + } + } + } + return out; + } + + /// The text of the file declaring `main` in `pkg`, found by searching, or null. + /// + /// Walks the project for a `.java` or `.kt` file that declares the class, so + /// a configured source root or a Kotlin file whose name differs from its + /// class is found anyway. Bounded in depth and in how many files it will + /// open, because this runs when Settings opens a project and a source tree is + /// not a search index. + private String findMainClassSource(String projectDir, String main, String pkg) { + if (projectDir == null || main == null || main.isEmpty()) { + return null; + } + // Collected first, then examined in two passes. Deciding as we walk made + // the answer depend on directory order: the budget could be spent on + // unrelated files before reaching the one Kotlin source whose name + // differs from its class -- which is the only layout this fallback exists + // for, so exactly the case it would drop. + java.util.List named = new java.util.ArrayList<>(); + java.util.List others = new java.util.ArrayList<>(); + java.util.List queue = new java.util.ArrayList<>(mainSourceRoots(projectDir)); + for (int i = 0; i < queue.size() && i < 4000; i++) { + String dir = queue.get(i); + String[] children; + try { + children = FileSystemStorage.getInstance().listFiles(ProjectIO.fsUrl(dir)); + } catch (Exception ex) { + continue; + } + if (children == null) { + continue; + } + for (String child : children) { + String name = child.endsWith("/") ? child.substring(0, child.length() - 1) : child; + String path = dir + "/" + name; + if (FileSystemStorage.getInstance().isDirectory(ProjectIO.fsUrl(path))) { + // The same roots as the peer sweep, so the two cannot + // disagree about where this module's sources are. + if (!name.startsWith(".")) { + queue.add(path); + } + continue; + } + if (name.equals(main + ".java") || name.equals(main + ".kt")) { + named.add(path); + } else if (name.endsWith(".kt")) { + // Only Kotlin: Java requires a public type to be named after + // its file, so a differently named .java cannot declare the + // main class of an application. + others.add(path); + } + } + } + String hit = firstDeclaring(named, main, pkg, named.size()); + return hit != null ? hit : firstDeclaring(others, main, pkg, 400); + } + + + /// The text of the first of `paths` that declares `main` in `pkg`, opening at + /// most `budget` of them. + private String firstDeclaring(java.util.List paths, String main, String pkg, + int budget) { + int opened = 0; + for (String path : paths) { + if (opened++ >= budget) { + return null; + } + String text = readIfPresent(path); + if (text != null && !path.endsWith(".kt")) { + text = decodeUnicodeEscapes(text); + } + if (text == null || !declaresClass(text, main, pkg, path.endsWith(".kt"))) { + continue; + } + lastSourceWasKotlin = path.endsWith(".kt"); + lastSourcePath = path; + return text; + } + return null; + } + + /// Whether `text` declares `main` in `pkg`, judged by the package statement + /// and a `class`/`object` declaration rather than by where the file sits. + static boolean declaresClass(String text, String main, String pkg) { + return declaresClass(text, main, pkg, true); + } + + /// Whether `text` declares `main` in `pkg`, judged by the package statement + /// and a `class`/`object` declaration rather than by where the file sits. + /// + /// Found in CODE: a `// class Main` left over from an edit, or those words + /// inside a string, would otherwise make an unrelated file answer for the + /// main class -- ownership then reads as empty and Settings offers Add for a + /// hint the real main class already annotates. + /// The package `source` declares, or "" for the default package. + static String declaredPackageIn(String text, boolean kotlin) { + int pkgAt = nextMarker(text, "package", 0, kotlin); + while (pkgAt >= 0) { + int after = pkgAt + "package".length(); + if (after < text.length() && !continuesAName(text.charAt(after)) + && (pkgAt == 0 || !continuesAName(text.charAt(pkgAt - 1)))) { + return qualifiedNameAt(text, after, kotlin); + } + pkgAt = nextMarker(text, "package", after, kotlin); + } + return ""; + } + + static boolean declaresClass(String text, String main, String pkg, boolean kotlin) { + String declaredPkg = ""; + int pkgAt = nextMarker(text, "package", 0, kotlin); + while (pkgAt >= 0) { + int after = pkgAt + "package".length(); + if (after < text.length() && !continuesAName(text.charAt(after)) + && (pkgAt == 0 || !continuesAName(text.charAt(pkgAt - 1)))) { + // Live tokens, as the processor-side helper reads it. + // `package /* generated */ com.example;` is legal, and taking the + // remainder of the text and trimming it started the name at the + // comment -- so the real main source was rejected by both the + // conventional lookup and the fallback search. + // Component by component, exactly as the import reader does. + // `package com /* generated */ . example;` is legal, and reading + // the name as one contiguous run recorded `com` and rejected the + // real main source. + declaredPkg = qualifiedNameAt(text, after, kotlin); + break; + } + pkgAt = nextMarker(text, "package", after, kotlin); + } + if (!(pkg == null || pkg.isEmpty() ? "" : pkg).equals(declaredPkg)) { + return false; + } + // At the TOP level. An application's main class is not nested, and + // accepting a nested one let an unrelated `class Outer { class Main }` + // in the same package end the search on the wrong file -- so the + // annotations on the real main class were never read, and Settings + // offered Add for a hint that is already annotated. + int depth = 0; + int i = 0; + while (i < text.length()) { + char c = text.charAt(i); + if (c == '"' || c == '\'' || c == '/' || c == '`') { + int skipped = skipNonCode(text, i, kotlin); + if (skipped > i) { + i = skipped; + continue; + } + } + if (c == '{') { + depth++; + i++; + continue; + } + if (c == '}') { + depth--; + i++; + continue; + } + if (depth != 0 || !continuesAName(c) + || (i > 0 && continuesAName(text.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < text.length() && continuesAName(text.charAt(wordEnd))) { + wordEnd++; + } + String word = text.substring(i, wordEnd); + if ("class".equals(word) || "object".equals(word)) { + // Every legal separator, not just a space: `class\nMain` and + // `class /* why */ Main` are both valid Java and Kotlin, and + // stopping at a newline read the declaration as unnamed. + int n = nextLiveChar(text, wordEnd, kotlin); + if (n >= 0) { + // Kotlin lets the name be ESCAPED in backticks, and the + // binary name -- which is what codename1.mainName holds -- + // is the text between them. Reading it with the identifier + // rule recorded an empty name, so the real main source was + // rejected, nothing knew which hints an annotation already + // owns, and Settings offered Add for one of them. + int end = n; + String declared; + if (kotlin && text.charAt(n) == '`') { + int close = text.indexOf('`', n + 1); + declared = close < 0 ? null : text.substring(n + 1, close); + } else { + while (end < text.length() && continuesAName(text.charAt(end))) { + end++; + } + declared = text.substring(n, end); + } + if (main.equals(declared)) { + return true; + } + } + } + i = wordEnd; + } + return false; + } + + /// The POM as bytes-to-ISO-8859-1, used only to find the encoding + /// declaration -- which is ASCII wherever it appears. + private String readIfPresentRaw(String path) { + InputStream in = null; + try { + String url = ProjectIO.fsUrl(path); + FileSystemStorage fs = FileSystemStorage.getInstance(); + if (!fs.exists(url)) { + return null; + } + in = fs.openInputStream(url); + return new String(Util.readInputStream(in), "ISO-8859-1"); + } catch (Exception ex) { + return null; + } finally { + Util.cleanup(in); + } + } + + private String readIfPresent(String path) { + InputStream in = null; + try { + String url = ProjectIO.fsUrl(path); + FileSystemStorage fs = FileSystemStorage.getInstance(); + if (!fs.exists(url)) { + return null; + } + in = fs.openInputStream(url); + byte[] bytes = Util.readInputStream(in); + // What the project SAYS it is written in, when it says. The guess + // below can only tell UTF-8 from a single-byte encoding, so a + // multibyte one such as Shift_JIS came back as mojibake and its + // non-ASCII names never matched. + String declared = declaredSourceEncoding(); + if (declared != null) { + try { + return new String(bytes, declared); + } catch (Exception unsupported) { + // Named an encoding this runtime does not have. Guessing is + // better than failing to read the file at all. + } + } + // UTF-8 where the file is UTF-8, which is the overwhelming case; + // ISO-8859-1 where it is not, since that never fails to decode. The + // compiler's source encoding is a project setting this tool does not + // have, and decoding a single-byte source as UTF-8 produced + // replacement characters -- so a non-ASCII package or class name + // never matched codename1.packageName, the real main source was + // rejected, and a hint an annotation owns read as editable. + return new String(bytes, isValidUtf8(bytes) ? "UTF-8" : "ISO-8859-1"); + } catch (Exception ex) { + Log.e(ex); + return null; + } finally { + Util.cleanup(in); + } + } + + /// The index just past the dotted name starting at or after `from`, or + /// `from` when there is none. The same walk as `qualifiedNameAt`, so the two + /// cannot disagree about where a name ends. + static int qualifiedNameEnd(String source, int from, boolean kotlin) { + int i = nextLiveChar(source, from, kotlin); + int end = from; + while (i >= 0 && i < source.length()) { + int stop = componentEnd(source, i, kotlin); + if (stop == i) { + return end; + } + end = stop; + int dot = nextLiveChar(source, stop, kotlin); + if (dot < 0 || source.charAt(dot) != '.') { + return end; + } + i = nextLiveChar(source, dot + 1, kotlin); + } + return end; + } + + /// The dotted name starting at or after `from`, stepping over whitespace and + /// comments around each dot. + /// The end of the name component at `i`, or `i` when there is none. + /// + /// A Kotlin component may be ESCAPED in backticks -- `package com.`when`` + /// is legal and the class belongs to com.when. Reading only identifier + /// characters stopped at the backtick and recorded `com.`, so the real main + /// source was rejected: nothing then knew which hints an annotation already + /// owns, and Settings could write the duplicate properties declaration that + /// the next build rejects. + private static int componentEnd(String source, int i, boolean kotlin) { + if (kotlin && i < source.length() && source.charAt(i) == '`') { + int close = source.indexOf('`', i + 1); + return close < 0 ? i : close + 1; + } + int end = i; + while (end < source.length() && continuesAName(source.charAt(end))) { + end++; + } + return end; + } + + /// That component's text, which is what the backticks quote rather than + /// include. + private static String componentText(String source, int i, int end, boolean kotlin) { + if (kotlin && i < end && source.charAt(i) == '`') { + return source.substring(i + 1, end - 1); + } + return source.substring(i, end); + } + + static String qualifiedNameAt(String source, int from, boolean kotlin) { + int i = nextLiveChar(source, from, kotlin); + StringBuilder name = new StringBuilder(); + while (i >= 0 && i < source.length()) { + int end = componentEnd(source, i, kotlin); + if (end == i) { + break; + } + name.append(componentText(source, i, end, kotlin)); + int dot = nextLiveChar(source, end, kotlin); + if (dot < 0 || source.charAt(dot) != '.') { + break; + } + name.append('.'); + i = nextLiveChar(source, dot + 1, kotlin); + } + return name.toString(); + } + + /// One import directive: the dotted name it introduces and its alias, if any. + static final class Imported { + final String name; + final String alias; + + Imported(String name, String alias) { + this.name = name; + this.alias = alias; + } + } + + /// Every live `import` in `source`, read FORWARDS. + /// + /// Forwards rather than by backing up from a name, because backing up has to + /// step over comments in reverse -- and + /// `import /* build hints */ com.codename1.annotations.buildhints.Ios;` is + /// legal, so a backward walk that skipped only spaces missed the import and + /// the live @Ios was read as somebody else's. + static java.util.List importsIn(String source, boolean kotlin) { + java.util.List out = new java.util.ArrayList<>(); + int at = nextMarker(source, "import", 0, kotlin); + while (at >= 0) { + int after = at + "import".length(); + boolean whole = (at == 0 || !continuesAName(source.charAt(at - 1))) + && after < source.length() && !continuesAName(source.charAt(after)); + if (!whole) { + at = nextMarker(source, "import", after, kotlin); + continue; + } + int i = nextLiveChar(source, after, kotlin); + if (i < 0) { + return out; + } + // Java's optional `static`, which is a modifier and not the imported + // name. Reading it as the name recorded an import called `static`, + // so `import static com.example.Types.Ios;` never registered as + // giving `Ios` away -- a wildcard import of ours was trusted instead + // and the editor was hidden for a hint the processor never emits. + if (!kotlin && source.startsWith("static", i) + && i + 6 < source.length() && !continuesAName(source.charAt(i + 6))) { + int afterStatic = nextLiveChar(source, i + 6, kotlin); + if (afterStatic >= 0) { + i = afterStatic; + } + } + // Component by component, stepping over whitespace and comments + // around each dot. `import com.codename1.annotations. /* x */ + // buildhints.Ios;` is legal, and reading the name as one contiguous + // run stopped at the separator and recorded only the prefix -- so the + // import was not recognised and the live @Ios read as somebody + // else's. + StringBuilder name = new StringBuilder(); + while (i >= 0 && i < source.length()) { + if (source.charAt(i) == '*') { + name.append('*'); + i++; + break; + } + // A COMPONENT may be escaped -- `import + // com.codename1.annotations.`buildhints`.Ios` is legal Kotlin. + // Reading only identifier characters recorded `annotations.`, so + // the import went unrecognised and a live @Ios was read as + // somebody else's: Settings then offered the hint as unowned and + // could write the duplicate the next build refuses. + int end = componentEnd(source, i, kotlin); + if (end == i) { + break; + } + name.append(componentText(source, i, end, kotlin)); + int dot = nextLiveChar(source, end, kotlin); + if (dot < 0 || source.charAt(dot) != '.') { + i = end; + break; + } + name.append('.'); + i = nextLiveChar(source, dot + 1, kotlin); + } + if (i < 0) { + i = source.length(); + } + String alias = null; + int a = nextLiveChar(source, i, kotlin); + if (a >= 0 && source.regionMatches(a, "as", 0, 2) + && a + 2 < source.length() && !continuesAName(source.charAt(a + 2))) { + int n = nextLiveChar(source, a + 2, kotlin); + if (n >= 0) { + // The alias may be escaped too: `import a.B as `when``. + int nameEnd = componentEnd(source, n, kotlin); + if (nameEnd > n) { + alias = componentText(source, n, nameEnd, kotlin); + } + } + } + if (name.length() > 0) { + out.add(new Imported(name.toString(), alias)); + } + at = nextMarker(source, "import", i, kotlin); + } + return out; + } + + /// Whether a live import brings `simple` in from the build hints package. + /// + /// Either the type by name or the package on demand, and neither if some + /// other library's type of that name is imported explicitly: a single-type + /// import shadows an on-demand one, so their `Ios` beats our wildcard. That + /// is the language's rule, not a preference. + static boolean importsAnnotation(String source, String simple, boolean kotlin) { + return importsAnnotation(source, simple, kotlin, false); + } + + /// As above; `shadowed` says the same package declares a type of that name. + /// + /// A same-package type beats an ON-DEMAND import in both languages, so a + /// project with its own `Ios` and a wildcard import of ours writes its own + /// -- and reading that as ours hid the editor for a hint the processor never + /// emits. A NAMED import still wins, since it is the more specific statement + /// and a file may not both import a name and declare it. + static boolean importsAnnotation(String source, String simple, boolean kotlin, + boolean shadowed) { + String pkg = "com.codename1.annotations.buildhints."; + boolean ours = false; + for (Imported imported : importsIn(source, kotlin)) { + if (imported.alias != null) { + // Introduces its ALIAS rather than its own name -- so it neither + // grants nor shadows the simple spelling, unless the alias IS + // that spelling. `import com.example.Other as Ios` makes `@Ios` + // mean Other, and ignoring it let a wildcard import of ours be + // trusted instead, hiding the editor for a hint the processor + // never emits. + if (imported.alias.equals(simple)) { + return imported.name.startsWith(pkg); + } + continue; + } + if (imported.name.equals(pkg + simple)) { + return true; + } + if (imported.name.equals(pkg + "*")) { + ours = !shadowed; + } else if (imported.name.endsWith("." + simple)) { + return false; + } + } + return ours; + } + + /// Whether a top-level type named `simple` is declared in `text`. + /// + /// Wider than the main-class lookup on purpose: an annotation is declared + /// with `annotation class` in Kotlin and `@interface` in Java, and any of + /// those shadows an on-demand import of the same name. + static boolean declaresTypeNamed(String text, String simple, boolean kotlin) { + return declaresTypeNamed(text, simple, kotlin, true); + } + + /// As above; `includePrivate` is false for a peer, where a file-private + /// declaration is not a name the main source can see. + /// + /// On a top-level Kotlin declaration `private` means this FILE only, so + /// another file's `private annotation class Ios` shadows nothing -- counting + /// it made a real `@Ios` read as somebody else's, so the hint looked unowned + /// and Add wrote the duplicate the next build refuses. In the main file + /// itself a private type does shadow, because that is the file it belongs + /// to. + static boolean declaresTypeNamed(String text, String simple, boolean kotlin, + boolean includePrivate) { + String modifiers = !includePrivate && kotlin ? blanked(text, kotlin) : null; + int depth = 0; + int i = 0; + while (i < text.length()) { + char c = text.charAt(i); + if (c == '"' || c == '\'' || c == '/' || c == '`') { + int skipped = skipNonCode(text, i, kotlin); + if (skipped > i) { + i = skipped; + continue; + } + } + if (c == '{') { + depth++; + i++; + continue; + } + if (c == '}') { + depth--; + i++; + continue; + } + if (depth != 0 || !continuesAName(c) + || (i > 0 && continuesAName(text.charAt(i - 1)))) { + i++; + continue; + } + int wordEnd = i; + while (wordEnd < text.length() && continuesAName(text.charAt(wordEnd))) { + wordEnd++; + } + String word = text.substring(i, wordEnd); + if ("class".equals(word) || "object".equals(word) || "interface".equals(word) + || "enum".equals(word) || "record".equals(word)) { + int n = nextLiveChar(text, wordEnd, kotlin); + if (n >= 0) { + int end = componentEnd(text, n, kotlin); + if (end > n && componentText(text, n, end, kotlin).equals(simple) + && (modifiers == null || !declaredPrivate(modifiers, i))) { + return true; + } + } + } + i = wordEnd; + } + return false; + } + + + /// The name a Kotlin `typealias Alias = Ios` gives an annotation, or null. + /// + /// Unlike an import alias this renames the type in the file itself, so the + /// annotation never appears under its own name and no import mentions the + /// alias at all. The right-hand side may be the simple name -- which only + /// counts when an import makes it ours -- or the fully qualified one, which + /// needs no import. + /// + /// One level: an alias of an alias is not followed, because the first is + /// what a file that renames our annotation actually writes. + static String kotlinTypeAlias(String source, String simple, boolean kotlin) { + java.util.List all = kotlinTypeAliases(source, simple, kotlin); + return all.isEmpty() ? null : all.get(0); + } + + /// EVERY such name, for the same reason the import form collects them all: + /// a file may declare `typealias First = Ios` and `typealias AppIos = Ios` + /// and use only the second. + static java.util.List kotlinTypeAliases(String source, String simple, + boolean kotlin) { + return kotlinTypeAliases(visibleTypeAliases(source, null), simple, kotlin); + } + + /// Every name that resolves to `simple`, across all of `sources`, following + /// a CHAIN of aliases. + /// + /// `typealias AppIos = Ios` then `typealias CustomIos = AppIos` is legal, + /// and `@CustomIos(...)` still compiles to our annotation. Accepting only a + /// right-hand side that names the annotation directly left the hint reading + /// as unowned, so Add wrote the duplicate declaration the next build + /// refuses. Resolved by closure rather than by recursion so that a cycle -- + /// which the compiler rejects, but this reader must not hang on -- simply + /// stops adding names. + /// A `typealias`, with where it was written and the name the main file sees + /// it under. + /// + /// The two names differ because an import may rename it: `import + /// com.other.AppIos as Custom` makes `com.other`'s `AppIos` usable only as + /// `Custom`, so the file that declares it and the file that writes the + /// annotation disagree about what it is called. + static final class AliasDeclaration { + /// The name in the file that declares it, which its own chain uses. + final String local; + /// The name the main file writes, or null when it cannot see this one. + final String visible; + final String target; + /// The package it is declared in, which is the scope its chain resolves + /// in -- a chain may span files, but only within one package. + final String scope; + /// The text that declares it, whose imports decide what its target names. + final String owner; + + AliasDeclaration(String local, String visible, String target, String scope, String owner) { + this.local = local; + this.visible = visible; + this.target = target; + this.scope = scope; + this.owner = owner; + } + } + + /// Whether `word` is a modifier that may sit between `private` and the + /// keyword it belongs to. + /// + /// A class carries more of them than a typealias does -- `private + /// annotation class Ios` is the shape that matters here -- and stopping at + /// the first one not on this list is what keeps a `private` belonging to an + /// earlier declaration from being read as this one's. + private static boolean isDeclarationModifier(String word) { + return "public".equals(word) || "internal".equals(word) || "protected".equals(word) + || "actual".equals(word) || "expect".equals(word) + || "annotation".equals(word) || "data".equals(word) || "enum".equals(word) + || "sealed".equals(word) || "open".equals(word) || "abstract".equals(word) + || "final".equals(word) || "inner".equals(word) || "value".equals(word) + || "inline".equals(word) || "external".equals(word); + } + + /// The source encoding the POM declares, or null when it declares none. + /// + /// Read once per session: this is asked for every source file the sweeps + /// open, and the answer cannot change while the project is bound. + private String declaredSourceEncoding() { + if (!sourceEncodingRead) { + sourceEncodingRead = true; + // What the launcher resolved, when it did: Maven has already applied + // the profiles, the inheritance and the properties that this reader + // can only approximate. + if (binding != null && binding.sourceEncoding() != null + && !binding.sourceEncoding().isEmpty()) { + sourceEncoding = binding.sourceEncoding(); + return sourceEncoding; + } + // The chain, not the module alone: `project.build.sourceEncoding` + // is normally declared once in the parent, which is where a + // multi-module Codename One project puts it -- so looking only at + // the bound POM found nothing in the standard layout. + for (String pom : pomChain()) { + for (String active : activeConfiguration(pom)) { + sourceEncoding = declaredSourceEncoding(active); + if (sourceEncoding != null) { + break; + } + } + if (sourceEncoding != null) { + break; + } + } + } + return sourceEncoding; + } + + private boolean sourceEncodingRead; + private String sourceEncoding; + + /// The encoding `pomText` declares: the conventional property first, then + /// the compiler plugin's own setting. + /// + /// A string read rather than an XML model, which is how this tool handles + /// POMs everywhere else. It is looking for one value that is written as a + /// plain element in both places. + static String declaredSourceEncoding(String pomText) { + if (pomText == null) { + return null; + } + String value = elementValue(pomText, "project.build.sourceEncoding"); + if (value == null) { + value = elementValue(pomText, "maven.compiler.encoding"); + } + if (value == null) { + // Inside the COMPILER plugin. maven-resources-plugin declares an + // of its own, and taking the first one in the file + // adopted the resource charset for every source -- so a UTF-8 source + // with a differently encoded resources block was read as neither. + value = elementValue(pluginBlock(pomText, "maven-compiler-plugin"), "encoding"); + } + if (value == null || value.trim().isEmpty() || value.indexOf('$') >= 0) { + // An unresolved ${property} is not an encoding, and this reader has + // no model to resolve it against. + return null; + } + return value.trim(); + } + + /// The `` element declaring `artifactId`, or null. + static String pluginBlock(String pomText, String artifactId) { + if (pomText == null) { + return null; + } + int at = pomText.indexOf("" + artifactId + ""); + if (at < 0) { + return null; + } + int open = pomText.lastIndexOf("", at); + int close = pomText.indexOf("", at); + if (open < 0 || close < 0) { + return null; + } + return pomText.substring(open, close); + } + + private static String elementValue(String xml, String name) { + if (xml == null) { + return null; + } + String open = "<" + name + ">"; + int at = xml.indexOf(open); + if (at < 0) { + return null; + } + int close = xml.indexOf("", at + open.length()); + return close < 0 ? null : xml.substring(at + open.length(), close); + } + + /// Whether `bytes` decode as UTF-8. + /// + /// Hand-rolled because CharsetDecoder is outside the Codename One API + /// subset this class compiles against, the same reason the name predicate + /// and the hex reader are. + static boolean isValidUtf8(byte[] bytes) { + int i = 0; + while (i < bytes.length) { + int b = bytes[i] & 0xFF; + int following; + int lowest; + int payload; + if (b < 0x80) { + i++; + continue; + } else if (b >= 0xC2 && b <= 0xDF) { + following = 1; + lowest = 0x80; + payload = 0x1F; + } else if (b >= 0xE0 && b <= 0xEF) { + following = 2; + lowest = 0x800; + payload = 0x0F; + } else if (b >= 0xF0 && b <= 0xF4) { + following = 3; + lowest = 0x10000; + payload = 0x07; + } else { + return false; + } + if (i + following >= bytes.length) { + return false; + } + int value = b & payload; + for (int n = 1; n <= following; n++) { + int next = bytes[i + n] & 0xFF; + if (next < 0x80 || next > 0xBF) { + return false; + } + value = (value << 6) | (next & 0x3F); + } + // Overlong, and the surrogate range, which UTF-8 does not encode. + if (value < lowest || value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF)) { + return false; + } + i += following + 1; + } + return true; + } + + /// `source` with its comments and literals replaced by spaces, offsets and + /// line breaks preserved. + /// + /// For reading BACKWARDS, which the forward scanner cannot help with: + /// `private /* note */ typealias AppIos = Ios` is legal, and a backward walk + /// that skips only whitespace stops at the comment and reports the + /// declaration as public. + private static String blanked(String source, boolean kotlin) { + char[] out = source.toCharArray(); + int i = 0; + while (i < out.length) { + char c = out[i]; + if (c != '"' && c != '\'' && c != '/' && c != '`') { + i++; + continue; + } + int end = skipNonCode(source, i, kotlin); + if (end <= i) { + i++; + continue; + } + while (i < end) { + if (out[i] != '\n' && out[i] != '\r') { + out[i] = ' '; + } + i++; + } + } + return new String(out); + } + + /// Whether the declaration at `at` carries the `private` modifier. + /// + /// Read backwards over the modifiers that may precede the keyword, stopping + /// at anything that is not one -- so a `private` belonging to whatever came + /// before this declaration is not read as this one's. + private static boolean declaredPrivate(String source, int at) { + int i = at; + for (int word = 0; word < 8; word++) { + int end = i; + while (end > 0 && (source.charAt(end - 1) == ' ' || source.charAt(end - 1) == '\t' + || source.charAt(end - 1) == '\n' || source.charAt(end - 1) == '\r')) { + end--; + } + int start = end; + while (start > 0 && continuesAName(source.charAt(start - 1))) { + start--; + } + if (start == end) { + return false; + } + String modifier = source.substring(start, end); + if ("private".equals(modifier)) { + return true; + } + if (!isDeclarationModifier(modifier)) { + return false; + } + i = start; + } + return false; + } + + /// Another source file, with the language it is written in. + /// + /// The language travels with the text because it changes what the text + /// MEANS: raw strings close differently, block comments nest in one and not + /// the other, and Java translates unicode escapes before it tokenizes -- so + /// a Java peer declaring `package \u0070;` is in package p, which a + /// Kotlin-mode read cannot see. + static final class PeerSource { + final String text; + final boolean kotlin; + + PeerSource(String text, boolean kotlin) { + this.text = text; + this.kotlin = kotlin; + } + } + + /// Peers written in one language, which is what a caller that has plain + /// texts means by them. + static java.util.List peers(java.util.List texts, boolean kotlin) { + java.util.List out = new java.util.ArrayList<>(); + if (texts != null) { + for (String text : texts) { + if (text != null) { + out.add(new PeerSource(text, kotlin)); + } + } + } + return out; + } + + /// Every `typealias` `mainSource` can see, with the name it sees it under. + /// + /// Visibility is per SYMBOL, not per package: `import com.other.Unrelated` + /// exposes nothing else from `com.other`, and `import com.other.AppIos as + /// Custom` exposes that one under `Custom`. Reducing this to "does the main + /// file import anything from that package" was wrong in both directions -- + /// it let an unrelated import expose an alias that hides the editor for a + /// hint nothing owns, and it lost the local name of a renamed one so a real + /// annotation went unrecognised and Add wrote the duplicate. + static java.util.List visibleTypeAliases(String mainSource, + java.util.List others) { + return visibleTypeAliases(mainSource, peers(others, true), true); + } + + static java.util.List visibleTypeAliases(String mainSource, + java.util.List others, + boolean kotlin) { + java.util.List out = new java.util.ArrayList<>(); + if (mainSource == null) { + return out; + } + String mainPkg = declaredPackageIn(mainSource, kotlin); + for (String[] declared : typeAliasDeclarations(mainSource, kotlin)) { + out.add(new AliasDeclaration(declared[0], declared[0], declared[1], mainPkg, + mainSource)); + } + if (others == null) { + return out; + } + java.util.List imports = importsIn(mainSource, kotlin); + for (PeerSource peer : others) { + String other = peer == null ? null : peer.text; + if (other == null) { + continue; + } + String pkg = declaredPackageIn(other, peer.kotlin); + boolean samePackage = pkg.equals(mainPkg); + for (String[] declared : typeAliasDeclarations(other, peer.kotlin)) { + if ("private".equals(declared[2])) { + // On a top-level Kotlin declaration `private` means this FILE + // only, not this package -- so another file's is not a name + // the main source can write, and treating it as one let it + // vouch for an unrelated annotation of the same name and hide + // the editor for a hint nothing owns. + continue; + } + String visible = samePackage ? declared[0] + : importedNameOf(imports, pkg, declared[0]); + // Kept even when invisible: it may still be a LINK in a chain + // whose visible end is imported, and that chain resolves in the + // package it is written in. + out.add(new AliasDeclaration(declared[0], visible, declared[1], pkg, other)); + } + } + return out; + } + + /// The name `imports` gives `pkg`.`simple`, or null when none of them does. + /// + /// A named import wins over an on-demand one, since it is the more specific + /// statement about that symbol and may rename it. + private static String importedNameOf(java.util.List imports, String pkg, + String simple) { + String qualified = pkg == null || pkg.isEmpty() ? simple : pkg + "." + simple; + String onDemand = null; + for (Imported imported : imports) { + if (imported.name.equals(qualified)) { + return imported.alias != null ? imported.alias : simple; + } + if (imported.name.equals(pkg + ".*")) { + onDemand = simple; + } + } + return onDemand; + } + + /// Every name that resolves to `simple`, following a CHAIN of aliases. + /// + /// `typealias AppIos = Ios` then `typealias CustomIos = AppIos` is legal, + /// and `@CustomIos(...)` still compiles to our annotation. Accepting only a + /// right-hand side that names the annotation directly left the hint reading + /// as unowned, so Add wrote the duplicate declaration the next build + /// refuses. Resolved by closure rather than by recursion so that a cycle -- + /// which the compiler rejects, but this reader must not hang on -- simply + /// stops adding names. + /// + /// The chain is followed by the LOCAL name within one package, which is the + /// scope a top-level declaration resolves in, and only names the main file + /// can actually see are returned. + static java.util.List kotlinTypeAliases(java.util.List declarations, + String simple, boolean kotlin) { + java.util.List out = new java.util.ArrayList(); + if (!kotlin || declarations == null) { + return out; + } + String qualified = "com.codename1.annotations.buildhints." + simple; + java.util.List resolved = new java.util.ArrayList(); + java.util.List pending = new java.util.ArrayList<>(); + // The key each pending declaration's target might name, worked out once + // rather than on every pass. + java.util.List> pendingTargets = new java.util.ArrayList<>(); + for (AliasDeclaration declared : declarations) { + // The bare name counts only where an import makes it ours, and that + // import is file-scoped -- so it is decided per owner, here, rather + // than once for the whole sweep. `import ...Ios as Base` then + // `typealias AppIos = Base` is the same point one step along. + boolean imported = importsAnnotation(declared.owner, simple, kotlin); + java.util.List importedAs = kotlinImportAliases(declared.owner, simple, kotlin); + if (declared.target.equals(qualified) + || (imported && declared.target.equals(simple)) + || importedAs.contains(declared.target)) { + add(resolved, declared.scope + "\u0000" + declared.local); + add(out, declared.visible); + } else { + pending.add(declared); + pendingTargets.add(targetKeys(declared)); + } + } + // Each pass can only resolve one more link, so the number of passes is + // bounded by the number of declarations left over. + for (int pass = 0; pass < pending.size(); pass++) { + boolean grew = false; + for (int i = 0; i < pending.size(); i++) { + AliasDeclaration declared = pending.get(i); + String key = declared.scope + "\u0000" + declared.local; + if (resolved.contains(key)) { + continue; + } + for (String candidate : pendingTargets.get(i)) { + if (resolved.contains(candidate)) { + resolved.add(key); + add(out, declared.visible); + grew = true; + break; + } + } + } + if (!grew) { + break; + } + } + return out; + } + + /// The chain links `declared`'s target might name, most specific first. + /// + /// A link may cross a package boundary: package `a` declares + /// `typealias Base = Ios`, package `b` imports `a.Base` and declares + /// `typealias AppIos = Base`. Looking only in the declaring file's own + /// package missed that, so the chain stopped there, the hint read as unowned + /// and Add wrote the duplicate declaration the next build refuses. + /// + /// A qualified target names its package outright. Otherwise a named import + /// -- under its own name or an `as` name -- says where it comes from, and + /// failing that it is the declaring package's own, or any package imported + /// on demand. + private static java.util.List targetKeys(AliasDeclaration declared) { + java.util.List out = new java.util.ArrayList(); + String target = declared.target; + int dot = target.lastIndexOf('.'); + if (dot > 0) { + out.add(target.substring(0, dot) + "\u0000" + target.substring(dot + 1)); + return out; + } + java.util.List onDemand = new java.util.ArrayList(); + for (Imported imported : importsIn(declared.owner, true)) { + int at = imported.name.lastIndexOf('.'); + if (at <= 0) { + continue; + } + String pkg = imported.name.substring(0, at); + String simpleName = imported.name.substring(at + 1); + if ("*".equals(simpleName)) { + onDemand.add(pkg + "\u0000" + target); + continue; + } + String visibleAs = imported.alias != null ? imported.alias : simpleName; + if (visibleAs.equals(target)) { + out.add(pkg + "\u0000" + simpleName); + return out; + } + } + out.add(declared.scope + "\u0000" + target); + out.addAll(onDemand); + return out; + } + + private static void add(java.util.List out, String value) { + if (value != null && !out.contains(value)) { + out.add(value); + } + } + + /// Every `typealias Name = Target` in `source`, as {name, target, private}. + /// + /// The third element is "private" when the declaration carries that + /// modifier, which on a top-level Kotlin declaration means visible in this + /// FILE only -- not in the package. + static java.util.List typeAliasDeclarations(String source, boolean kotlin) { + java.util.List out = new java.util.ArrayList(); + if (!kotlin || source == null) { + return out; + } + int at = nextMarker(source, "typealias", 0, kotlin); + while (at >= 0) { + int after = at + "typealias".length(); + boolean whole = (at == 0 || !continuesAName(source.charAt(at - 1))) + && after < source.length() && !continuesAName(source.charAt(after)); + if (whole) { + int n = nextLiveChar(source, after, kotlin); + if (n >= 0) { + int end = componentEnd(source, n, kotlin); + if (end > n) { + String name = componentText(source, n, end, kotlin); + int eq = nextLiveChar(source, end, kotlin); + if (eq >= 0 && source.charAt(eq) == '=') { + out.add(new String[] {name, qualifiedNameAt(source, eq + 1, kotlin), + declaredPrivate(blanked(source, kotlin), at) + ? "private" : ""}); + } + } + } + } + at = nextMarker(source, "typealias", after, kotlin); + } + return out; + } + + /// The name a Kotlin `import ... as Alias` gives an annotation, or null. + /// + /// Kotlin lets a file rename what it imports, and then the annotation never + /// appears under its own name anywhere in the source. Missing that reads the + /// hint as unowned, so Settings offers it for Add, writes the properties + /// line, and the next `process-annotations` fails on the duplicate the tool + /// itself created. + static String kotlinImportAlias(String source, String simple, boolean kotlin) { + java.util.List all = kotlinImportAliases(source, simple, kotlin); + return all.isEmpty() ? null : all.get(0); + } + + /// EVERY such name. A file may import the same annotation twice under + /// different aliases, and answering with the first left the other + /// unrecognised -- so the hint read as unowned, Settings offered Add, and + /// the next build failed on the duplicate the tool had just written. + static java.util.List kotlinImportAliases(String source, String simple, + boolean kotlin) { + String needle = "com.codename1.annotations.buildhints." + simple; + java.util.List out = new java.util.ArrayList(); + for (Imported imported : importsIn(source, kotlin)) { + if (imported.alias != null && needle.equals(imported.name)) { + out.add(imported.alias); + } + } + return out; + } + + /// Maps every `@Group(attr = ...)` on the main class to the hints it sets. + /// Java rules for the source text; see the three-argument form. + static void collectAnnotationOwnedHints(String source, java.util.Map out) { + collectAnnotationOwnedHints(source, out, false); + } + + static void collectAnnotationOwnedHints(String source, java.util.Map out, + boolean kotlin) { + collectAnnotationOwnedHints(source, out, kotlin, null); + } + + /// As above, also resolving `typealias` declarations made in OTHER files. + /// + /// A typealias is a top-level declaration, not a file-scoped one: a project + /// may declare `typealias AppIos = Ios` in one file and write `@AppIos(...)` + /// on the main class in another. Looking only at the main source read the + /// hint as unowned, so Add wrote the duplicate declaration the next build + /// refuses. An import alias is NOT collected this way -- that one applies + /// only to the file that writes it. + static void collectAnnotationOwnedHints(String source, java.util.Map out, + boolean kotlin, + java.util.List otherSources) { + collectOwnedHints(source, out, kotlin, peers(otherSources, kotlin)); + } + + static void collectOwnedHints(String source, java.util.Map out, + boolean kotlin, java.util.List otherSources) { + // Once, not once per hint: which aliases exist and what the main file + // calls them does not depend on which hint is being asked about. + java.util.List declaredAliases = + kotlin ? visibleTypeAliases(source, otherSources, kotlin) + : new java.util.ArrayList(); + // The sources whose top-level types could shadow an on-demand import: + // this file, and the rest of its package. Each is read in the language + // it is written in, since that decides what its text means -- a Java + // peer's unicode escapes among other things. + java.util.List samePackage = new java.util.ArrayList<>(); + samePackage.add(new PeerSource(source, kotlin)); + if (otherSources != null) { + String mainPkg = declaredPackageIn(source, kotlin); + for (PeerSource peer : otherSources) { + if (peer != null && peer.text != null + && declaredPackageIn(peer.text, peer.kotlin).equals(mainPkg)) { + samePackage.add(peer); + } + } + } + for (com.codename1.build.shared.BuildHints.Hint h : com.codename1.build.shared.BuildHints.entries()) { + if (!h.isAnnotated()) { + continue; + } + String simple = h.group().annotationSimpleName(); + // Three spellings are valid: the imported simple name, the fully + // qualified one, which needs no import, and a Kotlin alias, under + // which the annotation's own name appears nowhere. Missing any of + // them leaves the hint editable and Add writes the duplicate. + java.util.List aliases = kotlinImportAliases(source, simple, kotlin); + // A fourth: Kotlin can rename a type in the FILE, with no import + // involved -- `typealias AppIos = Ios` and then `@AppIos(...)`. The + // compiled annotation is still ours, so missing it left the hint + // editable and Add wrote the duplicate the next build refuses. + // One closure over every source, not one per file: a chain may cross + // files, with the link that names our annotation in one and the link + // that the main class writes in another. + aliases.addAll(kotlinTypeAliases(declaredAliases, simple, kotlin)); + // The simple name only counts when an import makes it OUR annotation. + // @Build and @Android are ordinary enough names that another library's + // annotation with a matching attribute would otherwise be read as + // ownership -- and Settings would hide the editor for a hint the + // processor never emits, which is indistinguishable from the tool + // being broken. + boolean shadowed = false; + boolean first = true; + for (PeerSource peer : samePackage) { + // The first entry is the main source itself, where a private + // type is in the file it belongs to and does shadow. + boolean own = first; + first = false; + if (declaresTypeNamed(peer.text, simple, peer.kotlin, own)) { + shadowed = true; + break; + } + } + boolean imported = importsAnnotation(source, simple, kotlin, shadowed); + String qualified = "com.codename1.annotations.buildhints." + simple; + + // Every `@` that is real code, with the name after it read component + // by component. Matching literal strings could not see + // `@com.codename1.annotations. /* generated */ buildhints.Ios`, which + // is legal -- ownership then read as empty and Add wrote the + // duplicate. + int at = nextMarker(source, "@", 0, kotlin); + boolean found = false; + while (at >= 0 && !found) { + String name = qualifiedNameAt(source, at + 1, kotlin); + int after = qualifiedNameEnd(source, at + 1, kotlin); + boolean ours = (imported && name.equals(simple)) + || name.equals(qualified) + || aliases.contains(name); + if (ours) { + int open = nextLiveChar(source, after, kotlin); + if (open >= 0 && source.charAt(open) == '(') { + String args = balancedArgs(source, open, kotlin); + if (args != null && declaresAttribute(args, h.attr(), kotlin)) { + out.put(com.codename1.build.shared.BuildHints.canonicalName(h.name()), + "@" + simple + "(" + h.attr() + ")"); + found = true; + break; + } + } + } + at = nextMarker(source, "@", at + 1, kotlin); + } + } + } + + /// The text inside the parentheses starting at `open`, or null when unbalanced. + /// + /// Skips strings, character literals and comments. A comment inside an + /// annotation can carry an unmatched delimiter -- + /// `@Ios(/* required for issue ( */ teamId = "x")` -- and counting it as + /// syntax loses the annotation's boundary, leaving an owned hint editable. + private static String balancedArgs(String source, int open, boolean kotlin) { + int depth = 0; + for (int i = open; i < source.length(); i++) { + int skipped = skipNonCode(source, i, kotlin); + if (skipped > i) { + i = skipped - 1; + continue; + } + char c = source.charAt(i); + if (c == '(' || c == '{' || c == '[') { + depth++; + } else if (c == ')' || c == '}' || c == ']') { + depth--; + if (depth == 0) { + return source.substring(open + 1, i); + } + } + } + return null; + } + + /// Whether `args` assigns `attr` at the top level, ignoring anything inside a + /// nested value, a string, a character literal or a comment. + private static boolean declaresAttribute(String args, String attr, boolean kotlin) { + int depth = 0; + StringBuilder word = new StringBuilder(); + for (int i = 0; i < args.length(); i++) { + int skipped = skipNonCode(args, i, kotlin); + if (skipped > i) { + i = skipped - 1; + continue; + } + char c = args.charAt(i); + if (c == '(' || c == '{' || c == '[') { + depth++; + } else if (c == ')' || c == '}' || c == ']') { + depth--; + } else if (depth == 0 && c == '=' + && (i + 1 >= args.length() || args.charAt(i + 1) != '=')) { + if (word.toString().trim().equals(attr)) { + return true; + } + word.setLength(0); + } else if (depth == 0 && c == ',') { + word.setLength(0); + } else if (depth == 0) { + word.append(c); + } + } + return false; + } + + /// Whether `c` could continue a Java identifier. + /// + /// Hand-rolled because Character.isJavaIdentifierPart is outside the + /// Codename One API subset, and this class is compiled as app code. + /// Java's unicode escapes, applied. + /// + /// javac processes `\\uXXXX` in the LEXICAL TRANSLATION step, before it + /// tokenizes anything, so `package com.ex\\u0061mple;` really declares + /// com.example and an escape works inside an identifier. Reading the text + /// literally recorded `com.ex`, so the real main source was rejected, + /// nothing knew which hints an annotation already owns, and Add could write + /// the duplicate declaration the next build refuses. + /// + /// A backslash only opens an escape when an EVEN number of backslashes + /// precedes it, which is what keeps a string literal spelling one. Kotlin + /// has no such step, so this is applied to Java only. + /// + /// Safe here because this tool never writes a source file back -- it edits + /// codenameone_settings.properties and the POM -- so nothing depends on an + /// offset into the text as it is on disk. + static String decodeUnicodeEscapes(String text) { + if (text == null || text.indexOf('\\') < 0) { + return text; + } + StringBuilder out = new StringBuilder(text.length()); + int i = 0; + while (i < text.length()) { + char c = text.charAt(i); + if (c != '\\') { + out.append(c); + i++; + continue; + } + int j = i; + while (j < text.length() && text.charAt(j) == '\\') { + j++; + } + int run = j - i; + for (int pair = 0; pair < run / 2; pair++) { + out.append('\\').append('\\'); + } + if (run % 2 == 0) { + i = j; + continue; + } + int u = j; + while (u < text.length() && text.charAt(u) == 'u') { + u++; + } + int value = u > j ? hexQuad(text, u) : -1; + if (value < 0) { + out.append('\\'); + i = j; + continue; + } + out.append((char) value); + i = u + 4; + } + return out.toString(); + } + + /// The four hex digits at `from`, or -1. Hand-rolled for the same reason + /// [#continuesAName] is: this class compiles against the Codename One API + /// subset. + private static int hexQuad(String text, int from) { + if (from + 4 > text.length()) { + return -1; + } + int value = 0; + for (int i = from; i < from + 4; i++) { + char c = text.charAt(i); + int digit; + if (c >= '0' && c <= '9') { + digit = c - '0'; + } else if (c >= 'a' && c <= 'f') { + digit = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + digit = c - 'A' + 10; + } else { + return -1; + } + value = value * 16 + digit; + } + return value; + } + + private static boolean continuesAName(char c) { + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') || c == '_' || c == '$') { + return true; + } + // Both languages allow a non-ASCII identifier -- `package com.应用` is + // valid Java and Kotlin -- and stopping at the first such character read + // a short name, so the real main source was rejected and Settings could + // offer a hint an annotation already owns. + // + // Everything outside ASCII that is not whitespace counts, since + // Character.isJavaIdentifierPart is outside the Codename One API subset + // this class is compiled against. That is wider than the language rule, + // but only by characters that cannot legally sit next to an identifier + // in source the compiler has already accepted -- and the alternative, + // rejecting all of them, is wrong for every name that has one. + return c >= 0x80 && !Character.isWhitespace(c); + } + + /// The index of the next character that is neither whitespace nor part of a + /// comment, starting at `from`; -1 when the source ends first. + static int nextLiveChar(String source, int from, boolean kotlin) { + int i = from; + while (i < source.length()) { + char c = source.charAt(i); + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f') { + i++; + continue; + } + if (c == '/') { + int skipped = skipNonCode(source, i, kotlin); + if (skipped > i) { + i = skipped; + continue; + } + } + return i; + } + return -1; + } + + /// The next occurrence of `marker` that is real code, or -1. + /// + /// Comments and string literals are stepped over with the same scanner the + /// argument reader uses, so what counts as code is one answer rather than + /// two that can disagree. + static int nextMarker(String source, String marker, int from, boolean kotlin) { + int i = from; + while (i < source.length()) { + char c = source.charAt(i); + if (c == '"' || c == '\'' || c == '/' || c == '`') { + int skipped = skipNonCode(source, i, kotlin); + if (skipped > i) { + i = skipped; + continue; + } + } + if (source.startsWith(marker, i)) { + return i; + } + i++; + } + return -1; + } + + /// If a string, character literal or comment starts at `i`, the index just + /// past it; otherwise `i`. + /// Index just past a Java text block opening at `i`. Escapes apply, so a + /// backslash consumes the character after it and cannot start a delimiter. + private static int endOfJavaTextBlock(String s, int i) { + int j = i + 3; + while (j < s.length()) { + char c = s.charAt(j); + if (c == '\\') { + j += 2; + continue; + } + if (c == '"' && s.startsWith("\"\"\"", j)) { + return j + 3; + } + j++; + } + return s.length(); + } + + /// Index just past a Kotlin raw string opening at `i`. No escapes, and a run + /// of quotes closes at its last three, so the extra ones belong to the value. + /// The offset just past a `${ ... }` template expression at `i`, or -1 when + /// one does not start there. + /// + /// Braces are matched, and a nested literal inside the expression is stepped + /// over so that a `}` inside it does not close the expression early. + private static int endOfKotlinTemplate(String s, int i) { + if (i + 1 >= s.length() || s.charAt(i) != '$' || s.charAt(i + 1) != '{') { + return -1; + } + int depth = 0; + int j = i + 1; + while (j < s.length()) { + char ch = s.charAt(j); + if (ch == '"') { + j = s.startsWith("\"\"\"", j) ? endOfKotlinRawString(s, j) : endOfKotlinString(s, j); + continue; + } + // The expression is ordinary code, so it holds ordinary comments and + // char literals -- and a quote inside one of those is not a nested + // string. Reading `${ /* " */ 1 }` as if it were swallowed the rest + // of the file, hiding every annotation after it. + // An escaped identifier belongs here too: everything inside it is + // part of the name, so a quote there does not open a string and a + // brace does not close the expression. + if (ch == '\'' || ch == '/' || ch == '`') { + int skipped = skipNonCode(s, j, true); + if (skipped > j) { + j = skipped; + continue; + } + } + if (ch == '{') { + depth++; + } else if (ch == '}') { + depth--; + if (depth == 0) { + return j + 1; + } + } + j++; + } + return -1; + } + + /// The offset just past an ordinary Kotlin string starting at `i`. + private static int endOfKotlinString(String s, int i) { + int j = i + 1; + while (j < s.length()) { + if (s.charAt(j) == '\\') { + j += 2; + continue; + } + int template = endOfKotlinTemplate(s, j); + if (template > j) { + j = template; + continue; + } + if (s.charAt(j) == '"') { + return j + 1; + } + j++; + } + return s.length(); + } + + private static int endOfKotlinRawString(String s, int i) { + int j = i + 3; + while (j < s.length()) { + // A template expression here too: a `"""` inside one is a nested + // literal, not this string's terminator. + int template = endOfKotlinTemplate(s, j); + if (template > j) { + j = template; + continue; + } + if (s.charAt(j) != '"') { + j++; + continue; + } + int run = j; + while (run < s.length() && s.charAt(run) == '"') { + run++; + } + if (run - j >= 3) { + return run; + } + j = run; + } + return s.length(); + } + + private static int skipNonCode(String s, int i, boolean kotlin) { + char c = s.charAt(i); + // A Kotlin raw string or a Java text block, which the ordinary rule reads + // as an empty string followed by a new one -- and then an embedded quote + // inside it opens a literal that swallows the annotation after it. + // + // The two languages close it differently, and taking the shorter reading + // in either direction over-consumes past a live annotation: + // + // Java escape sequences DO apply, so \" is one quote and the run + // \""" is an escaped quote followed by two, not a delimiter. + // Kotlin escapes do NOT apply, and a run of four or more quotes ends + // the literal at its LAST three -- """a"""" holds a" . + if (c == '"' && s.startsWith("\"\"\"", i)) { + return kotlin ? endOfKotlinRawString(s, i) : endOfJavaTextBlock(s, i); + } + if (c == '"') { + for (int j = i + 1; j < s.length(); j++) { + if (s.charAt(j) == '\\') { + j++; + continue; + } + // A Kotlin template expression opens a fresh nesting level, and + // the first quote inside it starts a NEW literal rather than + // closing this one -- so `"${"@Ios(teamId = x)"}"` ended the + // string early and exposed its contents as live code, which read + // as an annotation nobody wrote and hid the editor for a hint + // nothing owns. + int template = kotlin ? endOfKotlinTemplate(s, j) : -1; + if (template > j) { + j = template - 1; + continue; + } + if (s.charAt(j) == '"') { + return j + 1; + } + } + return s.length(); + } + if (c == '\'') { + for (int j = i + 1; j < s.length(); j++) { + if (s.charAt(j) == '\\') { + j++; + } else if (s.charAt(j) == '\'') { + return j + 1; + } + } + return s.length(); + } + // A Kotlin escaped identifier -- `class `when``. It is code, not a + // literal, but it is stepped over whole because a quote inside it + // (`say"hi` is a legal name) would otherwise open a literal that + // swallows every annotation after it, leaving an owned hint editable in + // Settings and letting the user add the duplicate that fails the build. + if (kotlin && c == '`') { + int close = s.indexOf('`', i + 1); + int nl = s.indexOf('\n', i + 1); + if (close >= 0 && (nl < 0 || close < nl)) { + return close + 1; + } + } + if (c == '/' && i + 1 < s.length()) { + char n = s.charAt(i + 1); + if (n == '/') { + int nl = s.indexOf('\n', i); + return nl < 0 ? s.length() : nl; + } + if (n == '*') { + // Kotlin block comments NEST; Java's do not. Stopping at the + // first */ in Kotlin ends the comment early and the rest of it is + // then read as live code. + if (!kotlin) { + int close = s.indexOf("*/", i + 2); + return close < 0 ? s.length() : close + 2; + } + int depth = 0; + int j = i; + while (j < s.length()) { + if (s.charAt(j) == '/' && j + 1 < s.length() && s.charAt(j + 1) == '*') { + depth++; + j += 2; + continue; + } + if (s.charAt(j) == '*' && j + 1 < s.length() && s.charAt(j + 1) == '/') { + depth--; + j += 2; + if (depth == 0) { + return j; + } + continue; + } + j++; + } + return s.length(); + } + } + return i; + } } diff --git a/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintCatalog.java b/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintCatalog.java index e75d0bc3b5b..4246df1387e 100644 --- a/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintCatalog.java +++ b/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintCatalog.java @@ -1,5 +1,30 @@ +/* + * Copyright (c) 2012, 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.codename1.settings.hints; +import com.codename1.build.shared.BuildHints; +import com.codename1.build.shared.HintType; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -7,6 +32,15 @@ import java.util.List; import java.util.Map; +/** + * The build hints the Settings tool offers for editing. + * + *

Built from {@link BuildHints}, the same table the {@code @Ios} / {@code @Android} + * annotations are generated from and the same one the builders' drift gate checks. It + * used to be scraped out of the developer guide's AsciiDoc table at runtime, with the + * type guessed by string-matching the description prose -- so a hint the guide did not + * mention was invisible here, and one whose wording changed silently changed type.

+ */ public final class BuildHintCatalog { private final Map hints = new LinkedHashMap(); @@ -38,181 +72,46 @@ public void add(BuildHintMetadata hint) { } } - public static BuildHintCatalog fromAsciiDoc(String asciidoc) { + /** + * Every hint the catalog describes, including the ones consumed only by the + * build service. Dynamic families such as {@code android.permission.} + * are left out: their names are patterns rather than keys, so there is + * nothing for the editor to set. + */ + public static BuildHintCatalog load() { BuildHintCatalog catalog = new BuildHintCatalog(); - if (asciidoc == null) { - return fallback(); - } - String[] lines = asciidoc.replace("\r\n", "\n").split("\n"); - boolean inTable = false; - boolean buildHintTable = false; - String currentName = null; - StringBuilder currentDescription = new StringBuilder(); - for (String raw : lines) { - String line = raw.trim(); - if ("|===".equals(line)) { - if (inTable) { - if (buildHintTable) { - flush(catalog, currentName, currentDescription.toString()); - break; - } - inTable = false; - } else { - inTable = true; - buildHintTable = false; - currentName = null; - currentDescription.setLength(0); - } - continue; - } - if (!inTable) { - continue; - } - if (line.startsWith("//")) { - continue; - } - if (!buildHintTable) { - String header = line.startsWith("|") ? line.substring(1).trim() : line; - if (header.startsWith("Name") && header.contains("|Description")) { - buildHintTable = true; - } + for (BuildHints.Hint h : BuildHints.entries()) { + if (h.isDynamic()) { continue; } - if (line.startsWith("|")) { - String cell = line.substring(1).trim(); - if (currentName == null) { - currentName = cell; - currentDescription.setLength(0); - } else if (currentDescription.length() == 0) { - currentDescription.append(cell); - } else { - flush(catalog, currentName, currentDescription.toString()); - currentName = cell; - currentDescription.setLength(0); - } - } else if (currentName != null && line.length() > 0) { - if (currentDescription.length() > 0) { - currentDescription.append(' '); - } - currentDescription.append(line); - } - } - if (catalog.hints.isEmpty()) { - return fallback(); + catalog.add(new BuildHintMetadata( + h.name(), + h.doc(), + toSettingsType(h.type()), + h.platform(), + h.values(), + h.def(), + annotationOf(h))); } return catalog; } - private static void flush(BuildHintCatalog catalog, String rawName, String description) { - if (rawName == null || rawName.trim().length() == 0) { - return; - } - for (String name : splitNames(rawName)) { - catalog.add(new BuildHintMetadata(name, description, inferType(name, description), inferPlatform(name))); - } - } - - private static List splitNames(String raw) { - ArrayList names = new ArrayList(); - String normalized = raw.replace("`", "").replace("(a.k.a.", "/").replace(")", ""); - String[] parts = normalized.split(","); - for (String part : parts) { - String[] slashParts = part.split("/"); - for (String slashPart : slashParts) { - String name = slashPart.trim(); - if (name.indexOf(' ') >= 0 || name.length() == 0 || name.startsWith("(")) { - continue; - } - names.add(name); - } - } - return names.isEmpty() ? Collections.singletonList(raw.trim()) : names; - } - - private static BuildHintType inferType(String name, String description) { - String n = name.toLowerCase(); - String d = description == null ? "" : description.toLowerCase(); - if ("java.version".equals(name)) { - return BuildHintType.INTEGER; - } - if ("android.targetSDKVersion".equals(name)) { - return BuildHintType.INTEGER; - } - if ("android.useAndroidX".equals(name)) { - return BuildHintType.BOOLEAN; + private static String annotationOf(BuildHints.Hint h) { + if (!h.isAnnotated()) { + return null; } - if ("build.cn1Version".equals(name) || "ios.bundleVersion".equals(name)) { - return BuildHintType.VERSION; - } - if (n.contains("password") || n.contains("secret") || n.contains("token")) { - return BuildHintType.SECRET; - } - if (n.contains("certificate") || n.contains("provision") || n.contains("sdkroot") || d.contains("path to")) { - return BuildHintType.PATH; - } - if (n.contains("url") || d.contains("https://") || d.contains("http://")) { - return BuildHintType.URL; - } - if (d.contains("true/false") || d.contains("boolean true/false") || d.contains("`true`") || d.contains("`false`")) { - return BuildHintType.BOOLEAN; - } - if (d.contains("comma") || d.contains("comma-delimited") || d.contains("comma delimited")) { - return BuildHintType.CSV; - } - if (d.contains("<") && d.contains(">") || n.contains("xml") || n.contains("plistinject") || n.contains("xpermissions")) { - return BuildHintType.XML; - } - if (n.contains("version") || d.contains("version")) { - return BuildHintType.VERSION; - } - if (d.contains("can be ") || d.contains("supported values") || d.contains("accepts ")) { - return BuildHintType.ENUM; - } - if (d.contains("integer") || d.contains("size in bytes") || n.endsWith("port")) { - return BuildHintType.INTEGER; - } - return BuildHintType.TEXT; + return "@" + h.group().annotationSimpleName() + "(" + h.attr() + ")"; } - private static String inferPlatform(String name) { - if (name.startsWith("android.") || name.startsWith("and.")) { - return "android"; + /** + * Maps the catalog's type to this tool's vocabulary. Derived rather than + * duplicated so the two cannot drift apart again. + */ + private static BuildHintType toSettingsType(HintType type) { + try { + return BuildHintType.valueOf(BuildHints.settingsType(type)); + } catch (IllegalArgumentException ex) { + return BuildHintType.TEXT; } - if (name.startsWith("ios.")) { - return "ios"; - } - if (name.startsWith("macNative.") || name.startsWith("codename1.mac.") || name.startsWith("desktop.mac.")) { - return "mac"; - } - if (name.startsWith("windows.") || name.startsWith("win.")) { - return "windows"; - } - if (name.startsWith("linux.")) { - return "linux"; - } - if (name.startsWith("javascript.")) { - return "javascript"; - } - if (name.startsWith("desktop.")) { - return "desktop"; - } - return "general"; - } - - public static BuildHintCatalog fallback() { - BuildHintCatalog catalog = new BuildHintCatalog(); - catalog.add(new BuildHintMetadata("build.cn1Version", "Pins the cloud build to a released Codename One version such as 7.0.250, or master.", BuildHintType.VERSION, "general")); - catalog.add(new BuildHintMetadata("java.version", "Build server Java version.", BuildHintType.INTEGER, "general")); - catalog.add(new BuildHintMetadata("android.debug", "Whether to include an Android debug build.", BuildHintType.BOOLEAN, "android")); - catalog.add(new BuildHintMetadata("android.release", "Whether to include an Android release build.", BuildHintType.BOOLEAN, "android")); - catalog.add(new BuildHintMetadata("android.xpermissions", "Additional Android manifest permissions XML.", BuildHintType.XML, "android")); - catalog.add(new BuildHintMetadata("ios.bundleVersion", "Version number of the generated iOS bundle.", BuildHintType.VERSION, "ios")); - catalog.add(new BuildHintMetadata("ios.deployment_target", "Minimum iOS version.", BuildHintType.VERSION, "ios")); - catalog.add(new BuildHintMetadata("ios.plistInject", "Raw XML injected into the iOS Info.plist.", BuildHintType.XML, "ios")); - catalog.add(new BuildHintMetadata("macNative.distribution", "Mac native distribution: appStore, developerID, or both.", BuildHintType.ENUM, "mac")); - catalog.add(new BuildHintMetadata("windows.signing.timestampUrl", "RFC 3161 timestamp server URL for Windows signing.", BuildHintType.URL, "windows")); - catalog.add(new BuildHintMetadata("desktop.width", "Desktop window width.", BuildHintType.INTEGER, "desktop")); - catalog.add(new BuildHintMetadata("desktop.height", "Desktop window height.", BuildHintType.INTEGER, "desktop")); - return catalog; } } diff --git a/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintMetadata.java b/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintMetadata.java index e5e27a1d789..92e4f72af73 100644 --- a/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintMetadata.java +++ b/scripts/settings/common/src/main/java/com/codename1/settings/hints/BuildHintMetadata.java @@ -1,16 +1,78 @@ +/* + * Copyright (c) 2012, 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.codename1.settings.hints; +import java.util.Collections; +import java.util.List; + public final class BuildHintMetadata { private final String name; private final String description; private final BuildHintType type; private final String platform; + private final List values; + private final String defaultValue; + private final String annotation; public BuildHintMetadata(String name, String description, BuildHintType type, String platform) { + this(name, description, type, platform, null, null, null); + } + + /** + * @param values the closed value domain, or null when the hint is free-form + * @param defaultValue the builder's own default, or null when it has none + * @param annotation the annotation attribute that sets this hint, e.g. + * {@code @Ios(pods)}, or null when it has none + */ + public BuildHintMetadata(String name, String description, BuildHintType type, String platform, + List values, String defaultValue, String annotation) { this.name = name; this.description = description == null ? "" : description.trim(); this.type = type == null ? BuildHintType.TEXT : type; this.platform = platform == null ? "general" : platform; + this.values = values == null || values.isEmpty() + ? Collections.emptyList() : Collections.unmodifiableList(values); + this.defaultValue = defaultValue; + this.annotation = annotation; + } + + /** The accepted values, or empty when the hint is free-form. */ + public List values() { + return values; + } + + /** The builder's own default, or null. */ + public String defaultValue() { + return defaultValue; + } + + /** + * The annotation attribute that sets this hint, or null when the hint has no + * checked form yet. Editing such a hint here is not wrong, but the annotation + * is the form the compiler validates. + */ + public String annotation() { + return annotation; } public String name() { diff --git a/scripts/settings/common/src/main/java/com/codename1/settings/project/ProjectBinding.java b/scripts/settings/common/src/main/java/com/codename1/settings/project/ProjectBinding.java index ff66d7e231d..26eceafb851 100644 --- a/scripts/settings/common/src/main/java/com/codename1/settings/project/ProjectBinding.java +++ b/scripts/settings/common/src/main/java/com/codename1/settings/project/ProjectBinding.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2012, 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.codename1.settings.project; public final class ProjectBinding { @@ -5,7 +27,8 @@ public final class ProjectBinding { private String settings; private String pom; private String multimoduleRoot; - private String buildHintsDoc; + private String sourceRoots; + private String sourceEncoding; public String projectDir() { return projectDir; @@ -23,8 +46,21 @@ public String multimoduleRoot() { return multimoduleRoot; } - public String buildHintsDoc() { - return buildHintsDoc; + /// The compile source roots Maven RESOLVED, path-separator joined, or null + /// when the launcher did not say. + /// + /// The tool can read a POM but it has no model: it cannot evaluate a profile + /// activation, follow an inherited `` or expand an + /// arbitrary property. Where the launcher knows, it says, and the tool's own + /// reading is the fallback. + public String sourceRoots() { + return sourceRoots; + } + + /// The source encoding Maven resolved, or null when the launcher did not + /// say. + public String sourceEncoding() { + return sourceEncoding; } public boolean isValid() { @@ -53,7 +89,8 @@ public static ProjectBinding parse(String content) { case "settings" -> b.settings = val; case "pom" -> b.pom = val; case "multimoduleRoot" -> b.multimoduleRoot = val; - case "buildHintsDoc" -> b.buildHintsDoc = val; + case "sourceRoots" -> b.sourceRoots = val; + case "sourceEncoding" -> b.sourceEncoding = val; default -> { } } diff --git a/scripts/settings/common/src/test/java/com/codename1/settings/BuildHintCatalogTest.java b/scripts/settings/common/src/test/java/com/codename1/settings/BuildHintCatalogTest.java index dbd47edf61f..6a13cd6ab00 100644 --- a/scripts/settings/common/src/test/java/com/codename1/settings/BuildHintCatalogTest.java +++ b/scripts/settings/common/src/test/java/com/codename1/settings/BuildHintCatalogTest.java @@ -1,54 +1,1960 @@ +/* + * Copyright (c) 2012, 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.codename1.settings; import com.codename1.settings.hints.BuildHintCatalog; +import com.codename1.settings.hints.BuildHintMetadata; import com.codename1.settings.hints.BuildHintType; import org.junit.jupiter.api.Test; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; - import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * The hint catalog the Settings tool offers for editing. + * + *

It used to be scraped out of the developer guide's AsciiDoc table at runtime, + * with each hint's type guessed by string-matching its description prose. It now + * comes from {@code com.codename1.build.shared.BuildHints}, the same table the + * build hint annotations are generated from and the same one the drift gate holds + * the builders against.

+ */ public class BuildHintCatalogTest { + @Test - public void parsesDeveloperGuideBuildHintTable() { - String doc = """ - Before - |=== - |Name\t|Description + public void carriesTheHintsTheDeveloperGuideDocuments() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + assertNotNull(catalog.get("android.debug")); + assertNotNull(catalog.get("ios.plistInject")); + assertNotNull(catalog.get("windows.signing.timestampUrl")); + assertTrue(catalog.all().size() > 400, + "expected the full catalog, got " + catalog.all().size()); + } - |android.debug - |true/false defaults to true - indicates whether to include debug. + @Test + public void knownHintsCarryTheRightType() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + assertEquals(BuildHintType.BOOLEAN, catalog.get("android.debug").type()); + assertEquals(BuildHintType.XML, catalog.get("ios.plistInject").type()); + assertEquals(BuildHintType.INTEGER, catalog.get("java.version").type()); + assertEquals(BuildHintType.INTEGER, catalog.get("android.min_sdk_version").type()); + assertEquals(BuildHintType.BOOLEAN, catalog.get("android.useAndroidX").type()); + assertEquals(BuildHintType.CSV, catalog.get("ios.pods").type()); + } - |ios.plistInject - |Injects raw XML into the plist. + /** + * The tool used to accept any string for every hint but an integer, a version + * or a URL. A hint with a closed domain is the one case where a wrong value is + * certainly wrong, because the builder compares against those strings and + * silently falls back to its default when it matches none of them. + */ + @Test + public void hintsWithAClosedDomainExposeIt() { + BuildHintMetadata titleBar = BuildHintCatalog.load().get("desktop.titleBar"); + assertNotNull(titleBar); + assertEquals(BuildHintType.ENUM, titleBar.type()); + assertTrue(titleBar.values().contains("native")); + assertTrue(titleBar.values().contains("custom")); + assertTrue(titleBar.values().contains("toolbar")); + assertFalse(titleBar.values().contains("natvie")); + } - |windows.signing.timestampUrl - |RFC 3161 timestamp server URL. + /** A hint with a checked form should say so, so the UI can point at it. */ + @Test + public void annotatedHintsNameTheirAnnotation() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + assertEquals("@Ios(pods)", catalog.get("ios.pods").annotation()); + assertEquals("@Desktop(titleBar)", catalog.get("desktop.titleBar").annotation()); + // Not every hint has one; the properties file remains the way to set those. + assertEquals(null, catalog.get("android.xmanifest").annotation()); + } - |=== - After - """; - BuildHintCatalog catalog = BuildHintCatalog.fromAsciiDoc(doc); - assertNotNull(catalog.get("android.debug")); - assertEquals(BuildHintType.BOOLEAN, catalog.get("android.debug").type()); - assertEquals(BuildHintType.XML, catalog.get("ios.plistInject").type()); - assertEquals(BuildHintType.URL, catalog.get("windows.signing.timestampUrl").type()); + /** + * Dynamic families such as {@code android.permission.} are patterns, not + * keys, so there is nothing for the editor to set. + */ + @Test + public void dynamicFamiliesAreNotOffered() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + for (BuildHintMetadata h : catalog.all()) { + assertFalse(h.name().contains("*"), + h.name() + " is a pattern, not a hint the editor can set"); + } + } + + /** + * The generated project ships hints like ios.themeMode as annotations, not + * properties lines. The catalog has to say which hints have an annotation + * form so the Build Hints UI can refuse to write a second declaration -- + * doing so would fail the very next build with a duplicate-hint error. + */ + @Test + public void everyAnnotatedHintNamesItsAttribute() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + int annotated = 0; + for (BuildHintMetadata h : catalog.all()) { + if (h.annotation() == null) { + continue; + } + annotated++; + assertTrue(h.annotation().startsWith("@"), h.name() + " -> " + h.annotation()); + assertTrue(h.annotation().endsWith(")"), h.name() + " -> " + h.annotation()); + } + assertTrue(annotated > 50, "expected the curated set, got " + annotated); + } + + /** + * The Settings field for a credential is masked from its type. The catalog + * that replaced the old name-matching scraper has to keep classifying these + * as SECRET, or a stored certificate password renders as visible text. + */ + @Test + public void credentialHintsStayMasked() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + for (BuildHintMetadata h : catalog.all()) { + String n = h.name().toLowerCase(); + if (n.contains("password") || n.contains("secret") || n.contains("token")) { + assertEquals(BuildHintType.SECRET, h.type(), + h.name() + " holds a credential and must render masked"); + } + } + } + + /** + * A deprecated alias configures the same effective setting as its target, so + * the Build Hints UI has to treat it as annotation-owned too -- otherwise its + * row still offers Add and creates the duplicate the next build refuses. + */ + @Test + public void aliasesResolveToTheirCanonicalName() { + assertEquals("and.themeMode", + com.codename1.build.shared.BuildHints.canonicalName("cn1.androidTheme")); + assertEquals("nativeTheme", + com.codename1.build.shared.BuildHints.canonicalName("cn1.nativeTheme")); + assertEquals("ios.pods", + com.codename1.build.shared.BuildHints.canonicalName("ios.pods")); + } + + /** + * Right after cn1:migrate-build-hints the source declares the annotations and + * no build has emitted the manifest yet. Treating them as unowned there would + * offer Add for a hint the annotations already set, and the next build would + * fail on the duplicate declaration -- so the source is read directly. + */ + @Test + public void annotationsAreFoundInSourceBeforeTheProjectIsBuilt() { + String src = "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(pods = {\"A\", \"B\"}, teamId = \"T\")\n" + + "@Desktop(titleBar = DesktopTitleBar.NATIVE)\n" + + "public class MyApp extends Lifecycle {\n}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned); + assertEquals("@Ios(pods)", owned.get("ios.pods")); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + assertEquals("@Desktop(titleBar)", owned.get("desktop.titleBar")); + assertTrue(owned.get("ios.objC") == null, "an attribute nobody set is not owned"); + } + + /** + * Attribute detection must not be fooled by a value that contains an equals + * sign, a comma or a bracket -- android.xpermissions is XML, and gradleDep + * entries carry both. + */ + @Test + public void valuesContainingSeparatorsDoNotCreatePhantomOwnership() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "@Android(xpermissions = \"\")\n" + + "public class MyApp {}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned); + assertEquals("@Android(xpermissions)", owned.get("android.xpermissions")); + assertTrue(owned.get("android.gradleDep") == null, + "nothing inside a string value may register as an attribute"); + assertTrue(owned.get("android.debug") == null); + } + + /** + * A comment inside an annotation can carry an unmatched delimiter. Counting + * it as syntax loses the annotation's boundary, and the hint it owns stays + * editable -- so Add writes the duplicate the next build refuses. + */ + @Test + public void commentsInsideAnAnnotationDoNotBreakOwnership() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(/* required for issue ( */ teamId = \"T\")\n" + + "public class MyApp {}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + } + + @Test + public void lineCommentsAndCharLiteralsDoNotBreakOwnership() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(\n" + + " // a stray ) in a line comment\n" + + " teamId = \"T\",\n" + + " urlScheme = \"x\")\n" + + "public class MyApp {}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + assertEquals("@Ios(urlScheme)", owned.get("ios.urlScheme")); + + String withChar = "import com.codename1.annotations.buildhints.*;\n" + + "@Android(xpermissions = \"a\") // ')'\npublic class MyApp {}\n"; + java.util.Map owned2 = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(withChar, owned2); + assertEquals("@Android(xpermissions)", owned2.get("android.xpermissions")); + } + + /** + * The fully qualified spelling needs no import and is equally valid. Missing + * it left the hint editable, and Add then wrote the duplicate declaration. + */ + @Test + public void fullyQualifiedAnnotationsAreRecognized() { + String src = "@com.codename1.annotations.buildhints.Ios(teamId = \"T\")\n" + + "public class MyApp {}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + } + + /** `@Ios` must not match `@IosPrivacy`, which is a different annotation. */ + @Test + public void aSimpleNameDoesNotMatchALongerAnnotation() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "@IosPrivacy(cameraUsageDescription = \"why\")\n" + + "public class MyApp {}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned); + assertEquals("@IosPrivacy(cameraUsageDescription)", + owned.get("ios.NSCameraUsageDescription")); + assertTrue(owned.get("ios.teamId") == null, + "@IosPrivacy must not be read as @Ios"); + } + + @Test + public void searchStillMatchesOnNameAndDescription() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + assertFalse(catalog.search("pods").isEmpty()); + assertFalse(catalog.search("android").isEmpty()); + } + + /// Kotlin lets a file rename what it imports, and then the annotation's own + /// name appears nowhere in the source. Reading that as unowned put the hint + /// back on the Add list, and Add writes the properties line that makes the + /// next process-annotations fail on a duplicate the tool itself created. + @Test + public void aKotlinAliasedImportIsRecognized() { + String src = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as BuildIos\n" + + "@BuildIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// The alias only counts when it really is one: the import must say `as`. + @Test + public void aPlainImportIsNotReadAsAnAlias() { + String src = "import com.codename1.annotations.buildhints.Ios\n" + + "@Ios(teamId = \"ABCDE12345\")\n"; + assertNull(CodenameOneSettings.kotlinImportAlias(src, "Ios", true)); + } + + /// A commented-out annotation is not an annotation. Reading it as one made + /// Settings withhold Add and the editor for a hint the processor never + /// emits, which looks like the tool being broken. + @Test + public void aCommentedOutAnnotationIsNotOwnership() { + String src = "package com.example;\n" + + "import com.codename1.annotations.buildhints.Ios;\n" + + "// @Ios(teamId = \"OLD\")\n" + + "public class MyApp {}\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out); + assertNull(out.get("ios.teamId")); + } + + /// Same for a block comment and for an annotation quoted inside a string. + @Test + public void aBlockCommentOrStringIsNotOwnership() { + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints( + "/* @Ios(teamId = \"OLD\") */ public class MyApp {}", out); + assertNull(out.get("ios.teamId")); + + out.clear(); + CodenameOneSettings.collectAnnotationOwnedHints( + "String doc = \"@Ios(teamId = x)\";", out); + assertNull(out.get("ios.teamId")); + } + + /// And the real one is still found when a commented-out copy precedes it. + @Test + public void aLiveAnnotationAfterACommentedOneIsStillFound() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "// @Ios(teamId = \"OLD\")\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "public class MyApp {}\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// A commented-out earlier alias must not win over the live import. It did, + /// and then the live `@BuildIos` was never looked for at all -- the very bug + /// the alias support exists to prevent. + @Test + public void aCommentedOutAliasDoesNotShadowTheLiveOne() { + String src = "// import com.codename1.annotations.buildhints.Ios as Old\n" + + "import com.codename1.annotations.buildhints.Ios as BuildIos\n" + + "@BuildIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + assertEquals("BuildIos", CodenameOneSettings.kotlinImportAlias(src, "Ios", true)); + + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// The package named somewhere that is not an import is not an alias. + @Test + public void aMentionThatIsNotAnImportIsNotAnAlias() { + assertNull(CodenameOneSettings.kotlinImportAlias( + "val doc = com.codename1.annotations.buildhints.Ios as Whatever", "Ios", true)); + } + + /// Parentheses are optional on an annotation, so searching forward for the + /// next `(` adopted whatever call came after it. Settings then withheld the + /// Add and editor controls for a hint the processor never emits. + @Test + public void aBareAnnotationDoesNotAdoptTheNextCall() { + String src = "@Ios\n" + + "class MyApp {\n" + + " fun setUp() { configure(teamId = \"ABCDE12345\") }\n" + + "}\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out); + assertNull(out.get("ios.teamId")); + } + + /// A comment between the name and its own argument list is still its own. + @Test + public void anAnnotationsOwnArgumentListIsStillFoundAcrossAComment() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "@Ios /* why */ (teamId = \"ABCDE12345\")\nclass MyApp\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// The two capture-record spellings are one setting: the builder reads the + /// long name and then lets the short one override it. Without the alias an + /// annotation and a properties line are not seen as a conflict, and the + /// properties line silently wins over the compile-checked annotation. + @Test + public void theShortCaptureRecordSpellingIsAnAliasOfTheLongOne() { + assertEquals("android.captureRecord", + com.codename1.build.shared.BuildHints.canonicalName("and.captureRecord")); + assertEquals("android.facebook_permissions", + com.codename1.build.shared.BuildHints.canonicalName("and.facebook_permissions")); + } + + /// A Kotlin raw string containing a quote was read as an empty literal + /// followed by a new one, and that new one then swallowed the annotation + /// after it -- so the hint read as unowned and Add wrote the duplicate. + @Test + public void aTripleQuotedStringDoesNotSwallowTheAnnotation() { + String src = "import com.codename1.annotations.buildhints.*\n" + + "val doc = \"\"\"quoted \" text\"\"\"\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// And an annotation written INSIDE a raw string is still not ownership. + @Test + public void anAnnotationInsideATripleQuotedStringIsNotOwnership() { + String src = "val doc = \"\"\"@Ios(teamId = \"x\")\"\"\"\nclass MyApp\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertNull(out.get("ios.teamId")); + } + + /// Java text blocks DO process escapes, so `\\"""` is an escaped quote and + /// two more -- not the closing delimiter. Reading it as one made the scanner + /// treat the REAL delimiter as a new text block and run past the annotation + /// after it. + @Test + public void anEscapedQuoteRunDoesNotCloseAJavaTextBlock() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "String doc = \"\"\"\n" + + " a \\\"\"\" b\n" + + " \"\"\";\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "public class MyApp {}\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, false); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// Kotlin does NOT process escapes in a raw string, and a run of four quotes + /// closes at the last three -- the extra one belongs to the value. Applying + /// Java's rule here would keep scanning and swallow the annotation. + @Test + public void aQuoteRunClosesAKotlinRawStringAtItsLastThree() { + String src = "import com.codename1.annotations.buildhints.*\n" + + "val doc = \"\"\"a\"\"\"\"\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// `@Build` and `@Android` are ordinary enough names that another library's + /// annotation with a matching attribute would be read as ownership -- and + /// Settings would then hide the editor for a hint the processor never emits. + /// The simple name only counts when an import makes it ours. + @Test + public void anUnrelatedAnnotationOfTheSameNameIsNotOwnership() { + String src = "import com.example.other.Ios;\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "public class MyApp {}\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out); + assertNull(out.get("ios.teamId")); + } + + /// A wildcard import counts, and so does the fully qualified spelling, which + /// needs no import at all. + @Test + public void aWildcardImportAndTheQualifiedSpellingBothCount() { + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints( + "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(teamId = \"T\")\npublic class MyApp {}\n", out); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + + out.clear(); + CodenameOneSettings.collectAnnotationOwnedHints( + "@com.codename1.annotations.buildhints.Ios(teamId = \"T\")\n" + + "public class MyApp {}\n", out); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// A commented-out import does not bring the name in. + @Test + public void aCommentedOutImportDoesNotCount() { + assertFalse(CodenameOneSettings.importsAnnotation( + "// import com.codename1.annotations.buildhints.Ios;\n", "Ios", false)); + assertTrue(CodenameOneSettings.importsAnnotation( + "import com.codename1.annotations.buildhints.Ios;\n", "Ios", false)); + } + + /// The runtime accepts spellings the picklist does not offer: + /// IOSImplementation.installNativeTheme compares against `flat` and `liquid`, + /// AndroidImplementation against `material` and `holo`. Rejecting them told a + /// developer a working configuration was invalid and refused the edit. + @Test + public void documentedThemeSpellingsAreAccepted() { + com.codename1.build.shared.BuildHints.Hint ios = + com.codename1.build.shared.BuildHints.byName("ios.themeMode"); + assertEquals("ios7", ios.canonicalValue("flat")); + assertEquals("modern", ios.canonicalValue("liquid")); + assertEquals("legacy", ios.canonicalValue("iphone")); + assertEquals("modern", ios.canonicalValue("MODERN")); + assertNull(ios.canonicalValue("nonsense")); + + com.codename1.build.shared.BuildHints.Hint and = + com.codename1.build.shared.BuildHints.byName("and.themeMode"); + assertEquals("modern", and.canonicalValue("material")); + assertEquals("hololight", and.canonicalValue("holo")); + assertNull(and.canonicalValue("nonsense")); + } + + /// An alias does not become a picklist choice or an enum constant: one + /// behaviour, one constant, or the annotation asks a question with no right + /// answer. + @Test + public void anAcceptedSpellingIsNotOfferedAsAChoice() { + com.codename1.build.shared.BuildHints.Hint ios = + com.codename1.build.shared.BuildHints.byName("ios.themeMode"); + assertFalse(ios.values().contains("flat")); + assertFalse(ios.values().contains("liquid")); + } + + /// `import ...Ios as BuildIos` puts BuildIos in scope, NOT Ios. Counting it + /// as a simple-name import attributed another library's @Ios to us. + @Test + public void anAliasedImportDoesNotBringTheSimpleNameIntoScope() { + String src = "import com.codename1.annotations.buildhints.Ios as BuildIos\n" + + "import com.example.other.Ios\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + assertFalse(CodenameOneSettings.importsAnnotation(src, "Ios", true)); + + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertNull(out.get("ios.teamId")); + } + + /// ...while the alias itself still is. + @Test + public void theAliasMarkerStillCounts() { + String src = "import com.codename1.annotations.buildhints.Ios as BuildIos\n" + + "@BuildIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, true); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// Kotlin does not require a file to be named after the class it declares, so + /// the declaration is what identifies the main class -- not the filename and + /// not the directory. + @Test + public void aClassIsIdentifiedByItsDeclarationNotItsFile() { + String kt = "package com.example\n\nclass Helper\n\nclass MyApp\n"; + assertTrue(CodenameOneSettings.declaresClass(kt, "MyApp", "com.example")); + assertTrue(CodenameOneSettings.declaresClass(kt, "Helper", "com.example")); + assertFalse(CodenameOneSettings.declaresClass(kt, "Other", "com.example")); + } + + /// A same-named class in another package is a different class. Accepting it + /// is how a moved class makes its own orphan look alive. + @Test + public void thePackageIsPartOfTheIdentity() { + String src = "package com.example.moved;\npublic class MyApp {}\n"; + assertFalse(CodenameOneSettings.declaresClass(src, "MyApp", "com.example")); + assertTrue(CodenameOneSettings.declaresClass(src, "MyApp", "com.example.moved")); + } + + /// A Kotlin `object` declares a type too. + @Test + public void anObjectDeclarationCounts() { + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\nobject MyApp\n", "MyApp", "com.example")); + } + + /// The default package is "" on both sides rather than null on one. + @Test + public void theDefaultPackageMatches() { + assertTrue(CodenameOneSettings.declaresClass("public class MyApp {}\n", "MyApp", null)); + assertTrue(CodenameOneSettings.declaresClass("public class MyApp {}\n", "MyApp", "")); + assertFalse(CodenameOneSettings.declaresClass("public class MyApp {}\n", "MyApp", "com.x")); + } + + /// A commented-out or quoted mention of a declaration is not a declaration. + /// An unrelated file answering for the main class reads ownership as empty, + /// and Settings then offers Add for a hint the real main class annotates. + @Test + public void aMentionOfADeclarationIsNotADeclaration() { + assertFalse(CodenameOneSettings.declaresClass( + "package com.example\n// class MyApp\n", "MyApp", "com.example", true)); + assertFalse(CodenameOneSettings.declaresClass( + "package com.example\n/* class MyApp */\n", "MyApp", "com.example", true)); + assertFalse(CodenameOneSettings.declaresClass( + "package com.example\nval s = \"class MyApp\"\n", "MyApp", "com.example", true)); + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\n// class MyApp\nclass MyApp\n", "MyApp", + "com.example", true)); + } + + /// The same for a commented-out package statement, which would otherwise make + /// a default-package file claim to be in one. + @Test + public void aCommentedPackageStatementIsNotThePackage() { + assertTrue(CodenameOneSettings.declaresClass( + "// package com.example\nclass MyApp\n", "MyApp", "", true)); + assertFalse(CodenameOneSettings.declaresClass( + "// package com.example\nclass MyApp\n", "MyApp", "com.example", true)); + } + + /// `class\nMain` and `class /* why */ Main` are both legal. Stopping at a + /// space read the declaration as unnamed, so the file did not declare the + /// main class and ownership came back empty. + @Test + public void anyLegalSeparatorBeforeTheNameIsAccepted() { + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\nclass\nMyApp\n", "MyApp", "com.example", true)); + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\nclass /* why */ MyApp\n", "MyApp", "com.example", true)); + assertTrue(CodenameOneSettings.declaresClass( + "package com.example;\npublic class\t MyApp {}\n", "MyApp", + "com.example", false)); + } + + /// An application's main class is top-level. Accepting a nested one let an + /// unrelated `class Outer { class Main }` end the fallback search on the + /// wrong file, so annotations on the real main class were never read. + @Test + public void aNestedDeclarationIsNotTheMainClass() { + assertFalse(CodenameOneSettings.declaresClass( + "package com.example\nclass Outer { class MyApp }\n", "MyApp", + "com.example", true)); + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\nclass Outer { }\nclass MyApp\n", "MyApp", + "com.example", true)); + } + + /// A brace inside a char literal is not syntax; counting it loses the depth + /// and turns a top-level declaration into a nested one or the reverse. + @Test + public void aBraceInACharLiteralDoesNotMoveTheDepth() { + assertTrue(CodenameOneSettings.declaresClass( + "package com.example;\npublic class Helper { char c = '{'; }\n" + + "class MyApp {}\n", "MyApp", "com.example", false)); + } + + /// A single-type import shadows an on-demand one -- the language rule, not a + /// preference. A file importing our package with a wildcard AND another + /// library's Ios by name is using theirs. + @Test + public void anExplicitImportBeatsOurWildcard() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "import com.example.other.Ios;\n" + + "@Ios(teamId = \"T\")\npublic class MyApp {}\n"; + assertFalse(CodenameOneSettings.importsAnnotation(src, "Ios", false)); + + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints(src, out, false); + assertNull(out.get("ios.teamId")); + } + + /// Our own explicit import is not "another library's". + @Test + public void ourOwnExplicitImportStillCounts() { + String src = "import com.codename1.annotations.buildhints.*;\n" + + "import com.codename1.annotations.buildhints.Ios;\n" + + "@Ios(teamId = \"T\")\npublic class MyApp {}\n"; + assertTrue(CodenameOneSettings.importsAnnotation(src, "Ios", false)); + } + + /// Nor is a Kotlin alias, which introduces its alias rather than the name. + @Test + public void anAliasedForeignImportDoesNotShadow() { + String src = "import com.codename1.annotations.buildhints.*\n" + + "import com.example.other.Ios as TheirIos\n" + + "@Ios(teamId = \"T\")\nclass MyApp\n"; + assertTrue(CodenameOneSettings.importsAnnotation(src, "Ios", true)); + } + + /// Only one spelling of a closed-domain value works everywhere: + /// AndroidGradleBuilder copies android.installLocation straight into the + /// case-sensitive android:installLocation manifest attribute. Accepting + /// `INTERNALONLY` and storing it verbatim marked it valid and then failed the + /// Android build. + @Test + public void aClosedDomainValueHasOneWorkingSpelling() { + com.codename1.build.shared.BuildHints.Hint h = + com.codename1.build.shared.BuildHints.byName("android.installLocation"); + assertEquals("internalOnly", h.canonicalValue("INTERNALONLY")); + assertEquals("internalOnly", h.canonicalValue("internalonly")); + assertEquals("internalOnly", h.canonicalValue("internalOnly")); + assertNull(h.canonicalValue("nowhere")); + } + + /// `import /* build hints */ com.codename1...Ios;` is legal. Backing up from + /// the name over spaces only missed it, so the live @Ios was read as somebody + /// else's and Add offered a hint that is already annotated. + @Test + public void anImportSeparatedByCommentsOrNewlinesIsRecognised() { + assertTrue(CodenameOneSettings.importsAnnotation( + "import /* build hints */ com.codename1.annotations.buildhints.Ios;\n", + "Ios", false)); + assertTrue(CodenameOneSettings.importsAnnotation( + "import\n com.codename1.annotations.buildhints.Ios;\n", "Ios", false)); + assertEquals("BuildIos", CodenameOneSettings.kotlinImportAlias( + "import com.codename1.annotations.buildhints.Ios as BuildIos\n", + "Ios", true)); + } + + /// ...and a mention that is not an import still does not count. + @Test + public void aNonImportMentionIsStillNotAnImport() { + assertFalse(CodenameOneSettings.importsAnnotation( + "val t = com.codename1.annotations.buildhints.Ios::class\n", "Ios", true)); + assertFalse(CodenameOneSettings.importsAnnotation( + "// import com.codename1.annotations.buildhints.Ios;\n", "Ios", false)); + } + + /// `package /* generated */ com.example;` is legal. Taking the remainder of + /// the text and trimming it started the name at the comment, so the real main + /// source was rejected by both the conventional lookup and the fallback. + @Test + public void aCommentBetweenPackageAndItsNameIsSkipped() { + assertTrue(CodenameOneSettings.declaresClass( + "package /* generated */ com.example;\npublic class MyApp {}\n", + "MyApp", "com.example", false)); + assertTrue(CodenameOneSettings.declaresClass( + "package\n com.example\nclass MyApp\n", "MyApp", "com.example", true)); + } + + /// Adding a hint must start from what the build already does. Seeding a + /// type-wide placeholder wrote a value the project did not have: + /// android.NotificationChannel.importance defaults to 2, and persisting 0 + /// silences the channel before the user has typed anything. + @Test + public void theCatalogCarriesTheBuildersOwnDefault() { + BuildHintMetadata importance = + BuildHintCatalog.load().get("android.NotificationChannel.importance"); + assertNotNull(importance); + assertEquals("2", importance.defaultValue()); + + BuildHintMetadata pods = BuildHintCatalog.load().get("ios.pods"); + assertNotNull(pods); + assertTrue(pods.defaultValue() == null || pods.defaultValue().isEmpty(), + "a hint with no builder default must not invent one"); + } + + /// facebook.appId has no default: both builders decide whether Facebook + /// support is in the app by asking whether the hint is null, so seeding the + /// literal from the call site enabled the integration against an unrelated + /// shared app ID the moment Add was clicked. + @Test + public void facebookAppIdHasNoDefault() { + BuildHintMetadata meta = BuildHintCatalog.load().get("facebook.appId"); + assertNotNull(meta); + assertTrue(meta.defaultValue() == null || meta.defaultValue().isEmpty()); + } + + /// A qualified import may carry whitespace or a comment around any dot. + /// Reading the name as one contiguous run stopped at the separator and + /// recorded only the prefix, so the import went unrecognised and the live + /// @Ios read as somebody else's. + @Test + public void aQualifiedImportMaySpanSeparators() { + assertTrue(CodenameOneSettings.importsAnnotation( + "import com.codename1.annotations. /* generated */ buildhints.Ios;\n", + "Ios", false)); + assertTrue(CodenameOneSettings.importsAnnotation( + "import com.codename1\n .annotations\n .buildhints\n .*;\n", + "Ios", false)); + assertEquals("BuildIos", CodenameOneSettings.kotlinImportAlias( + "import com.codename1.annotations . buildhints . Ios as BuildIos\n", + "Ios", true)); + } + + /// ...and a foreign import spanning separators still shadows ours. + @Test + public void aForeignImportSpanningSeparatorsStillShadows() { + assertFalse(CodenameOneSettings.importsAnnotation( + "import com.codename1.annotations.buildhints.*;\n" + + "import com.example . other . Ios;\n", "Ios", false)); + } + + /// For a hint whose value the build computes when the line is ABSENT, there + /// is nothing safe to seed. android.targetSDKVersion has no catalog default, + /// and writing 0 does not create an unset hint -- it overrides the + /// computation, selecting the legacy android-14 target and emitting + /// targetSdkVersion="0". + @Test + public void aHintWithNoDefaultHasNothingSafeToSeed() { + BuildHintCatalog catalog = BuildHintCatalog.load(); + BuildHintMetadata target = catalog.get("android.targetSDKVersion"); + assertNotNull(target); + assertTrue(target.defaultValue() == null || target.defaultValue().isEmpty(), + "the catalog must not invent a default the builder computes"); + + BuildHintMetadata facebook = catalog.get("facebook.appId"); + assertNotNull(facebook); + assertTrue(facebook.defaultValue() == null || facebook.defaultValue().isEmpty(), + "presence is the switch, so an empty seed would enable the feature"); + } + + /// ...while a hint the builder does have a default for is seeded with it. + @Test + public void aHintWithADefaultIsSeededWithIt() { + assertEquals("2", + BuildHintCatalog.load().get("android.NotificationChannel.importance") + .defaultValue()); + } + + /// The same separator rule as imports, applied to the package name: reading + /// it as one contiguous run recorded `com` and rejected the real main source. + @Test + public void aPackageNameMaySpanSeparatorsInSettingsToo() { + assertTrue(CodenameOneSettings.declaresClass( + "package com /* generated */ . example;\npublic class MyApp {}\n", + "MyApp", "com.example", false)); + assertTrue(CodenameOneSettings.declaresClass( + "package com\n . example\nclass MyApp\n", "MyApp", "com.example", true)); + assertFalse(CodenameOneSettings.declaresClass( + "package com . other;\npublic class MyApp {}\n", "MyApp", "com.example", false)); + } + + /// A fully qualified annotation may carry separators between components, and + /// matching a contiguous literal could not see it -- ownership read as empty + /// and Add wrote the duplicate. + @Test + public void aQualifiedAnnotationMaySpanSeparators() { + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints( + "@com.codename1.annotations. /* generated */ buildhints.Ios(teamId = \"X\")\n" + + "public class MyApp {}\n", out, false); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + + out.clear(); + CodenameOneSettings.collectAnnotationOwnedHints( + "@com.codename1.annotations\n .buildhints\n .Ios(teamId = \"X\")\n" + + "class MyApp\n", out, true); + assertEquals("@Ios(teamId)", out.get("ios.teamId")); + } + + /// Another library's qualified annotation of the same simple name is not ours + /// however it is spaced. + @Test + public void aQualifiedForeignAnnotationIsStillNotOurs() { + java.util.Map out = new java.util.HashMap(); + CodenameOneSettings.collectAnnotationOwnedHints( + "@com.example . other . Ios(teamId = \"X\")\npublic class MyApp {}\n", + out, false); + assertNull(out.get("ios.teamId")); + } + + /// Kotlin block comments NEST. Stopping at the first `*/` ended the comment + /// early, so a commented-out package declaration was read as live code. + @Test + public void aNestedKotlinBlockCommentStaysClosed() { + String kt = "/* docs /* sample */ package old.name */\n" + + "package com.example\nclass MyApp\n"; + assertTrue(CodenameOneSettings.declaresClass(kt, "MyApp", "com.example", true)); + // Java does not nest, so the same text really does end at the inner `*/`. + assertFalse(CodenameOneSettings.declaresClass(kt, "MyApp", "com.example", false)); + } + + /// A Kotlin main class may escape its name in backticks, and + /// `codename1.mainName` holds the name between them. Reading it with the + /// identifier rule recorded an empty name, so the real main source was + /// rejected, nothing knew which hints an annotation already owns, and + /// Settings offered Add for one of them -- the duplicate declaration that + /// fails the next build. + @Test + public void aKotlinEscapedMainNameIsRecognised() { + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\nclass `when` {\n}\n", "when", "com.example")); + assertFalse(CodenameOneSettings.declaresClass( + "package com.example\nclass `when` {\n}\n", "Other", "com.example")); + + // A quote inside an escaped name is legal, and is not the start of a + // literal: reading it as one blanked the declaration that followed. + String quoted = "package com.example\nclass `say\"hi` { }\nclass MyApp { }\n"; + assertTrue(CodenameOneSettings.declaresClass(quoted, "MyApp", "com.example")); } + /// A Kotlin package may escape a COMPONENT -- `package com.`when`` is legal + /// and the class belongs to com.when. Reading only identifier characters + /// recorded `com.`, so the real main source was rejected: nothing knew which + /// hints an annotation already owns, and Settings could write the duplicate + /// properties declaration that the next build rejects. @Test - public void packagedDeveloperGuideCatalogProvidesKnownHintTypes() throws Exception { - try (InputStream in = CodenameOneSettings.class.getResourceAsStream( - "/com/codename1/settings/hints/Advanced-Topics-Under-The-Hood.asciidoc")) { - assertNotNull(in, "The Settings jar should carry the developer-guide build hint table."); - String doc = new String(in.readAllBytes(), StandardCharsets.UTF_8); - BuildHintCatalog catalog = BuildHintCatalog.fromAsciiDoc(doc); - assertEquals(BuildHintType.INTEGER, catalog.get("java.version").type()); - assertEquals(BuildHintType.VERSION, catalog.get("build.cn1Version").type()); - assertEquals(BuildHintType.VERSION, catalog.get("ios.bundleVersion").type()); - assertEquals(BuildHintType.INTEGER, catalog.get("android.targetSDKVersion").type()); - assertEquals(BuildHintType.BOOLEAN, catalog.get("android.useAndroidX").type()); + public void aKotlinPackageMayEscapeAComponent() { + assertTrue(CodenameOneSettings.declaresClass( + "package com.`when`\nclass MyApp {\n}\n", "MyApp", "com.when")); + assertFalse(CodenameOneSettings.declaresClass( + "package com.`when`\nclass MyApp {\n}\n", "MyApp", "com")); + // The first component too, and an ordinary name is unchanged. + assertTrue(CodenameOneSettings.declaresClass( + "package `in`.example\nclass MyApp {\n}\n", "MyApp", "in.example")); + assertTrue(CodenameOneSettings.declaresClass( + "package com.example\nclass MyApp {\n}\n", "MyApp", "com.example")); + } + + /// An import may escape a component too -- `import + /// com.codename1.annotations.`buildhints`.Ios` is legal Kotlin. Reading only + /// identifier characters recorded `com.codename1.annotations.`, so the + /// import went unrecognised, a live @Ios was read as somebody else's, and + /// Settings could write the duplicate the next build refuses. + @Test + public void aKotlinImportMayEscapeAComponent() { + assertTrue(CodenameOneSettings.importsAnnotation( + "package com.example\n" + + "import com.codename1.annotations.`buildhints`.Ios\n" + + "class MyApp\n", "Ios", true)); + // The type name itself, and the on-demand form. + assertTrue(CodenameOneSettings.importsAnnotation( + "package com.example\n" + + "import com.codename1.annotations.buildhints.`Ios`\n" + + "class MyApp\n", "Ios", true)); + // An escaped ALIAS is the name the file then uses -- read through the + // reader for aliases, which is what an aliased import belongs to. + assertEquals("when", CodenameOneSettings.kotlinImportAlias( + "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as `when`\n" + + "class MyApp\n", "Ios", true)); + // Somebody else's package is still somebody else's. + assertFalse(CodenameOneSettings.importsAnnotation( + "package com.example\n" + + "import com.other.`buildhints`.Ios\n" + + "class MyApp\n", "Ios", true)); + } + + /// Kotlin can rename a type in the FILE, with no import involved: + /// `typealias AppIos = Ios` and then `@AppIos(...)`. The compiled + /// annotation is still ours, so missing it left the hint editable and Add + /// wrote the duplicate declaration the next build refuses. + @Test + public void aKotlinTypeAliasStillOwnsTheHint() { + String src = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias AppIos = Ios\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // The fully qualified right-hand side needs no import. + String qualified = "package com.example\n" + + "typealias AppIos = com.codename1.annotations.buildhints.Ios\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(qualified, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // Somebody else's annotation renamed to the same alias is not ours. + String theirs = "package com.example\n" + + "typealias AppIos = com.other.Ios\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(theirs, owned, true); + assertNull(owned.get("ios.teamId")); + + // Java has no typealias, so the same text owns nothing there. + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned, false); + assertNull(owned.get("ios.teamId")); + } + + /// A file may name the same annotation twice. Answering with the first + /// alias left the one actually used unrecognised, so the hint read as + /// unowned and Add wrote the duplicate the next build refuses. + @Test + public void everyKotlinAliasCounts() { + String twoTypeAliases = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias First = Ios\n" + + "typealias AppIos = Ios\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(twoTypeAliases, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + String twoImportAliases = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as First\n" + + "import com.codename1.annotations.buildhints.Ios as AppIos\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(twoImportAliases, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + } + + /// A `typealias` is a top-level declaration, not a file-scoped one, so it + /// may be written in another file and used on the main class. Looking only + /// at the main source read the hint as unowned, and Add wrote the duplicate + /// the next build refuses. + @Test + public void aTypeAliasFromAnotherFileStillOwnsTheHint() { + String main = "package com.example\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + String sibling = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias AppIos = Ios\n"; + + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, true, + java.util.Collections.singletonList(sibling)); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // Without the sibling there is nothing to resolve the name to. + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, true, null); + assertNull(owned.get("ios.teamId")); + + // An IMPORT alias is file-scoped, so another file's does not apply. + String importAliasElsewhere = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as AppIos\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, true, + java.util.Collections.singletonList(importAliasElsewhere)); + assertNull(owned.get("ios.teamId")); + } + + /// Both languages allow a non-ASCII identifier. Stopping at the first such + /// character read a short name, so the real main source was rejected and + /// Settings could offer a hint an annotation already owns. + @Test + public void aNonAsciiNameIsStillAName() { + assertTrue(CodenameOneSettings.declaresClass( + "package com.\u5e94\u7528;\npublic class MyApp {}\n", "MyApp", "com.\u5e94\u7528")); + assertFalse(CodenameOneSettings.declaresClass( + "package com.\u5e94\u7528;\npublic class MyApp {}\n", "MyApp", "com")); + // The class name too. + assertTrue(CodenameOneSettings.declaresClass( + "package com.example;\npublic class \u5e94\u7528 {}\n", "\u5e94\u7528", + "com.example")); + // An ASCII name is unchanged, and a separator still separates. + assertTrue(CodenameOneSettings.declaresClass( + "package com.example;\npublic class MyApp {}\n", "MyApp", "com.example")); + } + + /// javac translates a unicode escape before it tokenizes anything, so + /// `package com.ex` + an escaped `a` + `mple;` really declares com.example. + /// Reading the text literally recorded `com.ex`, so the real main source was + /// rejected and Settings could offer a hint an annotation already owns. + @Test + public void javaUnicodeEscapesAreTranslatedBeforeTheSourceIsRead() { + String escaped = "package com.ex" + "\\u0061" + "mple;\npublic class MyApp {}\n"; + assertTrue(CodenameOneSettings.declaresClass( + CodenameOneSettings.decodeUnicodeEscapes(escaped), "MyApp", "com.example")); + + // A doubled backslash is not an escape, which is what keeps a string + // literal spelling one. + String literal = "String s = \"" + "\\\\u0041" + "\";"; + assertEquals(literal, CodenameOneSettings.decodeUnicodeEscapes(literal)); + + // Any number of u's is one escape, and a malformed one is left alone. + assertEquals("A", CodenameOneSettings.decodeUnicodeEscapes("\\uuu0041")); + assertEquals("\\uZZZZ", CodenameOneSettings.decodeUnicodeEscapes("\\uZZZZ")); + assertEquals("\\n", CodenameOneSettings.decodeUnicodeEscapes("\\n")); + } + + /// `typealias AppIos = Ios` then `typealias CustomIos = AppIos` is legal, + /// and `@CustomIos(...)` still compiles to our annotation. Accepting only a + /// right-hand side that names the annotation directly left the hint reading + /// as unowned, so Add wrote the duplicate the next build refuses. + @Test + public void aChainOfTypeAliasesIsFollowed() { + String main = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias AppIos = Ios\n" + + "typealias CustomIos = AppIos\n" + + "@CustomIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // The chain may cross files: the link naming our annotation in one, the + // link the main class writes in another. + String usesIt = "package com.example\n" + + "@CustomIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + String declaresIt = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias AppIos = Ios\n" + + "typealias CustomIos = AppIos\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(usesIt, owned, true, + java.util.Collections.singletonList(declaresIt)); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // A chain that never reaches our annotation is not ours, and a cycle + // must not hang the reader. + String theirs = "package com.example\n" + + "typealias AppIos = com.other.Ios\n" + + "typealias CustomIos = AppIos\n" + + "typealias A = B\n" + + "typealias B = A\n" + + "@CustomIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(theirs, owned, true); + assertNull(owned.get("ios.teamId")); + } + + /// Inside a Kotlin template expression the first quote starts a NEW literal + /// rather than closing the outer one, so `"${"@Ios(teamId = x)"}"` ended the + /// string early and exposed its contents as live code -- an annotation + /// nobody wrote, which hid the editor for a hint nothing owns. + @Test + public void aStringInsideATemplateIsStillAString() { + String src = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "class MyApp {\n" + + " val note = \"${\"@Ios(teamId = fake)\"}\"\n" + + "}\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned, true); + assertNull(owned.get("ios.teamId")); + + // A real annotation in the same file is still found. + String real = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp {\n" + + " val note = \"${\"@Ios(pods = fake)\"}\"\n" + + "}\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(real, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + assertNull(owned.get("ios.pods")); + + // The expression is ordinary code, so it holds ordinary comments and + // char literals, and a quote inside one of those is not a nested string. + String commented = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "class Helper {\n" + + " val note = \"${ /* \\\" */ 1 }\"\n" + + "}\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(commented, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // A brace inside the nested literal must not close the expression early. + String braced = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "class MyApp {\n" + + " val note = \"${\"} @Ios(teamId = fake)\"}\"\n" + + "}\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(braced, owned, true); + assertNull(owned.get("ios.teamId")); + } + + /// `import ...Ios as Base` then `typealias AppIos = Base` is legal, and the + /// compiled annotation is still ours. Collecting the two kinds of alias into + /// one list left the typealias unresolved, because its right-hand side names + /// the IMPORT alias rather than the annotation. + @Test + public void aTypeAliasOfAnImportAliasIsFollowed() { + String src = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as Base\n" + + "typealias AppIos = Base\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // An import alias applies only to the file that writes it, so a + // typealias in ANOTHER file naming the same word is not this one. + String usesIt = "package com.example\n" + + "typealias AppIos = Base\n" + + "@AppIos(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + String importsIt = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as Base\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(usesIt, owned, true, + java.util.Collections.singletonList(importsIt)); + assertNull(owned.get("ios.teamId")); + } + + /// An escaped identifier inside a template expression is a NAME: a quote in + /// it does not open a string and a brace does not close the expression. + @Test + public void anEscapedIdentifierInsideATemplateIsNotAString() { + String src = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "class Helper {\n" + + " val note = \"${ `\\\"` }\"\n" + + "}\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + } + + /// A `typealias` is top-level but not global, and visibility is per SYMBOL + /// rather than per package: `import com.other.Unrelated` exposes nothing + /// else from `com.other`, and `import com.other.AppIos as Custom` exposes + /// that one under `Custom`. A package-level answer was wrong both ways -- + /// it let an unrelated import expose an alias, hiding the editor for a hint + /// nothing owns, and it lost the renamed name so a real annotation went + /// unrecognised and Add wrote the duplicate. + @Test + public void aliasVisibilityIsPerSymbol() { + String elsewhere = "package com.other\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias AppIos = Ios\n"; + java.util.List others = java.util.Collections.singletonList(elsewhere); + + // Not imported at all: invisible. + String plain = "package com.example\n@AppIos(teamId = \"X\")\nclass MyApp\n"; + assertTrue(CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(plain, others), "Ios", true).isEmpty()); + + // Another symbol from the same package: still invisible. + String unrelated = "package com.example\n" + + "import com.other.Unrelated\n" + + "@AppIos(teamId = \"X\")\nclass MyApp\n"; + assertTrue(CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(unrelated, others), "Ios", true).isEmpty()); + + // Named: visible under its own name. + String named = "package com.example\n" + + "import com.other.AppIos\n" + + "@AppIos(teamId = \"X\")\nclass MyApp\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(named, others), "Ios", true)); + + // Renamed: visible under the NEW name, and not under the old one. + String renamed = "package com.example\n" + + "import com.other.AppIos as Custom\n" + + "@Custom(teamId = \"X\")\nclass MyApp\n"; + assertEquals(java.util.Collections.singletonList("Custom"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(renamed, others), "Ios", true)); + + // On demand: visible under its own name. + String wildcard = "package com.example\n" + + "import com.other.*\n" + + "@AppIos(teamId = \"X\")\nclass MyApp\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(wildcard, others), "Ios", true)); + + // Same package needs no import. + String samePackage = "package com.other\n@AppIos(teamId = \"X\")\nclass MyApp\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(samePackage, others), "Ios", true)); + } + + /// A chain resolves in the package it is written in, and only its visible + /// end reaches the main file -- under whatever name the import gives it. + @Test + public void aChainResolvesInItsOwnScope() { + String elsewhere = "package com.other\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias Base = Ios\n" + + "typealias AppIos = Base\n"; + String main = "package com.example\n" + + "import com.other.AppIos as Custom\n" + + "@Custom(teamId = \"ABCDE12345\")\nclass MyApp\n"; + + // Custom resolves; Base, which the main file cannot name, does not leak. + assertEquals(java.util.Collections.singletonList("Custom"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Collections.singletonList(elsewhere)), + "Ios", true)); + + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, true, + java.util.Collections.singletonList(elsewhere)); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + } + + /// A chain link may cross a package boundary: `a` declares + /// `typealias Base = Ios`, `b` imports `a.Base` and declares + /// `typealias AppIos = Base`. Looking only in the declaring file's own + /// package stopped the chain there, so the hint read as unowned and Add + /// wrote the duplicate the next build refuses. + @Test + public void aChainLinkMayBeImportedFromAnotherPackage() { + String a = "package a\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias Base = Ios\n"; + String b = "package b\n" + + "import a.Base\n" + + "typealias AppIos = Base\n"; + String main = "package com.example\n" + + "import b.AppIos\n" + + "@AppIos(teamId = \"ABCDE12345\")\nclass MyApp\n"; + java.util.List others = java.util.Arrays.asList(a, b); + + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, others), "Ios", true)); + + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, true, others); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // The renamed form of the link, and the qualified spelling. + String renamedLink = "package b\n" + + "import a.Base as Root\n" + + "typealias AppIos = Root\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Arrays.asList(a, renamedLink)), "Ios", true)); + + String qualifiedLink = "package b\ntypealias AppIos = a.Base\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Arrays.asList(a, qualifiedLink)), "Ios", true)); + + // A link that names nothing reachable is still not ours. + String broken = "package b\ntypealias AppIos = Base\n"; + assertTrue(CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Arrays.asList(a, broken)), "Ios", true).isEmpty()); + } + + /// On a top-level Kotlin declaration `private` means this FILE only, not + /// this package. Exposing another file's private alias let it vouch for an + /// unrelated annotation of the same name, hiding the editor for a hint + /// nothing owns. + @Test + public void aPrivateAliasBelongsToItsFile() { + String sibling = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "private typealias AppIos = Ios\n"; + String main = "package com.example\n@AppIos(teamId = \"X\")\nclass MyApp\n"; + java.util.List others = java.util.Collections.singletonList(sibling); + + assertTrue(CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, others), "Ios", true).isEmpty()); + + // Without the modifier the same declaration is visible in the package. + String shared = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "typealias AppIos = Ios\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Collections.singletonList(shared)), "Ios", true)); + + // A private alias in the MAIN file is the file it belongs to. + String privateHere = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "private typealias AppIos = Ios\n" + + "@AppIos(teamId = \"ABCDE12345\")\nclass MyApp\n"; + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(privateHere, owned, true); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // A comment between the modifier and the keyword is legal, and the + // backward walk skips only whitespace -- so it is read over blanked + // code, where the comment is spaces. + String commented = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "private /* note */ typealias AppIos = Ios\n"; + assertTrue(CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Collections.singletonList(commented)), "Ios", true).isEmpty()); + + // `internal` is module-wide, so it is not this file's alone. + String internal = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "internal typealias AppIos = Ios\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Collections.singletonList(internal)), "Ios", true)); + + // A `private` belonging to whatever came before is not this one's. + String before = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios\n" + + "private val x = 1\n" + + "typealias AppIos = Ios\n"; + assertEquals(java.util.Collections.singletonList("AppIos"), + CodenameOneSettings.kotlinTypeAliases( + CodenameOneSettings.visibleTypeAliases(main, + java.util.Collections.singletonList(before)), "Ios", true)); + } + + /// A same-package type beats an ON-DEMAND import in both languages, so a + /// project with its own `Ios` and a wildcard import of ours writes its own. + /// Reading that as ours hid the editor for a hint the processor never emits. + @Test + public void aSamePackageTypeBeatsAWildcardImport() { + String ownAnnotation = "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "@interface Ios { String teamId(); }\n"; + String main = "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(teamId = \"X\")\n" + + "public class MyApp {}\n"; + + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, false, + java.util.Collections.singletonList(ownAnnotation)); + assertNull(owned.get("ios.teamId")); + + // Declared in the main file itself, which is the same rule one step in. + String declaresItHere = "package com.example;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "@interface Ios { String teamId(); }\n" + + "@Ios(teamId = \"X\")\n" + + "class MyApp {}\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(declaresItHere, owned, false); + assertNull(owned.get("ios.teamId")); + + // With no such type the wildcard import is ours, as before. + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, false); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // A NAMED import is the more specific statement and still wins. + String named = "package com.example;\n" + + "import com.codename1.annotations.buildhints.Ios;\n" + + "@Ios(teamId = \"X\")\n" + + "public class MyApp {}\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(named, owned, false, + java.util.Collections.singletonList(ownAnnotation)); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // A Kotlin main class with a Java peer, which a mixed project has. The + // peer is read in ITS language, and the languages genuinely disagree: + // a block comment nests in Kotlin and does not in Java, so `/* /* */` + // ends here and leaves the package declaration live -- read by Kotlin's + // rules the comment never closes and the peer lands in the default + // package, shadowing nothing. + String javaPeer = "/* /* */\n" + + "package com.example;\n" + + "@interface Ios { String teamId(); }\n"; + String kotlinMainWithJavaPeer = "package com.example\n" + + "import com.codename1.annotations.buildhints.*\n" + + "@Ios(teamId = \"X\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectOwnedHints(kotlinMainWithJavaPeer, owned, true, + java.util.Collections.singletonList( + new CodenameOneSettings.PeerSource(javaPeer, false))); + assertNull(owned.get("ios.teamId")); + + // The same peer read as Kotlin is the bug, stated as a test. + owned.clear(); + CodenameOneSettings.collectOwnedHints(kotlinMainWithJavaPeer, owned, true, + java.util.Collections.singletonList( + new CodenameOneSettings.PeerSource(javaPeer, true))); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // A file-private Kotlin type in a PEER shadows nothing either: on a + // top-level declaration `private` means that file only. + String privatePeer = "package com.example\n" + + "private annotation class Ios(val teamId: String)\n"; + String ktMain = "package com.example\n" + + "import com.codename1.annotations.buildhints.*\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectOwnedHints(ktMain, owned, true, + java.util.Collections.singletonList( + new CodenameOneSettings.PeerSource(privatePeer, true))); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // Without the modifier the same peer shadows. + String sharedPeer = "package com.example\n" + + "annotation class Ios(val teamId: String)\n"; + owned.clear(); + CodenameOneSettings.collectOwnedHints(ktMain, owned, true, + java.util.Collections.singletonList( + new CodenameOneSettings.PeerSource(sharedPeer, true))); + assertNull(owned.get("ios.teamId")); + + // A private type in the MAIN file is in the file it belongs to. + String privateHere = "package com.example\n" + + "import com.codename1.annotations.buildhints.*\n" + + "private annotation class Ios(val teamId: String)\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectOwnedHints(privateHere, owned, true, null); + assertNull(owned.get("ios.teamId")); + + // A peer in ANOTHER package shadows nothing. + String elsewherePeer = "package com.other;\n@interface Ios { String teamId(); }\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(main, owned, false, + java.util.Collections.singletonList(elsewherePeer)); + assertEquals("@Ios(teamId)", owned.get("ios.teamId")); + + // Kotlin declares an annotation with `annotation class`. + String kotlinOwn = "package com.example\n" + + "annotation class Ios(val teamId: String)\n"; + String kotlinMain = "package com.example\n" + + "import com.codename1.annotations.buildhints.*\n" + + "@Ios(teamId = \"X\")\n" + + "class MyApp\n"; + owned.clear(); + CodenameOneSettings.collectAnnotationOwnedHints(kotlinMain, owned, true, + java.util.Collections.singletonList(kotlinOwn)); + assertNull(owned.get("ios.teamId")); + } + + /// Where the peer sweep looks. An allow-list of roots, not a walk of the + /// whole project with exclusions -- those were never going to be complete: + /// `src/test` was followed by `src/testFixtures`, then `src/main/resources`, + /// then `src/main/templates` and `src/main/proto`, because "not a source + /// root" is not a property of a directory's name. + @Test + public void thePeerSweepLooksInTheSourceRootsOnly() { + java.util.List maven = + CodenameOneSettings.candidateSourceRoots("/p/common", true); + assertTrue(maven.contains("/p/common/src/main/java")); + assertTrue(maven.contains("/p/common/src/main/kotlin")); + // Generated sources are a compile root that plugins add. + assertTrue(maven.contains("/p/common/target/generated-sources")); + + // Everything the exclusion list used to chase is simply not a root. + for (String notARoot : new String[] {"/p/common/src/test", "/p/common/src/testFixtures", + "/p/common/src/integrationTest", "/p/common/src/main/resources", + "/p/common/src/main/templates", "/p/common/src/main/proto", + "/p/common/target", "/p/common/build"}) { + assertFalse(maven.contains(notARoot), maven.toString()); } + + // The flat layout keeps its own root, and only there: under a Maven + // layout `src` would drag the test sets back in. + assertFalse(maven.contains("/p/common/src")); + java.util.List flat = + CodenameOneSettings.candidateSourceRoots("/p/common", false); + assertTrue(flat.contains("/p/common/src")); + + assertTrue(CodenameOneSettings.candidateSourceRoots(null, false).isEmpty()); + } + + /// The compiler's source encoding is a project setting this tool does not + /// have, and decoding a single-byte source as UTF-8 produced replacement + /// characters -- so a non-ASCII package or class name never matched + /// `codename1.packageName` and the real main source was rejected. + @Test + public void aSourceIsReadInTheEncodingItIsWrittenIn() throws Exception { + String text = "package com.caf\u00e9;\npublic class MyApp {}\n"; + + // A UTF-8 source decodes as UTF-8... + byte[] utf8 = text.getBytes("UTF-8"); + assertTrue(CodenameOneSettings.isValidUtf8(utf8)); + assertTrue(CodenameOneSettings.declaresClass( + new String(utf8, "UTF-8"), "MyApp", "com.caf\u00e9")); + + // ...and a single-byte one does not, so it is read as ISO-8859-1, which + // is what it is. + byte[] latin1 = text.getBytes("ISO-8859-1"); + assertFalse(CodenameOneSettings.isValidUtf8(latin1)); + assertTrue(CodenameOneSettings.declaresClass( + new String(latin1, "ISO-8859-1"), "MyApp", "com.caf\u00e9")); + // Read as UTF-8 instead it is mojibake, which is the bug. + assertFalse(CodenameOneSettings.declaresClass( + new String(latin1, "UTF-8"), "MyApp", "com.caf\u00e9")); + + // Plain ASCII decodes either way, so nothing about the common case moves. + assertTrue(CodenameOneSettings.isValidUtf8("package com.example;\n".getBytes("UTF-8"))); + + // The shapes the validity check exists to reject. + assertFalse(CodenameOneSettings.isValidUtf8(new byte[] {(byte) 0xC3})); + assertFalse(CodenameOneSettings.isValidUtf8(new byte[] {(byte) 0xC0, (byte) 0xAF})); + assertFalse(CodenameOneSettings.isValidUtf8(new byte[] {(byte) 0xED, (byte) 0xA0, + (byte) 0x80})); + assertTrue(CodenameOneSettings.isValidUtf8(new byte[] {(byte) 0xF0, (byte) 0x9F, + (byte) 0x98, (byte) 0x80})); + } + + /// `static` is a modifier, not the imported name. Reading it as the name + /// recorded an import called `static`, so + /// `import static com.example.Types.Ios;` never registered as giving `Ios` + /// away -- a wildcard import of ours was trusted instead and the editor was + /// hidden for a hint the processor never emits. + @Test + public void aSingleStaticImportTakesTheNameToo() { + String src = "package com.example;\n" + + "import static com.example.Types.Ios;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(teamId = \"X\")\n" + + "public class MyApp {}\n"; + assertFalse(CodenameOneSettings.importsAnnotation(src, "Ios", false)); + + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(src, owned, false); + assertNull(owned.get("ios.teamId")); + + // A static import of something else leaves our wildcard alone. + String other = "package com.example;\n" + + "import static com.example.Types.OTHER;\n" + + "import com.codename1.annotations.buildhints.*;\n" + + "@Ios(teamId = \"X\")\n" + + "public class MyApp {}\n"; + assertTrue(CodenameOneSettings.importsAnnotation(other, "Ios", false)); + + // A name that merely starts with `static` is a name. + String staticky = "package com.example;\n" + + "import staticky.Ios;\n" + + "@Ios(teamId = \"X\")\n" + + "public class MyApp {}\n"; + assertFalse(CodenameOneSettings.importsAnnotation(staticky, "Ios", false)); + assertEquals("staticky.Ios", CodenameOneSettings.importsIn(staticky, false).get(0).name); + } + + /// `import com.example.Other as Ios` makes `@Ios` mean Other, so it shadows + /// a wildcard import of ours. Ignoring every aliased import let the wildcard + /// be trusted, hiding the editor for a hint the processor never emits. + @Test + public void anImportAliasedToOurNameShadowsTheWildcard() { + String shadowed = "package com.example\n" + + "import com.example.other.Other as Ios\n" + + "import com.codename1.annotations.buildhints.*\n" + + "@Ios(teamId = \"X\")\n" + + "class MyApp\n"; + assertFalse(CodenameOneSettings.importsAnnotation(shadowed, "Ios", true)); + java.util.Map owned = new java.util.HashMap<>(); + CodenameOneSettings.collectAnnotationOwnedHints(shadowed, owned, true); + assertNull(owned.get("ios.teamId")); + + // OUR annotation aliased to its own name is still ours. + String ours = "package com.example\n" + + "import com.codename1.annotations.buildhints.Ios as Ios\n" + + "@Ios(teamId = \"ABCDE12345\")\n" + + "class MyApp\n"; + assertTrue(CodenameOneSettings.importsAnnotation(ours, "Ios", true)); + + // An alias to some OTHER name shadows nothing. + String elsewhere = "package com.example\n" + + "import com.example.other.Other as Something\n" + + "import com.codename1.annotations.buildhints.*\n" + + "@Ios(teamId = \"X\")\n" + + "class MyApp\n"; + assertTrue(CodenameOneSettings.importsAnnotation(elsewhere, "Ios", true)); + } + + /// The guess can only tell UTF-8 from a single-byte encoding, so a + /// multibyte one such as Shift_JIS came back as mojibake and its non-ASCII + /// names never matched. What the project SAYS it is written in settles it, + /// when it says. + @Test + public void thePomsDeclaredSourceEncodingIsUsed() throws Exception { + assertEquals("Shift_JIS", CodenameOneSettings.declaredSourceEncoding( + "" + + "Shift_JIS" + + "")); + // The compiler plugin's own setting counts too -- and only that + // plugin's; see theEncodingIsTheCompilerPluginsOwn. + assertEquals("Shift_JIS", CodenameOneSettings.declaredSourceEncoding( + "" + + "maven-compiler-plugin" + + "Shift_JIS" + + "")); + // Nothing declared is nothing to use, and the guess stays. + assertNull(CodenameOneSettings.declaredSourceEncoding("")); + assertNull(CodenameOneSettings.declaredSourceEncoding(null)); + // An unresolved property is not an encoding: this reader has no model to + // resolve it against, and passing it on would throw on every file. + assertNull(CodenameOneSettings.declaredSourceEncoding( + "${enc}" + + "")); + + // And it decodes what the guess could not: a multibyte source whose + // package name is only readable in its own encoding. + String text = "package com.\u30a2\u30d7\u30ea;\npublic class MyApp {}\n"; + byte[] sjis = text.getBytes("Shift_JIS"); + assertFalse(CodenameOneSettings.isValidUtf8(sjis)); + assertTrue(CodenameOneSettings.declaresClass( + new String(sjis, "Shift_JIS"), "MyApp", "com.\u30a2\u30d7\u30ea")); + assertFalse(CodenameOneSettings.declaresClass( + new String(sjis, "ISO-8859-1"), "MyApp", "com.\u30a2\u30d7\u30ea")); + } + + /// A module may put its sources somewhere else entirely, and the main class + /// is the one file the root list cannot afford to miss: without it nothing + /// knows which hints an annotation owns, and Add writes the duplicate the + /// next build refuses. + @Test + public void theRootsThePomDeclaresAreSearchedToo() { + java.util.List roots = CodenameOneSettings.declaredSourceRoots( + "" + + "appsrc" + + "" + + "build-helper-maven-plugin" + + "add-source" + + "" + + "src/generated/java" + + "" + + "kotlin-maven-plugin" + + "" + + "src/main/kt" + + "" + + ""); + assertTrue(roots.contains("appsrc"), roots.toString()); + assertTrue(roots.contains("src/generated/java"), roots.toString()); + assertTrue(roots.contains("src/main/kt"), roots.toString()); + + // A declared TEST root is dropped: those are configured through the same + // elements, and one shadowing a production type is the failure the root + // list exists to avoid. + java.util.List withTests = CodenameOneSettings.declaredSourceRoots( + "" + + "appsrc" + + "src/test/java" + + "build-helper-maven-plugin" + + "add-source" + + "" + + "src/integrationTest/java" + + "" + + ""); + assertTrue(withTests.contains("appsrc"), withTests.toString()); + assertFalse(withTests.contains("src/test/java"), withTests.toString()); + assertFalse(withTests.contains("src/integrationTest/java"), withTests.toString()); + + // `` and `` are ordinary words: another plugin naming + // a directory in one is not saying it is compiled. + java.util.List unrelated = CodenameOneSettings.declaredSourceRoots( + "" + + "some-other-plugin" + + "src/main/templates" + + "" + + ""); + assertTrue(unrelated.isEmpty(), unrelated.toString()); + + // build-helper's add-test-source uses the same element as add-source. + java.util.List helper = CodenameOneSettings.declaredSourceRoots( + "" + + "build-helper-maven-plugin" + + "add-source" + + "gen/main" + + "add-test-source" + + "gen/fixtures" + + "" + + "" + + ""); + assertTrue(helper.contains("gen/main"), helper.toString()); + assertFalse(helper.contains("gen/fixtures"), helper.toString()); + + // The Kotlin plugin's test-compile execution uses the same element, and + // a test directory whose NAME does not look like one is otherwise read + // as production code. + java.util.List kotlin = CodenameOneSettings.declaredSourceRoots( + "" + + "kotlin-maven-plugin" + + "compile" + + "src/main/kt" + + "" + + "test-compile" + + "fixtures" + + "" + + ""); + assertTrue(kotlin.contains("src/main/kt"), kotlin.toString()); + assertFalse(kotlin.contains("fixtures"), kotlin.toString()); + + // Plugin-level configuration applies to every execution, so it counts + // alongside them rather than being dropped when executions exist. + java.util.List both = CodenameOneSettings.declaredSourceRoots( + "" + + "kotlin-maven-plugin" + + "src/shared/kt" + + "" + + "" + + "compile" + + "src/main/kt" + + "" + + "test-compile" + + "fixtures" + + "" + + ""); + assertTrue(both.contains("src/shared/kt"), both.toString()); + assertTrue(both.contains("src/main/kt"), both.toString()); + assertFalse(both.contains("fixtures"), both.toString()); + + // A project-directory expression is deterministic, so it is resolved + // rather than discarded. + java.util.List expression = CodenameOneSettings.declaredSourceRoots( + "${project.basedir}/appsrc" + + ""); + assertTrue(expression.contains("${project.basedir}/appsrc"), expression.toString()); + assertEquals("/p/common/appsrc", + CodenameOneSettings.expandProjectPaths("${project.basedir}/appsrc", "/p/common")); + assertEquals("/p/common/target/generated", + CodenameOneSettings.expandProjectPaths("${project.build.directory}/generated", + "/p/common")); + + // What it still cannot resolve it leaves alone rather than guessing. + assertTrue(CodenameOneSettings.declaredSourceRoots( + "${custom.dir}/x" + + "").isEmpty()); + assertNull(CodenameOneSettings.expandProjectPaths("${custom.dir}/x", "/p/common")); + assertTrue(CodenameOneSettings.declaredSourceRoots(null).isEmpty()); + } + + /// maven-resources-plugin declares an `` of its own, and taking + /// the first one in the file adopted the resource charset for every source. + @Test + public void theEncodingIsTheCompilerPluginsOwn() { + String pom = "" + + "maven-resources-plugin" + + "ISO-8859-1" + + "maven-compiler-plugin" + + "UTF-8" + + ""; + assertEquals("UTF-8", CodenameOneSettings.declaredSourceEncoding(pom)); + + // With no compiler encoding at all, another plugin's is not adopted. + String resourcesOnly = "" + + "maven-resources-plugin" + + "ISO-8859-1" + + ""; + assertNull(CodenameOneSettings.declaredSourceEncoding(resourcesOnly)); + + // The property still wins, since that is what the convention is. + String property = "" + + "Shift_JIS" + + "" + resourcesOnly.substring("".length()); + assertEquals("Shift_JIS", CodenameOneSettings.declaredSourceEncoding(property)); + } + + /// `project.build.sourceEncoding` is normally declared once in the parent, + /// which is where a multi-module Codename One project puts it -- so looking + /// only at the bound module POM found nothing in the standard layout. + @Test + public void theParentPomIsPartOfTheChain() { + // Maven's own default when a parent is declared without a relativePath. + assertEquals("/p/pom.xml", + CodenameOneSettings.parentPomPath("/p/common/pom.xml", + "root")); + + // An explicit relativePath, to a file or to a directory. + assertEquals("/p/build/pom.xml", + CodenameOneSettings.parentPomPath("/p/common/pom.xml", + "../build/pom.xml" + + "")); + assertEquals("/p/build/pom.xml", + CodenameOneSettings.parentPomPath("/p/common/pom.xml", + "../build" + + "")); + + // No parent is the end of the chain, and an empty relativePath means + // "from the repository", which this reader cannot follow. + assertNull(CodenameOneSettings.parentPomPath("/p/common/pom.xml", "")); + assertNull(CodenameOneSettings.parentPomPath("/p/common/pom.xml", + "")); + + // The path arithmetic the walk depends on. + assertEquals("/p/pom.xml", CodenameOneSettings.normalizePath("/p/common/../pom.xml")); + assertEquals("/p/a/pom.xml", + CodenameOneSettings.normalizePath("/p/common/./../a/pom.xml")); + assertEquals("a/pom.xml", CodenameOneSettings.normalizePath("b/../a/pom.xml")); + } + + /// `${project.build.directory}` is `target` by default and whatever + /// `` says otherwise -- hard-coding `target` sent the + /// search to a directory a project that overrides it does not compile from. + @Test + public void theConfiguredBuildDirectoryIsUsed() { + assertEquals("out", CodenameOneSettings.configuredBuildDirectory( + "out")); + assertEquals("/p/common/out/generated-sources", + CodenameOneSettings.expandProjectPaths( + "${project.build.directory}/generated-sources", "/p/common", "out")); + + // The default when nothing configures one. + assertNull(CodenameOneSettings.configuredBuildDirectory("")); + assertEquals("/p/common/target/generated-sources", + CodenameOneSettings.expandProjectPaths( + "${project.build.directory}/generated-sources", "/p/common", null)); + + // A DIRECT child: resources and the plugin sections carry `` + // elements of their own, and taking the first would read a resource + // directory as the output directory. + assertNull(CodenameOneSettings.configuredBuildDirectory( + "" + + "src/main/resources" + + "")); + assertEquals("out", CodenameOneSettings.configuredBuildDirectory( + "" + + "src/main/resources" + + "out")); + + // An absolute one is taken as it stands. + assertEquals("/elsewhere/gen", CodenameOneSettings.expandProjectPaths( + "${project.build.directory}/gen", "/p/common", "/elsewhere")); + } + + /// A profile this reader cannot evaluate is left out rather than merged in. + /// An inactive `src/preview` was read as + /// a production root, so a type kept there shadowed the real annotation -- + /// and activation depends on properties, files, the JDK and the OS, none of + /// which this tool has a model for. + @Test + public void anInactiveProfileIsNotTheBuild() { + String pom = "appsrc" + + "" + + "previewpreview" + + "" + + "src/preview" + + "always" + + "true" + + "src/always" + + ""; + java.util.List roots = CodenameOneSettings.declaredSourceRoots(pom); + assertTrue(roots.contains("appsrc"), roots.toString()); + // Active by default is knowable, so it counts. + assertTrue(roots.contains("src/always"), roots.toString()); + // Conditionally active is not, so it does not. + assertFalse(roots.contains("src/preview"), roots.toString()); + } + + /// `${project.basedir}/out` is legal and resolvable; + /// discarding it sent the search to `target` for a project that compiles + /// somewhere else. + @Test + public void theBuildDirectoryMayUseAnExpression() { + assertEquals("${project.basedir}/out", CodenameOneSettings.configuredBuildDirectory( + "${project.basedir}/out")); + assertEquals("/p/common/out/gen", CodenameOneSettings.expandProjectPaths( + "${project.build.directory}/gen", "/p/common", "/p/common/out")); + + // The expansion the build directory itself gets: the basedir family. + assertEquals("/p/common/out", + CodenameOneSettings.expandBasedir("${project.basedir}/out", "/p/common")); + assertEquals("/p/common/out", + CodenameOneSettings.expandBasedir("${basedir}/out", "/p/common")); + assertEquals("out", CodenameOneSettings.expandBasedir("out", "/p/common")); + + // NOT a reference to itself: the general expander resolves that one to + // `target`, which would quietly make a self-reference mean the default. + assertNull(CodenameOneSettings.expandBasedir("${project.build.directory}/x", "/p/common")); + assertNull(CodenameOneSettings.expandBasedir("${custom.dir}/x", "/p/common")); + } + + /// The roots the launcher resolved are read, not merely carried. Path + /// separated, since a comma is legal in a directory name. + @Test + public void theResolvedRootsAreParsed() { + assertEquals(java.util.Arrays.asList("/p/common/src/main/java", "/p/common/appsrc"), + CodenameOneSettings.splitRoots("/p/common/src/main/java:/p/common/appsrc")); + assertEquals(java.util.Arrays.asList("/a", "/b"), + CodenameOneSettings.splitRoots("/a;/b")); + + // A Windows drive letter belongs to the path that follows it. + assertEquals(java.util.Arrays.asList("C:/p/src", "D:/other"), + CodenameOneSettings.splitRoots("C:/p/src;D:/other")); + + assertTrue(CodenameOneSettings.splitRoots(null).isEmpty()); + assertTrue(CodenameOneSettings.splitRoots(" ").isEmpty()); } } diff --git a/scripts/settings/common/src/test/java/com/codename1/settings/ProjectIOTest.java b/scripts/settings/common/src/test/java/com/codename1/settings/ProjectIOTest.java index a10ff1da57b..8ef2bfb8fac 100644 --- a/scripts/settings/common/src/test/java/com/codename1/settings/ProjectIOTest.java +++ b/scripts/settings/common/src/test/java/com/codename1/settings/ProjectIOTest.java @@ -65,4 +65,26 @@ public void bindingParserKeepsWindowsBackslashesVerbatim() { assertEquals("C:\\Users\\John Smith\\My App", b.projectDir()); assertEquals("C:\\Users\\John Smith\\My App\\codenameone_settings.properties", b.settings()); } + + /// What Maven RESOLVED, so the tool does not have to infer it from POM + /// text: it has no model for profile activation, inheritance or property + /// expansion, and each of those has been a way for it to miss the main + /// class and then offer an annotation-owned hint for editing. + @Test + public void theBindingCarriesTheResolvedSourceRootsAndEncoding() { + ProjectBinding b = ProjectBinding.parse( + "projectDir=/p/common\n" + + "settings=/p/common/codenameone_settings.properties\n" + + "sourceRoots=/p/common/src/main/java:/p/common/appsrc\n" + + "sourceEncoding=Shift_JIS\n"); + assertEquals("/p/common/src/main/java:/p/common/appsrc", b.sourceRoots()); + assertEquals("Shift_JIS", b.sourceEncoding()); + + // A binding written by an older plugin says neither, and the tool falls + // back to reading the POM itself. + ProjectBinding older = ProjectBinding.parse( + "projectDir=/p/common\nsettings=/p/common/codenameone_settings.properties\n"); + assertNull(older.sourceRoots()); + assertNull(older.sourceEncoding()); + } } diff --git a/scripts/settings/common/src/test/java/com/codename1/settings/SettingsThemeTest.java b/scripts/settings/common/src/test/java/com/codename1/settings/SettingsThemeTest.java index 44e7bd45a73..edcd91bc988 100644 --- a/scripts/settings/common/src/test/java/com/codename1/settings/SettingsThemeTest.java +++ b/scripts/settings/common/src/test/java/com/codename1/settings/SettingsThemeTest.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2012, 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.codename1.settings; import com.codename1.ui.css.CSSThemeCompiler; @@ -111,7 +133,10 @@ public void activeBuildHintControlsStayAlignedToTheRight() throws Exception { String source = Files.readString(APP_SOURCE, StandardCharsets.UTF_8); assertTrue(source.contains("widthPercentage(72), new Container()")); assertTrue(source.contains("widthPercentage(28), controls")); - assertTrue(source.contains("controls.add(BorderLayout.EAST, remove)")); + // The delete control is EAST of the editor. The button itself moved into + // removeHintButton so the conflict row can reuse it -- what this asserts + // is where it sits, which is unchanged. + assertTrue(source.contains("controls.add(BorderLayout.EAST, removeHintButton(meta))")); } @Test @@ -125,7 +150,12 @@ public void uiUsesDensityAwareThemeSizingInsteadOfFixedComponentDimensions() thr "Theme font sizes must use physical mm units so Retina density does not create miniature text."); assertTrue(source.contains("new TableLayout(1, 2)"), "The main content width should be responsive through TableLayout percentages."); - assertTrue(source.contains("new GridLayout(3, 2)"), + // Match the column count, not the row count. This asserted GridLayout(3, 2) + // and the Basic form has grown to five rows since; because this module's + // tests are skipped by default nothing reported the drift. The two columns + // are what makes the form responsive -- the row count is just how many + // fields there happen to be. + assertTrue(Pattern.compile("new GridLayout\\(\\d+, 2\\)").matcher(source).find(), "The Basic form should use a responsive two-column GridLayout."); assertTrue(source.contains("private Container configureToolbar()"), "Native desktop chrome should use a stable top-bar container, not a second Toolbar instance."); diff --git a/scripts/settings/pom.xml b/scripts/settings/pom.xml index ac7954b0357..24c27fa99d2 100644 --- a/scripts/settings/pom.xml +++ b/scripts/settings/pom.xml @@ -68,6 +68,11 @@ codenameone-javase ${cn1.version}
+ + com.codenameone + codenameone-build-hint-catalog + ${cn1.version} +
diff --git a/scripts/video-builder/common/codenameone_settings.properties b/scripts/video-builder/common/codenameone_settings.properties index b7f6775b36e..4dbecd58940 100644 --- a/scripts/video-builder/common/codenameone_settings.properties +++ b/scripts/video-builder/common/codenameone_settings.properties @@ -5,7 +5,4 @@ codename1.version=1.0 codename1.vendor=CodenameOne codename1.cssTheme=true codename1.arg.java.version=17 -codename1.arg.desktop.width=1280 -codename1.arg.desktop.height=720 -codename1.arg.desktop.titleBar=native codename1.kotlin=false diff --git a/scripts/video-builder/common/pom.xml b/scripts/video-builder/common/pom.xml index 5a9f0e5d5c8..54c1ef39659 100644 --- a/scripts/video-builder/common/pom.xml +++ b/scripts/video-builder/common/pom.xml @@ -38,7 +38,13 @@ compile-css process-classes - css + + css + + process-annotations + diff --git a/scripts/video-builder/common/src/main/java/com/codename1/videobuilder/VideoBuilder.java b/scripts/video-builder/common/src/main/java/com/codename1/videobuilder/VideoBuilder.java index 00dc4e27788..5883947d9b8 100644 --- a/scripts/video-builder/common/src/main/java/com/codename1/videobuilder/VideoBuilder.java +++ b/scripts/video-builder/common/src/main/java/com/codename1/videobuilder/VideoBuilder.java @@ -37,8 +37,10 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; +import com.codename1.annotations.buildhints.*; /** Codename One application lifecycle and CLI dispatcher. */ +@Desktop(height = 720, titleBar = DesktopTitleBar.NATIVE, width = 1280) public final class VideoBuilder { private Form current; diff --git a/scripts/website/build.sh b/scripts/website/build.sh index 737a9f00fa9..e9646e8c501 100755 --- a/scripts/website/build.sh +++ b/scripts/website/build.sh @@ -321,6 +321,11 @@ build_developer_guide_for_site() { local build_date build_date="$(date +%Y-%m-%d)" + # The guide includes a build hint table that is rendered from + # maven/build-hint-catalog rather than checked in, so it has to exist before + # asciidoctor resolves the include. + "${REPO_ROOT}/scripts/gen-build-hint-table.sh" + ( cd "${REPO_ROOT}" asciidoctor \ diff --git a/tools/build-hint-bootstrap/README.md b/tools/build-hint-bootstrap/README.md new file mode 100644 index 00000000000..f27e5ef8641 --- /dev/null +++ b/tools/build-hint-bootstrap/README.md @@ -0,0 +1,23 @@ +# Build hint catalog bootstrap (one-off, archived) + +These scripts seeded `maven/build-hint-catalog` when the catalog was first +created. They mined every `getArg` call site in the builders for a hint's name +and default, imported the prose from the developer guide's hand-written build +hint table, and emitted the `BuildHints*.java` registration classes. + +**They are not part of any build and should not be re-run.** The catalog is the +source of truth now and is edited directly; `scripts/gen-build-hint-annotations.sh` +generates the annotations, the docs and the Settings schema *from* it. + +They are kept only to show where the catalog's contents came from. They read the +guide's original hand-written table from a `guide_old.asciidoc` that is +deliberately not committed — recover it from history if you ever need it: + +```bash +git show :docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc \ + > tools/build-hint-bootstrap/guide_old.asciidoc +``` + +Re-running them would overwrite hand-edits to the catalog. If you ever need to +re-derive an entry, read the miner instead: `scripts/build_hint_miner.py` is the +supported, tested version of the same extraction and is what the CI gate uses. diff --git a/tools/build-hint-bootstrap/curation.py b/tools/build-hint-bootstrap/curation.py new file mode 100644 index 00000000000..7ca8c27d14e --- /dev/null +++ b/tools/build-hint-bootstrap/curation.py @@ -0,0 +1,220 @@ +# The curated set: hints exposed as typed annotation attributes. +# +# name -> (group, attribute, enum-or-None, forced-type-or-None, forced-default-or-None) +# +# TYPE_OVERRIDES below carries the hints whose type cannot be inferred from a +# literal default -- the call site computes one -- but whose type is unambiguous +# in the code that reads it. Without them a boolean hint is exposed as a String +# attribute, which is barely better than the properties file. +# +# Every enum domain below was read off the code that consumes the hint, not +# guessed from a name or a doc sentence. Where the consumer accepts alias +# spellings (ios.themeMode takes "liquid" for "modern"), the enum exposes the +# canonical spelling only: on the annotation path an over-tight domain costs a +# fallback to the properties file, never a broken build, and the aliases stay +# reachable there. + +ENUMS = { + # HardeningPreflight.java:90 rejects anything else outright. + "HardenLevel": ["off", "standard", "aggressive", "paranoid"], + "HardenStrings": ["off", "constants", "all"], + "HardenControlFlow": ["off", "on"], + # BuildHintSchemaDefaults.registerNativeTheme + JavaSEPort.resolveAutoNativeTheme + "NativeThemeMode": ["modern", "legacy", "custom"], + "IosThemeMode": ["auto", "modern", "ios7", "legacy"], + "AndroidThemeMode": ["auto", "modern", "hololight", "legacy"], + # GenerateDesktopAppWrapperMojo.sanitizeTitleBarMode warns and silently + # falls back to "native" on anything else -- the exact silent-typo case. + "DesktopTitleBar": ["native", "custom", "toolbar"], + # IOSDependencyManager.fromHint throws on anything else. + "IosDependencyManager": ["auto", "cocoapods", "spm", "both", "none"], + # "one of ios, ipad, iphone (defaults to ios)" -- the guide states it and + # the value is passed straight through to ParparVM (IPhoneBuilder.java:4572). + "IosProjectType": ["ios", "ipad", "iphone"], + # The three values android:installLocation itself accepts. + "InstallLocation": ["auto", "internalOnly", "preferExternal"], +} + +CURATED = { + # ---- @Ios ------------------------------------------------------------- + "ios.newStorageLocation": ("IOS", "newStorageLocation", None, None, None), + "ios.deployment_target": ("IOS", "deploymentTarget", None, "VERSION", None), + "ios.minDeploymentTarget": ("IOS", "minDeploymentTarget", None, "VERSION", "6.0"), + "ios.teamId": ("IOS", "teamId", None, None, None), + "ios.includePush": ("IOS", "includePush", None, None, None), + "ios.add_libs": ("IOS", "addLibs", None, None, None), + "ios.pods": ("IOS", "pods", None, None, None), + "ios.pods.platform": ("IOS", "podsPlatform", None, "VERSION", None), + "ios.pods.sources": ("IOS", "podsSources", None, None, None), + "ios.applicationQueriesSchemes": ("IOS", "applicationQueriesSchemes", None, None, None), + "ios.objC": ("IOS", "objC", None, None, None), + "ios.plistInject": ("IOS", "plistInject", None, None, None), + "ios.glAppDelegateHeader": ("IOS", "glAppDelegateHeader", None, None, None), + "ios.beforeFinishLaunching": ("IOS", "beforeFinishLaunching", None, None, None), + "ios.themeMode": ("IOS", "themeMode", "IosThemeMode", None, None), + "ios.interface_orientation": ("IOS", "interfaceOrientation", None, None, None), + "ios.project_type": ("IOS", "projectType", "IosProjectType", None, None), + "ios.prerendered_icon": ("IOS", "prerenderedIcon", None, None, None), + "ios.uiscene": ("IOS", "uiscene", None, None, None), + "ios.urlScheme": ("IOS", "urlScheme", None, None, None), + "ios.dependencyManager": ("IOS", "dependencyManager", "IosDependencyManager", None, None), + "ios.bundleVersion": ("IOS", "bundleVersion", None, "VERSION", None), + "ios.spm.packages": ("IOS", "spmPackages", None, None, None), + # ---- @Android --------------------------------------------------------- + "android.min_sdk_version": ("ANDROID", "minSdkVersion", None, None, None), + "android.targetSDKVersion": ("ANDROID", "targetSDKVersion", None, None, None), + "android.buildToolsVersion": ("ANDROID", "buildToolsVersion", None, None, None), + "android.xpermissions": ("ANDROID", "xpermissions", None, None, None), + "android.xapplication": ("ANDROID", "xapplication", None, None, None), + "android.gradleDep": ("ANDROID", "gradleDep", None, None, None), + "android.proguardKeep": ("ANDROID", "proguardKeep", None, None, None), + "android.release": ("ANDROID", "release", None, None, None), + "android.debug": ("ANDROID", "debug", None, None, None), + "android.useAndroidX": ("ANDROID", "useAndroidX", None, None, None), + "android.licenseKey": ("ANDROID", "licenseKey", None, None, None), + "android.installLocation": ("ANDROID", "installLocation", "InstallLocation", None, None), + "android.activity.launchMode": ("ANDROID", "activityLaunchMode", None, None, None), + "and.themeMode": ("ANDROID", "themeMode", "AndroidThemeMode", None, None), + "android.appBundle": ("ANDROID", "appBundle", None, None, None), + "android.disableR8": ("ANDROID", "disableR8", None, None, None), + "android.enableProguard": ("ANDROID", "enableProguard", None, None, None), + "android.newFirebaseMessaging": ("ANDROID", "newFirebaseMessaging", None, None, None), + "android.multidex": ("ANDROID", "multidex", None, None, None), + "android.captureRecord": ("ANDROID", "captureRecord", None, None, None), + "android.hideStatusBar": ("ANDROID", "hideStatusBar", None, None, None), + "android.repositories": ("ANDROID", "repositories", None, None, None), + "android.topDependency": ("ANDROID", "topDependency", None, None, None), + "android.xgradle": ("ANDROID", "xgradle", None, None, None), + # ---- @Desktop --------------------------------------------------------- + "desktop.titleBar": ("DESKTOP", "titleBar", "DesktopTitleBar", None, None), + "desktop.interactiveScrollbars": ("DESKTOP", "interactiveScrollbars", None, None, None), + "desktop.width": ("DESKTOP", "width", None, "INT", None), + "desktop.height": ("DESKTOP", "height", None, "INT", None), + "desktop.resizable": ("DESKTOP", "resizable", None, None, None), + "desktop.fullscreen": ("DESKTOP", "fullscreen", None, None, None), + "desktop.adaptToRetina": ("DESKTOP", "adaptToRetina", None, None, None), + # ---- @Hardening ------------------------------------------------------- + "harden.level": ("HARDENING", "level", "HardenLevel", None, None), + "harden.strings": ("HARDENING", "strings", "HardenStrings", None, None), + "harden.controlFlow": ("HARDENING", "controlFlow", "HardenControlFlow", None, None), + "harden.rename": ("HARDENING", "rename", None, None, None), + "harden.keep": ("HARDENING", "keep", None, "TEXT_BLOCK", None), + "harden.allowUnhardenedLocalBuild": ("HARDENING", "allowUnhardenedLocalBuild", None, None, None), + # ---- @OnDeviceDebug --------------------------------------------------- + "ios.onDeviceDebug": ("ON_DEVICE_DEBUG", "ios", None, None, None), + "ios.onDeviceDebug.proxyHost": ("ON_DEVICE_DEBUG", "iosProxyHost", None, None, None), + "ios.onDeviceDebug.proxyPort": ("ON_DEVICE_DEBUG", "iosProxyPort", None, "INT", None), + "ios.onDeviceDebug.waitForAttach": ("ON_DEVICE_DEBUG", "iosWaitForAttach", None, None, None), + "android.onDeviceDebug": ("ON_DEVICE_DEBUG", "android", None, None, None), + # ---- @Build ----------------------------------------------------------- + "nativeTheme": ("GENERAL", "nativeTheme", "NativeThemeMode", None, None), + "gcm.sender_id": ("GENERAL", "gcmSenderId", None, None, None), + "facebook.appId": ("GENERAL", "facebookAppId", None, None, None), + "noExtraResources": ("GENERAL", "noExtraResources", None, None, None), +} + +# ios.NS*UsageDescription -> @IosPrivacy, attribute is the key minus "ios.NS" +# with a lowercased first letter; the UsageDescription suffix is kept so the +# plist key it maps to is mechanically recoverable. +PRIVACY_PREFIX = "ios.NS" + +# Hints whose default the mining cannot state in one value, resolved by reading +# the code rather than by picking whichever call site came first. +DEFAULT_NOTES = { + "android.debug": + "Defaults conditionally rather than to a fixed value: when android.release is on " + "it defaults to false, and when release is off it defaults to true, so a build " + "that selects neither still produces something installable " + "(AndroidGradleBuilder.java:447-451).", + "ios.minDeploymentTarget": + "The null and empty-string reads of this hint are presence checks; 6.0 is the " + "substantive default (IPhoneBuilder.java:4671).", +} + +# Prose for curated hints the main developer-guide table does not describe. +# Sourced from the feature chapters (App-Hardening.asciidoc) or read off the +# code that consumes the hint. The privacy strings are generated mechanically +# by BuildHintCodeGenerator and are not listed here. +DOC_OVERRIDES = { + "harden.level": + "Master switch for app hardening: off, standard, aggressive or paranoid. An " + "unrecognized value fails the build rather than being quietly treated as off.", + "harden.rename": + "Overrides symbol renaming independently of harden.level.", + "harden.strings": + "Overrides string obfuscation independently of harden.level: off, constants or all.", + "harden.controlFlow": + "Overrides control-flow obfuscation independently of harden.level.", + "harden.keep": + "Keep rules in ProGuard syntax, one per line, for classes that are resolved by " + "name at runtime and so cannot be found by the automatic analysis. Same syntax " + "as android.proguardKeep, so existing rules port directly. Rules are separated " + "by newlines only, because a semicolon is legal inside a rule body such as " + "{ *; }.", + "harden.allowUnhardenedLocalBuild": + "Permits a local or source build to run with hardening requested but not " + "applied. Without it such a build is refused, so a hardened app is never " + "shipped from a target that cannot actually harden it.", + "desktop.titleBar": + "How the desktop window is framed: native for the OS title bar and menu bar, " + "custom for an undecorated window with a Codename One drawn title bar, or " + "toolbar for the legacy in-app Toolbar. An unrecognized value falls back to " + "native with a warning.", + "desktop.interactiveScrollbars": + "Enables grab-able, click-to-page desktop scrollbars.", + "desktop.fullscreen": + "Starts the desktop build in full-screen mode.", + "ios.dependencyManager": + "Which native dependency manager to use: auto picks one from whichever of " + "ios.pods and ios.spm.packages is set, and cocoapods, spm or both require the " + "matching hint to be set. An unrecognized value fails the build.", + "ios.deployment_target": + "Minimum iOS version the build targets. Set it to the lowest iOS you actually " + "support; a higher value excludes older devices from the App Store listing.", + "ios.pods.sources": + "Extra CocoaPods spec repositories to search, in addition to the default trunk.", + "ios.spm.packages": + "Swift Package Manager packages to link, one per entry, each written as " + "identity|url|requirement.", + "android.appBundle": + "Produces an Android App Bundle (.aab) rather than an APK. Required for new " + "Play Store submissions.", + "android.buildToolsVersion": + "Android build-tools version. It also selects the compile SDK, so there is no " + "separate compile-SDK hint.", + "android.disableR8": + "Turns off R8, falling back to the older shrinker. Note that hardening requires " + "R8, so this conflicts with harden.level.", + "android.gradleDep": + "Gradle dependency statements to add to the app module, such as " + "implementation 'com.example:lib:1.0'.", + "android.topDependency": + "Statements added to the top-level Gradle build file rather than the app module.", + "android.repositories": + "Extra Gradle repositories to resolve dependencies from.", + "android.xgradle": + "Arbitrary text spliced into the generated app-module Gradle file.", + "android.hideStatusBar": + "Hides the Android status bar.", + "android.newFirebaseMessaging": + "Uses the current Firebase Cloud Messaging integration. Requires AndroidX and " + "Gradle 8.13 or newer.", +} + + +# hint -> (HintType, separator-or-None). Each verified at the call site, not guessed. +TYPE_OVERRIDES = { + # request.getArg(...).equals("true"), with a computed rather than literal default + "android.useAndroidX": ("BOOLEAN", None), # AndroidGradleBuilder.java:1169 + "android.appBundle": ("BOOLEAN", None), # AndroidGradleBuilder.java:1441 + "harden.rename": ("BOOLEAN", None), # hardenBoolArg(..., true) + # version numbers whose default is computed from the installed toolchain + "android.targetSDKVersion": ("INT", None), # AndroidGradleBuilder.java:1401 + "android.buildToolsVersion": ("VERSION", None), # AndroidGradleBuilder.java:1186 + # split by the consumer, so they are lists even though no merger entry exists + "ios.spm.packages": ("STRING_LIST", ";"), # IOSDependencyManager.java:119 split("[;]") + "ios.pods.sources": ("STRING_LIST", ","), # IPhoneBuilder.java:5159 split("[;,]") + # free text that is expected to span lines + "ios.beforeFinishLaunching": ("TEXT_BLOCK", None), + "ios.glAppDelegateHeader": ("TEXT_BLOCK", None), +} diff --git a/tools/build-hint-bootstrap/gen_catalog.py b/tools/build-hint-bootstrap/gen_catalog.py new file mode 100644 index 00000000000..9015d1fbe11 --- /dev/null +++ b/tools/build-hint-bootstrap/gen_catalog.py @@ -0,0 +1,287 @@ +#!/usr/bin/env python3 +"""One-time bootstrap: emit the BuildHints* registration classes.""" +import json, re, os, sys, collections + +ROOT = "/Users/shai/dev/cn6/CodenameOne" +SC = os.path.dirname(os.path.abspath(__file__)) +OUT = os.path.join(ROOT, "maven/build-hint-catalog/src/main/java/com/codename1/build/shared") +def load_license(): + with open(os.path.join(SC, "license.txt"), encoding="utf-8") as fh: + return fh.read() + +def load_mined(): + with open(os.path.join(SC, "mined.json"), encoding="utf-8") as fh: + return json.load(fh) + +sys.path.insert(0, SC) +from curation import CURATED, ENUMS, PRIVACY_PREFIX, DEFAULT_NOTES, DOC_OVERRIDES, TYPE_OVERRIDES + + +def privacy_attr(name): + """ios.NSCameraUsageDescription -> cameraUsageDescription.""" + body = name[len(PRIVACY_PREFIX):] + return body[0].lower() + body[1:] + +# ---------------------------------------------------------------- doc prose +def load_docs(): + # The guide's inline table has been replaced by the generated include, so the + # prose no longer has a live source. Recover the pre-migration copy with + # git show :docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc + # This bootstrap is a one-off: the catalog is the source of truth now and is + # edited directly. + p = os.path.join(SC, "guide_old.asciidoc") + with open(p, encoding="utf-8") as fh: + lines = fh.read().split("\n")[30:736] + docs, i = {}, 0 + while i < len(lines): + ln = lines[i] + m = re.fullmatch(r'\|([A-Za-z][A-Za-z0-9_.<>\-]*)', ln.strip()) + # a Vale/AsciiDoc // directive may sit between the name and its description + k = i + 1 + while k < len(lines) and lines[k].lstrip().startswith("//"): + k += 1 + if m and k < len(lines) and lines[k].startswith("|"): + body, j = [lines[k][1:]], k + 1 + while j < len(lines) and lines[j].strip() and not lines[j].startswith("|"): + body.append(lines[j]); j += 1 + docs[m.group(1)] = " ".join(x.strip() for x in body).strip() + i = j + else: + i += 1 + return docs + + +def clean_doc(t): + t = re.sub(r'<<[^,>]*,\s*([^>]*)>>', r'\1', t) # <> -> text + t = re.sub(r'<<([^>]*)>>', r'\1', t) # <> -> anchor + t = re.sub(r'\s+', ' ', t).strip() + return t + +# separators are authoritative -- read off LibraryHintMerger +SEPARATORS = { + "android.gradleDep": ";", "gradleDependencies": "\n", "android.topDependency": "\n", + "android.repositories": "\n", "android.xgradle": "\n", "android.gradle.androidx": "\n", + "android.xgradle_default_config": "\n", "android.gradlePlugin": "\n", + "android.supportv4Dep": "\n", "android.proguardKeep": "\n", + "ios.pods": ",", "ios.applicationQueriesSchemes": ",", "ios.add_libs": ";", + # joins with a space, but it is an XML attribute fragment rather than a list + # the user thinks of as items, so it keeps HintType.XML -- see infer(). + "android.xapplication_attr": " ", +} +# Every entry above is a list the user edits as items; this one is not. +SEPARATOR_BUT_NOT_A_LIST = {"android.xapplication_attr"} +XML_HINTS = re.compile(r'^(android\.(xpermissions|xapplication|xmanifest|xactivity|' + r'xintent_filter|xqueries|xapplication_attr|xactivity_attr)|ios\.plistInject|' + r'ios\.entitlementsInject|.*Inject)$') + +ID_NAME = re.compile(r'(^|[._])([a-z]+_)?id$|Id$|_id$', re.I) + +def is_int_hint(name, lit): + """A digit default is only an int if it is arithmetic, not an identifier. + + facebook.appId defaults to a 15-digit Facebook app id: it overflows a Java + int and nothing ever adds to it. Such a hint is an opaque string. + """ + if ID_NAME.search(name): + return False + try: + v = int(lit) + except ValueError: + return False + return -2**31 <= v < 2**31 + + +def infer(name, defaults, doc): + if name in TYPE_OVERRIDES: + t, sep = TYPE_OVERRIDES[name] + lit = None + for x in defaults: + if x.startswith('"') and x.endswith('"'): + lit = x[1:-1]; break + if x in ("true", "false") or re.fullmatch(r'-?\d+', x): + lit = x; break + return t, lit, sep + d = [x for x in defaults if x not in ("", "null")] + lit = None + for x in d: + if x.startswith('"') and x.endswith('"'): + # json.loads, not a slice: the miner re-quotes with real escaping, so + # a naive strip would leave backslashes the build never sees. + lit = json.loads(x); break + if x in ("true", "false") or re.fullmatch(r'-?\d+', x): + lit = x; break + dl = doc.lower() + if name in SEPARATORS: + if name in SEPARATOR_BUT_NOT_A_LIST: + return "XML", lit, SEPARATORS[name] + return "STRING_LIST", lit, SEPARATORS[name] + if XML_HINTS.match(name): + return "XML", lit, "" + if lit in ("true", "false") or {x.strip('"') for x in d} <= {"true", "false"} and d: + return "BOOLEAN", lit, None + if lit is not None and re.fullmatch(r'-?\d+', lit) and is_int_hint(name, lit): + return "INT", lit, None + if "true/false" in dl or dl.startswith("boolean"): + return "BOOLEAN", lit, None + if lit is not None and re.fullmatch(r'\d+\.\d+(\.\d+)?', lit): + return "VERSION", lit, None + return "STRING", lit, None + +PLATFORM = [("android.", "android"), ("and.", "android"), ("ios.", "ios"), + ("macNative.", "mac"), ("desktop.mac.", "mac"), ("windows.", "windows"), + ("win.", "windows"), ("linux.", "linux"), ("javascript.", "javascript"), + ("desktop.", "desktop"), ("tvNative.", "tv"), ("watchNative.", "watch")] + +IOS_PRIVACY = re.compile(r'^ios\.NS.*UsageDescription$') +ODD = re.compile(r'^(ios\.onDeviceDebug|android\.onDeviceDebug$)') + +def group_of(name): + if IOS_PRIVACY.match(name): return "IOS_PRIVACY" + if ODD.match(name): return "ON_DEVICE_DEBUG" + for p, g in [("ios.", "IOS"), ("android.", "ANDROID"), ("and.", "ANDROID"), + ("desktop.", "DESKTOP"), ("macNative.", "MAC_NATIVE"), + ("windows.", "WINDOWS"), ("linux.", "LINUX"), + ("javascript.", "JAVASCRIPT"), ("tvNative.", "TV_NATIVE"), + ("watchNative.", "WATCH_NATIVE"), ("harden.", "HARDENING")]: + if name.startswith(p): return g + return "GENERAL" + +def platform_of(name): + for p, v in PLATFORM: + if name.startswith(p): return v + return "general" + +def jesc(s): + return (s.replace("\\", "\\\\").replace('"', '\\"') + .replace("\n", "\\n").replace("\t", "\\t").replace("\r", "")) + +def wrap(text, indent, width=88): + """Split a long Java string literal into concatenated chunks.""" + words, lines, cur = text.split(" "), [], "" + for w in words: + if len(cur) + len(w) + 1 > width and cur: + lines.append(cur); cur = w + else: + cur = (cur + " " + w).strip() + if cur: lines.append(cur) + if not lines: return '""' + if len(lines) == 1: return '"%s"' % jesc(lines[0]) + sep = "\n" + " " * indent + "+ " + return sep.join('"%s "' % jesc(l) if i < len(lines) - 1 else '"%s"' % jesc(l) + for i, l in enumerate(lines)) + +FILES = { + "BuildHintsIos": lambda n: group_of(n) in ("IOS", "IOS_PRIVACY"), + "BuildHintsAndroid": lambda n: group_of(n) == "ANDROID", + "BuildHintsApple": lambda n: group_of(n) in ("MAC_NATIVE", "TV_NATIVE", "WATCH_NATIVE"), + "BuildHintsDesktop": lambda n: group_of(n) in ("DESKTOP", "WINDOWS", "LINUX", "JAVASCRIPT"), + "BuildHintsGeneral": lambda n: group_of(n) in ("GENERAL", "HARDENING", "ON_DEVICE_DEBUG"), +} + +BLURB = { + "BuildHintsIos": "iOS build hints, including the Info.plist privacy strings.", + "BuildHintsAndroid": "Android build hints, including the {@code and.} override aliases.", + "BuildHintsApple": "macOS Catalyst, tvOS and watchOS native-slice build hints.", + "BuildHintsDesktop": "Desktop, native Windows, native Linux and JavaScript build hints.", + "BuildHintsGeneral": "Hints with no platform prefix, plus hardening and on-device debugging.", +} + +def main(): + """Emit the BuildHints* registration classes. + + Guarded rather than run at import: gen_external.py imports this module for + load_docs/clean_doc/infer, and without the guard that import would rewrite + every catalog source as a side effect. + """ + LICENSE = load_license() + DOCS = load_docs() + print(f"doc rows parsed: {len(DOCS)}", file=sys.stderr) + # A mined key ending in a dot is the constant half of a concatenation -- + # getArg("android.permission." + name) -- not a hint anyone can set. + # Cataloguing it would put a phantom row in the guide and a phantom entry in + # the Settings tool. Each one is covered by a dynamic family instead. + mined = {k: v for k, v in load_mined().items() if not k.endswith(".")} + + counts = collections.Counter() + for fname, pred in FILES.items(): + names = sorted(n for n in mined if pred(n)) + counts[fname] = len(names) + body = [] + for n in names: + defaults = [d for d, _, _ in mined[n]] + sites = sorted({os.path.basename(f)[:-5] for _, f, _ in mined[n]}) + doc = clean_doc(DOCS.get(n, "")) + if not doc and n in DOC_OVERRIDES: + doc = DOC_OVERRIDES[n] + if n in DEFAULT_NOTES: + if doc and not doc.rstrip().endswith((".", "!", "?")): + doc = doc.rstrip() + "." + doc = (doc + " " + DEFAULT_NOTES[n]).strip() + htype, lit, sep = infer(n, defaults, doc) + parts = [' h.add(new Hint("%s")' % jesc(n)] + g = group_of(n) + cur = CURATED.get(n) + enum_name = None + if g == "IOS_PRIVACY": + parts.append(' .annotatedAs(HintGroup.IOS_PRIVACY, "%s")' % privacy_attr(n)) + htype = "STRING" + elif cur: + cg, attr, enum_name, forced_type, forced_def = cur + parts.append(' .annotatedAs(HintGroup.%s, "%s")' % (cg, attr)) + if forced_type: + htype = forced_type + if forced_def is not None: + lit = forced_def + else: + parts.append(' .group(HintGroup.%s)' % g) + if enum_name: + vals = ", ".join('"%s"' % v for v in ENUMS[enum_name]) + parts.append(' .values("%s", %s)' % (enum_name, vals)) + if lit is not None and lit not in ENUMS[enum_name]: + lit = None + else: + parts.append(' .type(HintType.%s)' % htype) + if lit is not None and lit != "": + parts.append(' .def("%s")' % jesc(lit)) + if sep is not None: + parts.append(' .separator("%s")' % jesc(sep)) + parts.append(' .platform("%s")' % platform_of(n)) + parts.append(' .consumedBy(%s)' % ", ".join('"%s"' % s for s in sites)) + if doc: + parts.append(' .doc(%s)' % wrap(doc, 24)) + body.append("\n".join(parts) + ");") + + src = LICENSE + f'''package com.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * {BLURB[fname]} + * + *

Seeded by mining every {{@code getArg}} call site in the builders, so the + * name and the default match what the build actually reads. Curated entries + * carry an annotation attribute and, where the domain is provably closed, an + * enum; the rest are described but set through + * {{@code codenameone_settings.properties}}.

+ * + *

Split out of {{@link BuildHints}} because a single class initializer + * holding every entry would exceed the JVM's 64KB per-method limit.

+ */ +final class {fname} {{ + + private {fname}() {{ + }} + + static void register(List h) {{ +''' + "\n\n".join(body) + "\n }\n}\n" + with open(os.path.join(OUT, fname + ".java"), "w", encoding="utf-8") as fh: + fh.write(src) + + print("entries per file:", dict(counts), file=sys.stderr) + print("total:", sum(counts.values()), file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/tools/build-hint-bootstrap/gen_external.py b/tools/build-hint-bootstrap/gen_external.py new file mode 100644 index 00000000000..6794244504d --- /dev/null +++ b/tools/build-hint-bootstrap/gen_external.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +"""Emit BuildHintsExternal: hints the developer guide documents that no code in +this repository reads. Most are consumed by build-daemon lanes whose source is +not mirrored here, so their absence is not evidence they are dead -- which is +exactly why they are recorded rather than enforced.""" +import json, sys, os, re +SC = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, SC) +import gen_catalog as G + +ROOT = "/Users/shai/dev/cn6/CodenameOne" +OUT = os.path.join(ROOT, "maven/build-hint-catalog/src/main/java/com/codename1/build/shared") +LICENSE = G.load_license() + +with open(SC + "/mined.json", encoding="utf-8") as _fh: + mined = set(json.load(_fh)) +DOCS = G.load_docs() +PLACEHOLDER = re.compile(r'PERMISSION_NAME|[A-Z_]{4,}$|[<>]') + +names = sorted(k for k in DOCS + if k not in mined and not PLACEHOLDER.search(k) and "." in k or + (k not in mined and not PLACEHOLDER.search(k) and k.islower())) +names = sorted(set(n for n in names if not PLACEHOLDER.search(n))) + +body = [] +for n in names: + doc = G.clean_doc(DOCS[n]) + htype, lit, sep = G.infer(n, [], doc) + parts = [' h.add(new Hint("%s")' % G.jesc(n)] + parts.append(' .group(HintGroup.%s)' % G.group_of(n)) + parts.append(' .type(HintType.%s)' % htype) + if sep is not None: + parts.append(' .separator("%s")' % G.jesc(sep)) + parts.append(' .platform("%s")' % G.platform_of(n)) + parts.append(' .external()') + if doc: + parts.append(' .doc(%s)' % G.wrap(doc, 24)) + body.append("\n".join(parts) + ");") + +src = LICENSE + '''package com.codename1.build.shared; + +import com.codename1.build.shared.BuildHints.Hint; + +import java.util.List; + +/** + * Hints the developer guide documents that nothing in this repository reads. + * + *

Most are consumed by build-daemon lanes whose source is not mirrored here, + * so having no in-repo consumer is not evidence that a hint is dead. A few are + * probably genuinely obsolete. Recording the distinction as + * {@link Hint#isExternal()} keeps both the drift gate and the Settings tool + * honest: the gate does not demand a consumer for these, and the tool still + * offers them for editing.

+ * + *

They are deliberately not annotated. Exposing a hint as a typed attribute + * is a promise that setting it does something, and for these that promise + * cannot be checked from this repository.

+ */ +final class BuildHintsExternal { + + private BuildHintsExternal() { + } + + static void register(List h) { +''' + "\n\n".join(body) + "\n }\n}\n" +with open(os.path.join(OUT, "BuildHintsExternal.java"), "w", encoding="utf-8") as _fh: + _fh.write(src) +print("external entries:", len(names), file=sys.stderr)