@@ -50,9 +50,10 @@ public class @MAIN_NAME@UiTest {
5050 private @MAIN_NAME@Stub activity;
5151
5252 @Before
53- public void setUp() {
53+ public void setUp() throws Exception {
5454 controller = Robolectric.buildActivity(@
[email protected] );
5555 activity = controller.setup().get();
56+ bootstrapCodenameOneApp();
5657 waitForCodenameOneForm();
5758 }
5859
@@ -224,6 +225,36 @@ public class @MAIN_NAME@UiTest {
224225 throw new AssertionError("Timed out waiting for Codename One main form to be displayed");
225226 }
226227
228+ private void bootstrapCodenameOneApp() throws Exception {
229+ runOnMainSync(() -> AndroidImplementation.startContext(activity));
230+ if (!Display.isInitialized()) {
231+ runOnMainSync(() -> Display.init(activity));
232+ }
233+ if (!Display.isInitialized()) {
234+ throw new AssertionError("Codename One Display failed to initialize");
235+ }
236+ callSeriallyAndWait(() -> {
237+ @MAIN_NAME@ app = @
[email protected] ();
238+ boolean needsInit = isStubFirstStart(app);
239+ if (app == null) {
240+ app = new @MAIN_NAME@();
241+ assignStubAppInstance(app);
242+ needsInit = true;
243+ }
244+ if (needsInit) {
245+ app.init(activity);
246+ }
247+ app.start();
248+ markStubFirstTimeConsumed();
249+ return null;
250+ });
251+ }
252+
253+ private void runOnMainSync(Runnable runnable) {
254+ activity.runOnUiThread(runnable);
255+ ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
256+ }
257+
227258 private static Image captureCodenameOneScreenshot() throws Exception {
228259 return callSeriallyAndWait(() -> Display.getInstance().captureScreen());
229260 }
@@ -341,6 +372,50 @@ public class @MAIN_NAME@UiTest {
341372 }
342373 }
343374
375+ private static void assignStubAppInstance(@MAIN_NAME@ app) {
376+ try {
377+ Field appField = @
[email protected] ("i");
378+ appField.setAccessible(true);
379+ appField.set(null, app);
380+ } catch (NoSuchFieldException | IllegalAccessException e) {
381+ throw new RuntimeException("Unable to assign Codename One application instance", e);
382+ }
383+ }
384+
385+ private boolean isStubFirstStart(@MAIN_NAME@ appInstance) {
386+ try {
387+ Field firstTimeField = @
[email protected] ("firstTime");
388+ firstTimeField.setAccessible(true);
389+ boolean firstTimeValue;
390+ if (java.lang.reflect.Modifier.isStatic(firstTimeField.getModifiers())) {
391+ firstTimeValue = firstTimeField.getBoolean(null);
392+ } else {
393+ firstTimeValue = firstTimeField.getBoolean(activity);
394+ }
395+ return firstTimeValue || appInstance == null;
396+ } catch (NoSuchFieldException ignored) {
397+ return appInstance == null;
398+ } catch (IllegalAccessException e) {
399+ throw new RuntimeException("Unable to inspect Codename One stub firstTime flag", e);
400+ }
401+ }
402+
403+ private void markStubFirstTimeConsumed() {
404+ try {
405+ Field firstTimeField = @
[email protected] ("firstTime");
406+ firstTimeField.setAccessible(true);
407+ if (java.lang.reflect.Modifier.isStatic(firstTimeField.getModifiers())) {
408+ firstTimeField.setBoolean(null, false);
409+ } else {
410+ firstTimeField.setBoolean(activity, false);
411+ }
412+ } catch (NoSuchFieldException ignored) {
413+ // Field absent in some stub variants; nothing to update.
414+ } catch (IllegalAccessException e) {
415+ throw new RuntimeException("Unable to update Codename One stub firstTime flag", e);
416+ }
417+ }
418+
344419 private static <T> T callSeriallyAndWait(Callable<T> callable) throws Exception {
345420 CountDownLatch latch = new CountDownLatch(1);
346421 AtomicReference<T> result = new AtomicReference<>();
0 commit comments