From cc3577acdc6dab88547fd937e1e0feef7ef4292c Mon Sep 17 00:00:00 2001 From: "Sha..rd" Date: Tue, 10 Jul 2012 03:46:44 +0000 Subject: [PATCH] * Android renderer now supports configuration changes (see: http://jmonkeyengine.org/groups/android/forum/topic/supporting-device-configuration-changes/#post-181170) git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9543 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../android/com/jme3/app/AndroidHarness.java | 105 +++++++++++++----- .../com/jme3/input/android/AndroidInput.java | 86 +++++++------- .../android/AndroidGLSurfaceView.java | 26 +++++ .../com/jme3/system/android/OGLESContext.java | 16 ++- 4 files changed, 159 insertions(+), 74 deletions(-) create mode 100644 engine/src/android/com/jme3/renderer/android/AndroidGLSurfaceView.java diff --git a/engine/src/android/com/jme3/app/AndroidHarness.java b/engine/src/android/com/jme3/app/AndroidHarness.java index 84b8d59a6..cba95303f 100644 --- a/engine/src/android/com/jme3/app/AndroidHarness.java +++ b/engine/src/android/com/jme3/app/AndroidHarness.java @@ -137,7 +137,26 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt protected FrameLayout frameLayout = null; final private String ESCAPE_EVENT = "TouchEscape"; private boolean firstDrawFrame = true; + private boolean inConfigChange = false; + private class DataObject { + protected Application app = null; + } + + @Override + public Object onRetainNonConfigurationInstance() { + logger.log(Level.INFO, "onRetainNonConfigurationInstance called"); + final DataObject data = new DataObject(); + data.app = this.app; + inConfigChange = true; + logger.log(Level.INFO, "app: {0}", app.hashCode()); + logger.log(Level.INFO, "ctx: {0}", ctx.hashCode()); + logger.log(Level.INFO, "view: {0}", view.hashCode()); + logger.log(Level.INFO, "isGLThreadPaused: {0}", isGLThreadPaused); + logger.log(Level.INFO, "inConfigChange: {0}", inConfigChange); + return data; + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -155,37 +174,54 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt setRequestedOrientation(screenOrientation); - // Create Settings - AppSettings settings = new AppSettings(true); - settings.setEmulateMouse(mouseEventsEnabled); - settings.setEmulateMouseFlipAxis(mouseEventsInvertX, mouseEventsInvertY); - - // Create application instance - try { - if (app == null) { - @SuppressWarnings("unchecked") - Class clazz = (Class) Class.forName(appClass); - app = clazz.newInstance(); - } + final DataObject data = (DataObject) getLastNonConfigurationInstance(); + if (data != null) { + logger.log(Level.INFO, "onCreate: onRetainNonConfigurationInstance is not null"); + this.app = data.app; - app.setSettings(settings); - app.start(); ctx = (OGLESContext) app.getContext(); view = ctx.createView(eglConfigType, eglConfigVerboseLogging); - - // Set the screen reolution - //TODO try to find a better way to get a hand on the resolution - WindowManager wind = this.getWindowManager(); - Display disp = wind.getDefaultDisplay(); - logger.log(Level.WARNING, "Resolution from Window: {0}, {1}", new Object[]{disp.getWidth(), disp.getHeight()}); - ctx.getSettings().setResolution(disp.getWidth(), disp.getHeight()); - - // AndroidHarness wraps the app as a SystemListener. ctx.setSystemListener(this); layoutDisplay(); - } catch (Exception ex) { - handleError("Class " + appClass + " init failed", ex); - setContentView(new TextView(this)); + + logger.log(Level.INFO, "app: {0}", app.hashCode()); + logger.log(Level.INFO, "ctx: {0}", ctx.hashCode()); + logger.log(Level.INFO, "view: {0}", view.hashCode()); + } else { + logger.log(Level.INFO, "onCreate: onRetainNonConfigurationInstance is null"); + + // Create Settings + AppSettings settings = new AppSettings(true); + settings.setEmulateMouse(mouseEventsEnabled); + settings.setEmulateMouseFlipAxis(mouseEventsInvertX, mouseEventsInvertY); + + // Create application instance + try { + if (app == null) { + @SuppressWarnings("unchecked") + Class clazz = (Class) Class.forName(appClass); + app = clazz.newInstance(); + } + + app.setSettings(settings); + app.start(); + ctx = (OGLESContext) app.getContext(); + view = ctx.createView(eglConfigType, eglConfigVerboseLogging); + + // Set the screen reolution + //TODO try to find a better way to get a hand on the resolution + WindowManager wind = this.getWindowManager(); + Display disp = wind.getDefaultDisplay(); + logger.log(Level.WARNING, "Resolution from Window: {0}, {1}", new Object[]{disp.getWidth(), disp.getHeight()}); + ctx.getSettings().setResolution(disp.getWidth(), disp.getHeight()); + + // AndroidHarness wraps the app as a SystemListener. + ctx.setSystemListener(this); + layoutDisplay(); + } catch (Exception ex) { + handleError("Class " + appClass + " init failed", ex); + setContentView(new TextView(this)); + } } } @@ -258,8 +294,13 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt @Override protected void onDestroy() { - if (app != null) { - app.stop(!isGLThreadPaused); + final DataObject data = (DataObject) getLastNonConfigurationInstance(); + if (data != null || inConfigChange) { + logger.info("onDestroy: found DataObject or inConfigChange"); + } else { + if (app != null) { + app.stop(!isGLThreadPaused); + } } logger.info("onDestroy"); super.onDestroy(); @@ -293,7 +334,6 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt logger.log(Level.SEVERE, finalMsg); runOnUiThread(new Runnable() { - @Override public void run() { AlertDialog dialog = new AlertDialog.Builder(AndroidHarness.this) // .setIcon(R.drawable.alert_dialog_icon) @@ -362,7 +402,14 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt splashImageView.setImageResource(splashPicID); } + if (view.getParent() != null) { + ((ViewGroup)view.getParent()).removeView(view); + } frameLayout.addView(view); + + if (splashImageView.getParent() != null) { + ((ViewGroup)splashImageView.getParent()).removeView(splashImageView); + } frameLayout.addView(splashImageView, lp); setContentView(frameLayout); diff --git a/engine/src/android/com/jme3/input/android/AndroidInput.java b/engine/src/android/com/jme3/input/android/AndroidInput.java index 1c2c22c53..fede1b06c 100644 --- a/engine/src/android/com/jme3/input/android/AndroidInput.java +++ b/engine/src/android/com/jme3/input/android/AndroidInput.java @@ -1,12 +1,6 @@ package com.jme3.input.android; -import android.content.Context; -import android.opengl.GLSurfaceView; -import android.util.AttributeSet; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; +import android.view.*; import com.jme3.input.KeyInput; import com.jme3.input.RawInputListener; import com.jme3.input.TouchInput; @@ -25,8 +19,10 @@ import java.util.logging.Logger; * @author larynx * */ -public class AndroidInput extends GLSurfaceView implements +public class AndroidInput implements TouchInput, + View.OnTouchListener, + View.OnKeyListener, GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener, ScaleGestureDetector.OnScaleGestureListener { @@ -44,6 +40,7 @@ public class AndroidInput extends GLSurfaceView implements final private RingBuffer eventPool = new RingBuffer(MAX_EVENTS); final private HashMap lastPositions = new HashMap(); // Internal + private View view; private ScaleGestureDetector scaledetector; private GestureDetector detector; private int lastX; @@ -149,17 +146,16 @@ public class AndroidInput extends GLSurfaceView implements 0x0,//mute }; - public AndroidInput(Context ctx, AttributeSet attribs) { - super(ctx, attribs); + public AndroidInput(View view) { + setView(view); detector = new GestureDetector(null, this, null, false); - scaledetector = new ScaleGestureDetector(ctx, this); - + scaledetector = new ScaleGestureDetector(view.getContext(), this); } - public AndroidInput(Context ctx) { - super(ctx); - detector = new GestureDetector(null, this, null, false); - scaledetector = new ScaleGestureDetector(ctx, this); + public void setView(View view) { + this.view = view; + this.view.setOnTouchListener(this); + this.view.setOnKeyListener(this); } private TouchEvent getNextFreeTouchEvent() { @@ -218,10 +214,12 @@ public class AndroidInput extends GLSurfaceView implements } /** - * onTouchEvent gets called from android thread on touchpad events + * onTouch gets called from android thread on touchpad events */ - @Override - public boolean onTouchEvent(MotionEvent event) { + public boolean onTouch(View view, MotionEvent event) { + if (view != this.view) { + return false; + } boolean bWasHandled = false; TouchEvent touch; // System.out.println("native : " + event.getAction()); @@ -236,7 +234,7 @@ public class AndroidInput extends GLSurfaceView implements case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_DOWN: touch = getNextFreeTouchEvent(); - touch.set(Type.DOWN, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0); + touch.set(Type.DOWN, event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex), 0, 0); touch.setPointerId(pointerId); touch.setTime(event.getEventTime()); touch.setPressure(event.getPressure(pointerIndex)); @@ -248,7 +246,7 @@ public class AndroidInput extends GLSurfaceView implements case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: touch = getNextFreeTouchEvent(); - touch.set(Type.UP, event.getX(pointerIndex), this.getHeight() - event.getY(pointerIndex), 0, 0); + touch.set(Type.UP, event.getX(pointerIndex), view.getHeight() - event.getY(pointerIndex), 0, 0); touch.setPointerId(pointerId); touch.setTime(event.getEventTime()); touch.setPressure(event.getPressure(pointerIndex)); @@ -261,16 +259,16 @@ public class AndroidInput extends GLSurfaceView implements for (int p = 0; p < event.getPointerCount(); p++) { Vector2f lastPos = lastPositions.get(p); if (lastPos == null) { - lastPos = new Vector2f(event.getX(p), this.getHeight() - event.getY(p)); + lastPos = new Vector2f(event.getX(p), view.getHeight() - event.getY(p)); lastPositions.put(event.getPointerId(p), lastPos); } touch = getNextFreeTouchEvent(); - touch.set(Type.MOVE, event.getX(p), this.getHeight() - event.getY(p), event.getX(p) - lastPos.x, this.getHeight() - event.getY(p) - lastPos.y); + touch.set(Type.MOVE, event.getX(p), view.getHeight() - event.getY(p), event.getX(p) - lastPos.x, view.getHeight() - event.getY(p) - lastPos.y); touch.setPointerId(event.getPointerId(p)); touch.setTime(event.getEventTime()); touch.setPressure(event.getPressure(p)); processEvent(touch); - lastPos.set(event.getX(p), this.getHeight() - event.getY(p)); + lastPos.set(event.getX(p), view.getHeight() - event.getY(p)); } bWasHandled = true; break; @@ -286,8 +284,15 @@ public class AndroidInput extends GLSurfaceView implements return bWasHandled; } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { + /** + * onKey gets called from android thread on key events + */ + public boolean onKey(View view, int keyCode, KeyEvent event) { + if (view != this.view) { + return false; + } + + if (event.getAction() == KeyEvent.ACTION_DOWN) { TouchEvent evt; evt = getNextFreeTouchEvent(); evt.set(TouchEvent.Type.KEY_DOWN); @@ -304,10 +309,7 @@ public class AndroidInput extends GLSurfaceView implements } else { return true; } - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { + } else if (event.getAction() == KeyEvent.ACTION_UP) { TouchEvent evt; evt = getNextFreeTouchEvent(); evt.set(TouchEvent.Type.KEY_UP); @@ -324,6 +326,9 @@ public class AndroidInput extends GLSurfaceView implements } else { return true; } + } else { + return false; + } } public void loadSettings(AppSettings settings) { @@ -401,13 +406,13 @@ public class AndroidInput extends GLSurfaceView implements if (mouseEventsEnabled) { if (mouseEventsInvertX) { - newX = this.getWidth() - (int) event.getX(); + newX = view.getWidth() - (int) event.getX(); } else { newX = (int) event.getX(); } if (mouseEventsInvertY) { - newY = this.getHeight() - (int) event.getY(); + newY = view.getHeight() - (int) event.getY(); } else { newY = (int) event.getY(); } @@ -476,7 +481,7 @@ public class AndroidInput extends GLSurfaceView implements public void onLongPress(MotionEvent event) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.LONGPRESSED, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.set(Type.LONGPRESSED, event.getX(), view.getHeight() - event.getY(), 0f, 0f); touch.setPointerId(0); touch.setTime(event.getEventTime()); processEvent(touch); @@ -484,7 +489,7 @@ public class AndroidInput extends GLSurfaceView implements public boolean onFling(MotionEvent event, MotionEvent event2, float vx, float vy) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.FLING, event.getX(), this.getHeight() - event.getY(), vx, vy); + touch.set(Type.FLING, event.getX(), view.getHeight() - event.getY(), vx, vy); touch.setPointerId(0); touch.setTime(event.getEventTime()); processEvent(touch); @@ -499,7 +504,7 @@ public class AndroidInput extends GLSurfaceView implements public boolean onDoubleTap(MotionEvent event) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.DOUBLETAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.set(Type.DOUBLETAP, event.getX(), view.getHeight() - event.getY(), 0f, 0f); touch.setPointerId(0); touch.setTime(event.getEventTime()); processEvent(touch); @@ -525,7 +530,7 @@ public class AndroidInput extends GLSurfaceView implements public boolean onScale(ScaleGestureDetector scaleGestureDetector) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); + touch.set(Type.SCALE_MOVE, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); touch.setPointerId(0); touch.setTime(scaleGestureDetector.getEventTime()); touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); @@ -538,7 +543,7 @@ public class AndroidInput extends GLSurfaceView implements public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), this.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); + touch.set(Type.SCALE_END, scaleGestureDetector.getFocusX(), view.getHeight() - scaleGestureDetector.getFocusY(), 0f, 0f); touch.setPointerId(0); touch.setTime(scaleGestureDetector.getEventTime()); touch.setScaleSpan(scaleGestureDetector.getCurrentSpan()); @@ -548,7 +553,7 @@ public class AndroidInput extends GLSurfaceView implements public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SCROLL, e1.getX(), this.getHeight() - e1.getY(), distanceX, distanceY * (-1)); + touch.set(Type.SCROLL, e1.getX(), view.getHeight() - e1.getY(), distanceX, distanceY * (-1)); touch.setPointerId(0); touch.setTime(e1.getEventTime()); processEvent(touch); @@ -558,7 +563,7 @@ public class AndroidInput extends GLSurfaceView implements public void onShowPress(MotionEvent event) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.SHOWPRESS, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.set(Type.SHOWPRESS, event.getX(), view.getHeight() - event.getY(), 0f, 0f); touch.setPointerId(0); touch.setTime(event.getEventTime()); processEvent(touch); @@ -566,7 +571,7 @@ public class AndroidInput extends GLSurfaceView implements public boolean onSingleTapUp(MotionEvent event) { TouchEvent touch = getNextFreeTouchEvent(); - touch.set(Type.TAP, event.getX(), this.getHeight() - event.getY(), 0f, 0f); + touch.set(Type.TAP, event.getX(), view.getHeight() - event.getY(), 0f, 0f); touch.setPointerId(0); touch.setTime(event.getEventTime()); processEvent(touch); @@ -623,4 +628,5 @@ public class AndroidInput extends GLSurfaceView implements public boolean isSimulateMouse() { return mouseEventsEnabled; } + } diff --git a/engine/src/android/com/jme3/renderer/android/AndroidGLSurfaceView.java b/engine/src/android/com/jme3/renderer/android/AndroidGLSurfaceView.java new file mode 100644 index 000000000..b328c6b79 --- /dev/null +++ b/engine/src/android/com/jme3/renderer/android/AndroidGLSurfaceView.java @@ -0,0 +1,26 @@ +package com.jme3.renderer.android; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import java.util.logging.Logger; + +/** + * AndroidGLSurfaceView is derived from GLSurfaceView + * @author iwgeric + * + */ +public class AndroidGLSurfaceView extends GLSurfaceView { + + private final static Logger logger = Logger.getLogger(AndroidGLSurfaceView.class.getName()); + + public AndroidGLSurfaceView(Context ctx, AttributeSet attribs) { + super(ctx, attribs); + } + + public AndroidGLSurfaceView(Context ctx) { + super(ctx); + } + + +} \ No newline at end of file diff --git a/engine/src/android/com/jme3/system/android/OGLESContext.java b/engine/src/android/com/jme3/system/android/OGLESContext.java index 2d9a0b10f..8c3df1aef 100644 --- a/engine/src/android/com/jme3/system/android/OGLESContext.java +++ b/engine/src/android/com/jme3/system/android/OGLESContext.java @@ -31,9 +31,10 @@ */ package com.jme3.system.android; +import com.jme3.renderer.android.AndroidGLSurfaceView; +import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; -import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.text.InputType; import android.view.Gravity; @@ -73,7 +74,8 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex protected Timer timer; protected SystemListener listener; protected boolean autoFlush = true; - protected AndroidInput view; + protected AndroidInput androidInput; + protected AndroidGLSurfaceView view; protected int minFrameDuration = 0; // No FPS cap /** * EGL_RENDERABLE_TYPE: EGL_OPENGL_ES_BIT = OpenGL ES 1.0 | @@ -105,9 +107,13 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex * @return GLSurfaceView The newly created view */ public GLSurfaceView createView(ConfigType configType, boolean eglConfigVerboseLogging) { - // Start to set up the view - this.view = new AndroidInput(JmeAndroidSystem.getActivity()); + view = new AndroidGLSurfaceView(JmeAndroidSystem.getActivity()); + if (androidInput == null) { + androidInput = new AndroidInput(view); + } else { + androidInput.setView(view); + } if (configType == ConfigType.LEGACY) { // Hardcoded egl setup clientOpenGLESVersion = 2; @@ -268,7 +274,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer, SoftTex @Override public TouchInput getTouchInput() { - return view; + return androidInput; } @Override