Skip to content

Fail the build on undersized localized launcher icons#5208

Merged
shai-almog merged 2 commits into
masterfrom
fix-localized-icon-resolution-guard
Jun 9, 2026
Merged

Fail the build on undersized localized launcher icons#5208
shai-almog merged 2 commits into
masterfrom
fix-localized-icon-resolution-guard

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Background

A customer using the localizable app-icon feature (cn1_icon_<lang>[_<country>].png) on Android reported two problems:

  1. Blurry icon in production. The localized icon they supplied was low-resolution. The build scales every icon up to the largest launcher density (192px normally, 432px for the adaptive foreground), so a small source is upscaled and renders soft — but nothing warned about it, so it shipped.
  2. Stale icon picked up from target/classes. Maven's resource plugin copies src/main/resourcestarget/classes incrementally and never deletes a copy when the source file is removed or renamed. So an outdated low-res icon kept getting bundled and sent to the build server until mvn clean was run by hand.

The localizer itself was working correctly — it was faithfully upscaling a too-small source. The fix is to stop letting such an icon reach production.

Change

Both the server-side Android builder and the local Maven build now fail the build (not just warn) when a localized icon is smaller than the size it would be upscaled to:

  • AndroidGradleBuilder.processLocalizedIcons — collects every undersized localized icon and throws a BuildException with a clear message before the APK is produced. The threshold matches what writeLocalizedIconSet emits (192px, or 432px when android.enableAdaptiveIcons=true). This surfaces in the cloud-build log.
  • CN1BuildMojo — before assembling the jar-with-dependencies that is sent to the build server, scans the compiled output directories (each module's target/classes) for cn1_icon_*.png and fails with a MojoFailureException, listing the offenders and pointing at stale copies with a recommendation to run mvn clean. This catches the problem on the developer's machine before a build is even sent.

Per the reported use case (server builds, Android) IPhoneBuilder is intentionally left unchanged.

Docs

Miscellaneous-Features.asciidoc now recommends 1024×1024 localized icons, documents the new build failure, and adds a NOTE explaining Maven's incremental resource copy and the mvn clean fix.

Testing

mvn -o -pl codenameone-maven-plugin compile → BUILD SUCCESS.

🤖 Generated with Claude Code

Localized launcher icons (cn1_icon_<lang>[_<country>].png) are scaled up
to the largest launcher density at build time, so a low-resolution source
produces a blurry icon. Two related problems were reported on Android:

1. A small localized icon was upscaled and shipped blurry with no warning.
2. Maven copies these resources into target/classes incrementally and does
   not delete stale copies when a source icon is removed/renamed, so an old
   low-res icon kept getting bundled until 'mvn clean' was run manually.

This adds a hard build failure (not just a warning) when a localized icon
is smaller than the size it would be upscaled to (192px normally, 432px for
the adaptive foreground), so a soft icon can no longer reach production:

- AndroidGradleBuilder.processLocalizedIcons: collects undersized icons and
  throws a BuildException with a clear message before producing the APK.
- CN1BuildMojo: scans the compiled output (target/classes) that is about to
  be bundled and sent to the build server and fails with a MojoFailureException,
  pointing at stale copies and recommending 'mvn clean'.

Docs updated with the resolution recommendation and the stale-resource note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.

Native Android coverage

  • 📊 Line coverage: 14.08% (8521/60528 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.40% (42063/368959), branch 4.94% (1713/34653), complexity 5.98% (1987/33247), method 10.38% (1615/15559), class 16.98% (372/2191)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 14.08% (8521/60528 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.40% (42063/368959), branch 4.94% (1713/34653), complexity 5.98% (1987/33247), method 10.38% (1615/15559), class 16.98% (372/2191)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 824.000 ms
Base64 CN1 encode 149.000 ms
Base64 encode ratio (CN1/native) 0.181x (81.9% faster)
Base64 native decode 815.000 ms
Base64 CN1 decode 189.000 ms
Base64 decode ratio (CN1/native) 0.232x (76.8% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 121 screenshots: 121 matched.
✅ JavaScript-port screenshot tests passed.

Use contractions (doesn't / that's) to satisfy the Microsoft.Contractions
rule in the developer-guide quality gate, and update the wording from
"logs a warning" to "fails the build" to match the new behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 147 seconds

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 795.000 ms
Base64 CN1 encode 1340.000 ms
Base64 encode ratio (CN1/native) 1.686x (68.6% slower)
Base64 native decode 427.000 ms
Base64 CN1 decode 874.000 ms
Base64 decode ratio (CN1/native) 2.047x (104.7% slower)
Base64 SIMD encode 369.000 ms
Base64 encode ratio (SIMD/native) 0.464x (53.6% faster)
Base64 encode ratio (SIMD/CN1) 0.275x (72.5% faster)
Base64 SIMD decode 366.000 ms
Base64 decode ratio (SIMD/native) 0.857x (14.3% faster)
Base64 decode ratio (SIMD/CN1) 0.419x (58.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 59.000 ms
Image createMask (SIMD on) 12.000 ms
Image createMask ratio (SIMD on/off) 0.203x (79.7% faster)
Image applyMask (SIMD off) 170.000 ms
Image applyMask (SIMD on) 85.000 ms
Image applyMask ratio (SIMD on/off) 0.500x (50.0% faster)
Image modifyAlpha (SIMD off) 139.000 ms
Image modifyAlpha (SIMD on) 109.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.784x (21.6% faster)
Image modifyAlpha removeColor (SIMD off) 153.000 ms
Image modifyAlpha removeColor (SIMD on) 128.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.837x (16.3% faster)
Image PNG encode (SIMD off) 986.000 ms
Image PNG encode (SIMD on) 772.000 ms
Image PNG encode ratio (SIMD on/off) 0.783x (21.7% faster)
Image JPEG encode 422.000 ms

@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 128 screenshots: 128 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 348 seconds

Build and Run Timing

Metric Duration
Simulator Boot 104000 ms
Simulator Boot (Run) 1000 ms
App Install 18000 ms
App Launch 4000 ms
Test Execution 281000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 653.000 ms
Base64 CN1 encode 1300.000 ms
Base64 encode ratio (CN1/native) 1.991x (99.1% slower)
Base64 native decode 383.000 ms
Base64 CN1 decode 1274.000 ms
Base64 decode ratio (CN1/native) 3.326x (232.6% slower)
Base64 SIMD encode 554.000 ms
Base64 encode ratio (SIMD/native) 0.848x (15.2% faster)
Base64 encode ratio (SIMD/CN1) 0.426x (57.4% faster)
Base64 SIMD decode 538.000 ms
Base64 decode ratio (SIMD/native) 1.405x (40.5% slower)
Base64 decode ratio (SIMD/CN1) 0.422x (57.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 63.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.143x (85.7% faster)
Image applyMask (SIMD off) 158.000 ms
Image applyMask (SIMD on) 56.000 ms
Image applyMask ratio (SIMD on/off) 0.354x (64.6% faster)
Image modifyAlpha (SIMD off) 149.000 ms
Image modifyAlpha (SIMD on) 56.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.376x (62.4% faster)
Image modifyAlpha removeColor (SIMD off) 138.000 ms
Image modifyAlpha removeColor (SIMD on) 64.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.464x (53.6% faster)
Image PNG encode (SIMD off) 1079.000 ms
Image PNG encode (SIMD on) 916.000 ms
Image PNG encode ratio (SIMD on/off) 0.849x (15.1% faster)
Image JPEG encode 522.000 ms

@shai-almog shai-almog merged commit fb72379 into master Jun 9, 2026
31 of 33 checks passed
@shai-almog shai-almog deleted the fix-localized-icon-resolution-guard branch June 9, 2026 18:40
@shai-almog

shai-almog commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 124 screenshots: 124 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 183 seconds

Build and Run Timing

Metric Duration
Simulator Boot 72000 ms
Simulator Boot (Run) 1000 ms
App Install 13000 ms
App Launch 16000 ms
Test Execution 314000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 469.000 ms
Base64 CN1 encode 1356.000 ms
Base64 encode ratio (CN1/native) 2.891x (189.1% slower)
Base64 native decode 347.000 ms
Base64 CN1 decode 969.000 ms
Base64 decode ratio (CN1/native) 2.793x (179.3% slower)
Base64 SIMD encode 403.000 ms
Base64 encode ratio (SIMD/native) 0.859x (14.1% faster)
Base64 encode ratio (SIMD/CN1) 0.297x (70.3% faster)
Base64 SIMD decode 368.000 ms
Base64 decode ratio (SIMD/native) 1.061x (6.1% slower)
Base64 decode ratio (SIMD/CN1) 0.380x (62.0% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 56.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.161x (83.9% faster)
Image applyMask (SIMD off) 119.000 ms
Image applyMask (SIMD on) 105.000 ms
Image applyMask ratio (SIMD on/off) 0.882x (11.8% faster)
Image modifyAlpha (SIMD off) 161.000 ms
Image modifyAlpha (SIMD on) 81.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.503x (49.7% faster)
Image modifyAlpha removeColor (SIMD off) 337.000 ms
Image modifyAlpha removeColor (SIMD on) 142.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.421x (57.9% faster)
Image PNG encode (SIMD off) 1189.000 ms
Image PNG encode (SIMD on) 878.000 ms
Image PNG encode ratio (SIMD on/off) 0.738x (26.2% faster)
Image JPEG encode 423.000 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant