OSDN Git Service

* Eclipse classpath no longer includes .svn folders
[mikumikustudio/MikuMikuStudio.git] / engine / src / android / com / jme3 / app / AndroidHarness.java
1 package com.jme3.app;\r
2 \r
3 import java.util.logging.Handler;\r
4 import java.util.logging.Level;\r
5 import java.util.logging.Logger;\r
6 import java.util.logging.SimpleFormatter;\r
7 import com.jme3.util.JmeFormatter;\r
8 import android.app.Activity;\r
9 import android.app.AlertDialog;\r
10 import android.content.DialogInterface;\r
11 import android.content.pm.ActivityInfo;\r
12 import android.opengl.GLSurfaceView;\r
13 import android.os.Bundle;\r
14 import android.view.Display;\r
15 import android.view.SurfaceView;\r
16 import android.view.View;\r
17 import android.view.Window;\r
18 import android.view.WindowManager;\r
19 import android.widget.TextView;\r
20 \r
21 import com.jme3.app.Application;\r
22 import com.jme3.input.TouchInput;\r
23 import com.jme3.input.android.AndroidInput;\r
24 import com.jme3.input.controls.TouchListener;\r
25 import com.jme3.input.controls.TouchTrigger;\r
26 import com.jme3.input.event.TouchEvent;\r
27 import com.jme3.system.AppSettings;\r
28 import com.jme3.system.JmeSystem;\r
29 import com.jme3.system.android.OGLESContext;\r
30 import com.jme3.system.android.AndroidConfigChooser.ConfigType;\r
31 \r
32 /**\r
33  * <code>AndroidHarness</code> wraps a jme application object and runs it on Android\r
34  * @author Kirill\r
35  * @author larynx\r
36  */\r
37 public class AndroidHarness extends Activity implements TouchListener, DialogInterface.OnClickListener {\r
38 \r
39     protected final static Logger logger = Logger.getLogger(AndroidHarness.class.getName());\r
40     /**\r
41      * The application class to start\r
42      */\r
43     protected String appClass = "jme3test.android.Test";\r
44     /**\r
45      * The jme3 application object\r
46      */\r
47     protected Application app = null;\r
48     /**\r
49      * ConfigType.FASTEST is RGB565, GLSurfaceView default\r
50      * ConfigType.BEST is RGBA8888 or better if supported by the hardware\r
51      */\r
52     protected ConfigType eglConfigType = ConfigType.FASTEST;\r
53     /**\r
54      * If true all valid and not valid egl configs are logged\r
55      */\r
56     protected boolean eglConfigVerboseLogging = false;\r
57     /**\r
58      * If true MouseEvents are generated from TouchEvents\r
59      */\r
60     protected boolean mouseEventsEnabled = true;\r
61     /**\r
62      * Flip X axis\r
63      */\r
64     protected boolean mouseEventsInvertX = true;\r
65     /**\r
66      * Flip Y axis\r
67      */\r
68     protected boolean mouseEventsInvertY = true;\r
69     /**\r
70      * Title of the exit dialog, default is "Do you want to exit?"\r
71      */\r
72     protected String exitDialogTitle = "Do you want to exit?";\r
73     /**\r
74      * Message of the exit dialog, default is "Use your home key to bring this app into the background or exit to terminate it."\r
75      */\r
76     protected String exitDialogMessage = "Use your home key to bring this app into the background or exit to terminate it.";\r
77     \r
78     /**\r
79      * Set the screen window size\r
80      * if screenFullSize is true, then the notification bar and title bar are\r
81      *   removed and the screen covers the entire display\r
82      * if screenFullSize is false, then the notification bar remains visible\r
83      *   if screenShowTitle is true while screenFullScreen is false, then the\r
84      *     title bar is also displayed under the notification bar\r
85      */\r
86     protected boolean screenFullScreen = true;\r
87     \r
88     /**\r
89      * if screenShowTitle is true while screenFullScreen is false, then the\r
90      *     title bar is also displayed under the notification bar\r
91      */\r
92     protected boolean screenShowTitle = true;\r
93     \r
94     /**\r
95      * Set the screen orientation, default is SENSOR\r
96      * ActivityInfo.SCREEN_ORIENTATION_* constants\r
97      * package android.content.pm.ActivityInfo\r
98      *  \r
99      *   SCREEN_ORIENTATION_UNSPECIFIED\r
100      *   SCREEN_ORIENTATION_LANDSCAPE\r
101      *   SCREEN_ORIENTATION_PORTRAIT\r
102      *   SCREEN_ORIENTATION_USER\r
103      *   SCREEN_ORIENTATION_BEHIND\r
104      *   SCREEN_ORIENTATION_SENSOR (default)\r
105      *   SCREEN_ORIENTATION_NOSENSOR\r
106      */\r
107     protected int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;\r
108     protected OGLESContext ctx;\r
109     protected GLSurfaceView view = null;\r
110     protected boolean isGLThreadPaused = true;\r
111     final private String ESCAPE_EVENT = "TouchEscape";\r
112 \r
113     @Override\r
114     public void onCreate(Bundle savedInstanceState) {\r
115         super.onCreate(savedInstanceState);\r
116 \r
117         Logger log = logger;\r
118         boolean bIsLogFormatSet = false;\r
119         do {\r
120             if (log.getHandlers().length == 0) {\r
121                 log = logger.getParent();\r
122                 if (log != null) {\r
123                     for (Handler h : log.getHandlers()) {\r
124                         //h.setFormatter(new SimpleFormatter());\r
125                         h.setFormatter(new JmeFormatter());\r
126                         bIsLogFormatSet = true;\r
127                     }\r
128                 }\r
129             }\r
130         } while (log != null && !bIsLogFormatSet);\r
131 \r
132         JmeSystem.setResources(getResources());\r
133         JmeSystem.setActivity(this);\r
134 \r
135         if (screenFullScreen) {\r
136             requestWindowFeature(Window.FEATURE_NO_TITLE);\r
137             getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,\r
138                     WindowManager.LayoutParams.FLAG_FULLSCREEN);\r
139         } else {\r
140             if (!screenShowTitle) {\r
141                 requestWindowFeature(Window.FEATURE_NO_TITLE);\r
142             }\r
143         }\r
144 \r
145         setRequestedOrientation(screenOrientation);\r
146 \r
147         // Create Settings\r
148         AppSettings settings = new AppSettings(true);\r
149 \r
150         // Create the input class\r
151         AndroidInput input = new AndroidInput(this);\r
152         input.setMouseEventsInvertX(mouseEventsInvertX);\r
153         input.setMouseEventsInvertY(mouseEventsInvertY);\r
154         input.setMouseEventsEnabled(mouseEventsEnabled);\r
155 \r
156         // Create application instance\r
157         try {\r
158             if (app == null) {\r
159                 @SuppressWarnings("unchecked")\r
160                 Class<? extends Application> clazz = (Class<? extends Application>) Class.forName(appClass);\r
161                 app = clazz.newInstance();\r
162             }\r
163 \r
164             app.setSettings(settings);\r
165             app.start();\r
166             ctx = (OGLESContext) app.getContext();\r
167             view = ctx.createView(input, eglConfigType, eglConfigVerboseLogging);\r
168             setContentView(view);\r
169 \r
170             // Set the screen reolution\r
171             WindowManager wind = this.getWindowManager();\r
172             Display disp = wind.getDefaultDisplay();\r
173             ctx.getSettings().setResolution(disp.getWidth(), disp.getHeight());\r
174 \r
175             AppSettings s = ctx.getSettings();\r
176             logger.log(Level.INFO, "Settings: Width {0} Height {1}", new Object[]{s.getWidth(), s.getHeight()});\r
177         } catch (Exception ex) {\r
178             handleError("Class " + appClass + " init failed", ex);\r
179             setContentView(new TextView(this));\r
180         }\r
181     }\r
182 \r
183     @Override\r
184     protected void onRestart() {\r
185         super.onRestart();\r
186         if (app != null) {\r
187             app.restart();\r
188         }\r
189         logger.info("onRestart");\r
190     }\r
191 \r
192     @Override\r
193     protected void onStart() {\r
194         super.onStart();\r
195         logger.info("onStart");\r
196     }\r
197 \r
198     @Override\r
199     protected void onResume() {\r
200         super.onResume();\r
201         if (view != null) {\r
202             view.onResume();\r
203         }\r
204         isGLThreadPaused = false;\r
205         logger.info("onResume");\r
206     }\r
207 \r
208     @Override\r
209     protected void onPause() {\r
210         super.onPause();\r
211         if (view != null) {\r
212             view.onPause();\r
213         }\r
214         isGLThreadPaused = true;\r
215         logger.info("onPause");\r
216     }\r
217 \r
218     @Override\r
219     protected void onStop() {\r
220         super.onStop();\r
221         logger.info("onStop");\r
222     }\r
223 \r
224     @Override\r
225     protected void onDestroy() {\r
226         if (app != null) {\r
227             app.stop(!isGLThreadPaused);\r
228         }\r
229         super.onDestroy();\r
230         logger.info("onDestroy");\r
231     }\r
232 \r
233     public Application getJmeApplication() {\r
234         return app;\r
235     }\r
236 \r
237     /**\r
238      * Called when an error has occured. This is typically\r
239      * invoked when an uncaught exception is thrown in the render thread.\r
240      * @param errorMsg The error message, if any, or null.\r
241      * @param t Throwable object, or null.\r
242      */\r
243     public void handleError(final String errorMsg, final Throwable t) {\r
244         String sTrace = "";\r
245         if (t != null && t.getStackTrace() != null) {\r
246             for (StackTraceElement ste : t.getStackTrace()) {\r
247                 sTrace += "\tat " + ste.getClassName() + "." + ste.getMethodName() + "(";\r
248                 if (ste.isNativeMethod()){\r
249                     sTrace += "Native";\r
250                 }else{\r
251                     sTrace += ste.getLineNumber();\r
252                 }\r
253                 sTrace +=  ")\n";\r
254             }\r
255         }\r
256 \r
257         final String stackTrace = sTrace;\r
258 \r
259         logger.log(Level.SEVERE, t != null ? t.toString() : "OpenGL Exception");\r
260         logger.log(Level.SEVERE, "{0}{1}", new Object[]{errorMsg != null ? errorMsg + ": " : "", stackTrace});\r
261 \r
262         this.runOnUiThread(new Runnable() {\r
263             @Override\r
264             public void run() {\r
265                 AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon)\r
266                         .setTitle(t != null ? (t.getMessage() != null ? (t.getMessage() + ": " + t.getClass().getName()) : t.getClass().getName()) : "OpenGL Exception").setPositiveButton("Kill", AndroidHarness.this).setMessage((errorMsg != null ? errorMsg + ": " : "") + stackTrace).create();\r
267                 dialog.show();\r
268             }\r
269         });\r
270 \r
271     }\r
272 \r
273     /**\r
274      * Called by the android alert dialog, terminate the activity and OpenGL rendering\r
275      * @param dialog\r
276      * @param whichButton\r
277      */\r
278     public void onClick(DialogInterface dialog, int whichButton) {\r
279         if (whichButton != -2) {\r
280             if (app != null) {\r
281                 app.stop(true);\r
282             }\r
283             this.finish();\r
284         }\r
285     }\r
286 \r
287     /**\r
288      * Gets called by the InputManager on all touch/drag/scale events\r
289      */\r
290     @Override\r
291     public void onTouch(String name, TouchEvent evt, float tpf) {\r
292         if (name.equals(ESCAPE_EVENT)) {\r
293             switch (evt.getType()) {\r
294                 case KEY_UP:\r
295                     this.runOnUiThread(new Runnable() {\r
296                         @Override\r
297                         public void run() {\r
298                             AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon)\r
299                                     .setTitle(exitDialogTitle).setPositiveButton("Yes", AndroidHarness.this).setNegativeButton("No", AndroidHarness.this).setMessage(exitDialogMessage).create();\r
300                             dialog.show();\r
301                         }\r
302                     });\r
303 \r
304                     break;\r
305                 default:\r
306                     break;\r
307             }\r
308         }\r
309 \r
310     }\r
311 }\r