Skip to content

Commit 3433603

Browse files
authored
Add abstract iOS launcher (jMonkeyEngine#2829)
* add abstract ios launcher * fix launcher * return when context is null
1 parent d4d98e2 commit 3433603

2 files changed

Lines changed: 127 additions & 91 deletions

File tree

Lines changed: 29 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,50 @@
11
package jme3test.ios;
22

33
import com.jme3.app.Application;
4+
import com.jme3.app.IosApplicationLauncher;
45
import com.jme3.system.AppSettings;
5-
import com.jme3.system.JmeContext;
6-
import com.jme3.system.SystemListener;
7-
import com.jme3.system.ios.IGLESContext;
86
import java.io.BufferedReader;
97
import java.io.IOException;
108
import java.io.InputStream;
119
import java.io.InputStreamReader;
1210
import java.lang.reflect.InvocationTargetException;
11+
import java.lang.reflect.Modifier;
1312
import java.nio.charset.StandardCharsets;
1413
import java.util.ArrayList;
1514
import java.util.Collections;
1615
import java.util.List;
1716

18-
public final class IosTestChooserLauncher {
17+
public final class IosTestChooserLauncher extends IosApplicationLauncher {
1918
private static final String CLASS_LIST_RESOURCE = "/jme3test/test-classes.txt";
2019
private static final String IOS_INITIAL_EXAMPLE_CLASS = "jme3test.ios.IosInitialExample";
2120
private static List<String> testClasses;
2221
private static IosTestChooserLauncher activeLauncher;
2322

24-
private Application delegate;
2523
private String pendingClass;
2624

25+
@Override
2726
public void start() {
2827
activeLauncher = this;
29-
delegate = new IosTestChooser();
3028
pendingClass = initialExampleClass();
31-
startDelegate(delegate);
29+
super.start();
3230
}
3331

34-
public JmeContext getContext() {
35-
return null;
32+
@Override
33+
protected Application createApplication() {
34+
return new IosTestChooser();
3635
}
3736

37+
@Override
3838
public void update() {
3939
if (startPendingClass()) {
4040
return;
4141
}
42-
runDelegateFrame();
43-
}
44-
45-
public void reshape(int width, int height) {
46-
if (delegate == null) {
47-
return;
48-
}
49-
JmeContext context = delegate.getContext();
50-
if (context instanceof IGLESContext) {
51-
((IGLESContext) context).resizeFramebuffer(width, height);
52-
return;
53-
}
54-
if (delegate instanceof SystemListener) {
55-
((SystemListener) delegate).reshape(width, height);
56-
return;
57-
}
58-
invokeIfPresent(delegate, "reshape", new Class<?>[]{int.class, int.class}, width, height);
42+
super.update();
5943
}
6044

45+
@Override
6146
public void stop(boolean waitFor) {
62-
if (delegate != null) {
63-
delegate.stop(waitFor);
64-
delegate = null;
65-
}
47+
super.stop(waitFor);
6648
if (activeLauncher == this) {
6749
activeLauncher = null;
6850
}
@@ -129,12 +111,6 @@ private static Application instantiate(String className) {
129111
}
130112
}
131113

132-
private void startDelegate(Application application) {
133-
invokeSetShowSettings(application);
134-
configureIosSettings(application);
135-
application.start();
136-
}
137-
138114
private void selectForCurrentRun(String className) {
139115
pendingClass = className;
140116
}
@@ -145,9 +121,18 @@ private boolean startPendingClass() {
145121
return false;
146122
}
147123
pendingClass = null;
148-
stopDelegateForHandoff();
149-
delegate = instantiate(className);
150-
startDelegate(delegate);
124+
stopApplicationForHandoff();
125+
Application selected = instantiate(className);
126+
AppSettings settings = new AppSettings(true);
127+
settings.setUseJoysticks(true);
128+
settings.setOnDeviceJoystickRumble(true);
129+
invokeConfigureSettings(selected, settings);
130+
selected.setSettings(settings);
131+
try{
132+
startApplication(selected);
133+
} catch (Exception exception) {
134+
throw new IllegalStateException("Failed to start selected iOS test: " + className, exception);
135+
}
151136
return true;
152137
}
153138

@@ -176,25 +161,9 @@ private static String generatedInitialExampleClassName() {
176161
}
177162
}
178163

179-
private void runDelegateFrame() {
180-
if (delegate == null) {
181-
return;
182-
}
183-
JmeContext context = delegate.getContext();
184-
if (context instanceof IGLESContext) {
185-
((IGLESContext) context).runFrame();
186-
return;
187-
}
188-
if (delegate instanceof SystemListener) {
189-
((SystemListener) delegate).update();
190-
return;
191-
}
192-
invokeIfPresent(delegate, "update", new Class<?>[0]);
193-
}
194-
195-
private void stopDelegateForHandoff() {
196-
Application previous = delegate;
197-
delegate = null;
164+
private void stopApplicationForHandoff() {
165+
Application previous = app;
166+
app = null;
198167
if (previous == null) {
199168
return;
200169
}
@@ -204,47 +173,16 @@ private void stopDelegateForHandoff() {
204173
previous.stop(false);
205174
}
206175

207-
private static void invokeSetShowSettings(Application application) {
208-
try {
209-
application.getClass().getMethod("setShowSettings", boolean.class).invoke(application, false);
210-
} catch (NoSuchMethodException ignored) {
211-
// Some Application subclasses do not expose settings dialogs.
212-
} catch (IllegalAccessException | InvocationTargetException exception) {
213-
throw new IllegalStateException("Could not disable settings dialog", exception);
214-
}
215-
}
216-
217-
private static void configureIosSettings(Application application) {
218-
AppSettings settings = new AppSettings(true);
219-
settings.setUseJoysticks(true);
220-
settings.setOnDeviceJoystickRumble(true);
176+
private static void invokeConfigureSettings(Application application, AppSettings settings) {
221177
try {
222178
java.lang.reflect.Method method = application.getClass().getMethod("configureSettings", AppSettings.class);
223-
Object target = java.lang.reflect.Modifier.isStatic(method.getModifiers()) ? null : application;
179+
Object target = Modifier.isStatic(method.getModifiers()) ? null : application;
224180
method.invoke(target, settings);
225181
} catch (NoSuchMethodException ignored) {
226182
// Most examples rely on default settings.
227183
} catch (IllegalAccessException | InvocationTargetException exception) {
228184
throw new IllegalStateException("Could not configure iOS settings for "
229185
+ application.getClass().getName(), exception);
230186
}
231-
application.setSettings(settings);
232-
}
233-
234-
private static Object invokeIfPresent(Object target, String name, Class<?>[] parameterTypes, Object... args) {
235-
if (target == null) {
236-
return MissingMethod.INSTANCE;
237-
}
238-
try {
239-
return target.getClass().getMethod(name, parameterTypes).invoke(target, args);
240-
} catch (NoSuchMethodException ignored) {
241-
return MissingMethod.INSTANCE;
242-
} catch (IllegalAccessException | InvocationTargetException exception) {
243-
throw new IllegalStateException("Could not invoke " + name, exception);
244-
}
245-
}
246-
247-
private enum MissingMethod {
248-
INSTANCE
249187
}
250188
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (c) 2009-2026 jMonkeyEngine
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
*
9+
* * Redistributions of source code must retain the above copyright
10+
* notice, this list of conditions and the following disclaimer.
11+
*
12+
* * Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
*
16+
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17+
* may be used to endorse or promote products derived from this software
18+
* without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*/
32+
package com.jme3.app;
33+
34+
import com.jme3.system.JmeContext;
35+
import com.jme3.system.ios.IGLESContext;
36+
37+
/**
38+
* Base iOS launcher for jME
39+
* Extend this class and implement {@link #createApplication()} to return the jME application to run.
40+
*
41+
*/
42+
public abstract class IosApplicationLauncher {
43+
44+
protected Application app;
45+
46+
public void start() {
47+
try {
48+
startApplication(createApplication());
49+
} catch (Exception exception) {
50+
throw new IllegalStateException("jME application initialization failed", exception);
51+
}
52+
}
53+
54+
protected void startApplication(Application application) throws Exception {
55+
app = application;
56+
if (app instanceof SimpleApplication) {
57+
((SimpleApplication) app).setShowSettings(false);
58+
}
59+
app.start();
60+
}
61+
62+
/**
63+
* Creates the jME application hosted by this launcher.
64+
*
65+
* @return the application instance
66+
* @throws Exception if the application cannot be created
67+
*/
68+
protected abstract Application createApplication() throws Exception;
69+
70+
public void update() {
71+
if (app == null) return;
72+
JmeContext context = app.getContext();
73+
if (context == null) return;
74+
if (context instanceof IGLESContext) {
75+
((IGLESContext) context).runFrame();
76+
} else {
77+
throw new IllegalStateException("Application context is not an IGLESContext");
78+
}
79+
}
80+
81+
public void resize(int width, int height) {
82+
if (app == null) return;
83+
JmeContext context = app.getContext();
84+
if (context == null) return;
85+
if (context instanceof IGLESContext) {
86+
((IGLESContext) context).resizeFramebuffer(width, height);
87+
} else {
88+
throw new IllegalStateException("Application context is not an IGLESContext");
89+
}
90+
}
91+
92+
public void stop(boolean waitFor) {
93+
if (app != null) {
94+
app.stop(waitFor);
95+
app = null;
96+
}
97+
}
98+
}

0 commit comments

Comments
 (0)