@@ -11,10 +11,14 @@ import android.view.View;
1111
1212import com.codename1.ui.Display;
1313import com.codename1.ui.Form;
14+ import com.codename1.ui.Image;
15+ import com.codename1.ui.util.ImageIO;
1416
1517import java.io.File;
1618import java.io.FileOutputStream;
1719import java.io.IOException;
20+ import java.util.concurrent.Callable;
21+ import java.util.concurrent.FutureTask;
1822
1923import org.junit.After;
2024import org.junit.Before;
@@ -34,6 +38,7 @@ public class @MAIN_NAME@UiTest {
3438
3539 private static final long STARTUP_TIMEOUT_MS = 30_000L;
3640 private static final long LAYOUT_TIMEOUT_MS = 5_000L;
41+ private static final long EDT_TIMEOUT_MS = 10_000L;
3742
3843 private ActivityController<@MAIN_NAME@Stub> controller;
3944 private @MAIN_NAME@Stub activity;
@@ -61,16 +66,32 @@ public class @MAIN_NAME@UiTest {
6166
6267 ensureViewHasLayout(decorView);
6368
64- Bitmap screenshot = captureBitmap(decorView);
65- assertTrue("Screenshot width should be positive", screenshot.getWidth() > 0);
66- assertTrue("Screenshot height should be positive", screenshot.getHeight() > 0);
69+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
70+ Bitmap androidScreenshot = captureBitmap(decorView);
71+ assertTrue("Android screenshot width should be positive", androidScreenshot.getWidth() > 0);
72+ assertTrue("Android screenshot height should be positive", androidScreenshot.getHeight() > 0);
6773 assertTrue(
68- "Screenshot should contain rendered content beyond the background",
69- hasRenderableContent(screenshot));
70-
71- File screenshotFile = saveScreenshot(screenshot);
72- assertTrue("Screenshot file should exist", screenshotFile.isFile());
73- assertTrue("Screenshot file should not be empty", screenshotFile.length() > 0L);
74+ "Android screenshot should contain rendered content beyond the background",
75+ hasRenderableContent(androidScreenshot));
76+
77+ File androidScreenshotFile = saveBitmap(androidScreenshot, "@
[email protected] ");
78+ assertTrue("Android screenshot file should exist", androidScreenshotFile.isFile());
79+ assertTrue("Android screenshot file should not be empty", androidScreenshotFile.length() > 0L);
80+
81+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
82+ Image codenameOneScreenshot = captureCodenameOneScreenshot();
83+ assertNotNull("Codename One screenshot should be available", codenameOneScreenshot);
84+ assertTrue("Codename One screenshot width should be positive", codenameOneScreenshot.getWidth() > 0);
85+ assertTrue("Codename One screenshot height should be positive", codenameOneScreenshot.getHeight() > 0);
86+ assertTrue(
87+ "Codename One screenshot should contain rendered content beyond the background",
88+ hasRenderableContent(codenameOneScreenshot));
89+
90+ File codenameOneScreenshotFile = saveCodenameOneScreenshot(
91+ codenameOneScreenshot,
92+ 93+ assertTrue("Codename One screenshot file should exist", codenameOneScreenshotFile.isFile());
94+ assertTrue("Codename One screenshot file should not be empty", codenameOneScreenshotFile.length() > 0L);
7495 }
7596
7697 private static Bitmap captureBitmap(View view) {
@@ -101,12 +122,20 @@ public class @MAIN_NAME@UiTest {
101122 private static boolean hasRenderableContent(Bitmap screenshot) {
102123 int width = screenshot.getWidth();
103124 int height = screenshot.getHeight();
104- if (width <= 0 || height <= 0) {
105- return false;
106- }
107125 int[] pixels = new int[width * height];
108126 screenshot.getPixels(pixels, 0, width, 0, 0, width, height);
109- if (pixels.length == 0) {
127+ return hasRenderableContent(pixels, width, height);
128+ }
129+
130+ private static boolean hasRenderableContent(Image screenshot) throws Exception {
131+ int width = screenshot.getWidth();
132+ int height = screenshot.getHeight();
133+ int[] pixels = callOnEdt(screenshot::getRGB);
134+ return hasRenderableContent(pixels, width, height);
135+ }
136+
137+ private static boolean hasRenderableContent(int[] pixels, int width, int height) {
138+ if (width <= 0 || height <= 0 || pixels == null || pixels.length == 0) {
110139 return false;
111140 }
112141 int background = pixels[0];
@@ -126,17 +155,32 @@ public class @MAIN_NAME@UiTest {
126155 return false;
127156 }
128157
129- private static File saveScreenshot (Bitmap screenshot) throws IOException {
158+ private static File saveBitmap (Bitmap screenshot, String fileName ) throws IOException {
130159 File outputDir = resolveArtifactDirectory();
131- File screenshotFile = new File(outputDir,
"@[email protected] " );
160+ File screenshotFile = new File(outputDir, fileName );
132161 try (FileOutputStream out = new FileOutputStream(screenshotFile)) {
133162 if (!screenshot.compress(Bitmap.CompressFormat.PNG, 100, out)) {
134- throw new IOException("Failed to encode screenshot as PNG");
163+ throw new IOException("Failed to encode Android screenshot as PNG");
135164 }
136165 }
137166 return screenshotFile;
138167 }
139168
169+ private static File saveCodenameOneScreenshot(Image screenshot, String fileName) throws Exception {
170+ File outputDir = resolveArtifactDirectory();
171+ File screenshotFile = new File(outputDir, fileName);
172+ ImageIO io = callOnEdt(() -> Display.getInstance().getImageIO());
173+ assertNotNull("Codename One ImageIO should be available", io);
174+ try (FileOutputStream out = new FileOutputStream(screenshotFile)) {
175+ FileOutputStream stream = out;
176+ callOnEdt(() -> {
177+ io.save(screenshot, stream, ImageIO.FORMAT_PNG, 1.0f);
178+ return null;
179+ });
180+ }
181+ return screenshotFile;
182+ }
183+
140184 private static File resolveArtifactDirectory() throws IOException {
141185 String directory = System.getenv("CN1_TEST_SCREENSHOT_DIR");
142186 File outputDir = (directory != null && !directory.isEmpty())
@@ -162,4 +206,22 @@ public class @MAIN_NAME@UiTest {
162206 }
163207 throw new AssertionError("Timed out waiting for Codename One main form to be displayed");
164208 }
209+
210+ private static Image captureCodenameOneScreenshot() throws Exception {
211+ return callOnEdt(() -> Display.getInstance().captureScreen());
212+ }
213+
214+ private static <T> T callOnEdt(Callable<T> callable) throws Exception {
215+ FutureTask<T> task = new FutureTask<>(callable);
216+ Display.getInstance().callSerially(task);
217+ long deadline = SystemClock.uptimeMillis() + EDT_TIMEOUT_MS;
218+ while (!task.isDone() && SystemClock.uptimeMillis() < deadline) {
219+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
220+ SystemClock.sleep(4L);
221+ }
222+ if (!task.isDone()) {
223+ throw new AssertionError("Timed out waiting for Codename One EDT task to finish");
224+ }
225+ return task.get();
226+ }
165227}
0 commit comments