--- a/README.android Tue Jun 19 12:29:53 2012 -0400
+++ b/README.android Tue Jun 19 13:57:42 2012 -0300
@@ -74,6 +74,24 @@
================================================================================
+ Pause / Resume behaviour
+================================================================================
+
+If SDL is compiled with SDL_ANDROID_BLOCK_ON_PAUSE defined, the event loop will
+block itself when the app is paused (ie, when the user returns to the main
+Android dashboard). Blocking is better in terms of battery use, and it allows your
+app to spring back to life instantaneously after resume (versus polling for
+a resume message).
+Upon resume, SDL will attempt to restore the GL context automatically.
+In modern devices (Android 3.0 and up) this will most likely succeed and your
+app can continue to operate as it was.
+However, there's a chance (on older hardware, or on systems under heavy load),
+where the GL context can not be restored. In that case you have to listen for
+a specific message, (which is not yet implemented!) and restore your textures
+manually or quit the app (which is actually the kind of behaviour you'll see
+under iOS, if the OS can not restore your GL context it will just kill your app)
+
+================================================================================
Additional documentation
================================================================================
--- a/android-project/src/org/libsdl/app/SDLActivity.java Tue Jun 19 12:29:53 2012 -0400
+++ b/android-project/src/org/libsdl/app/SDLActivity.java Tue Jun 19 13:57:42 2012 -0300
@@ -68,17 +68,17 @@
}
// Events
- protected void onPause() {
+ /*protected void onPause() {
Log.v("SDL", "onPause()");
super.onPause();
- SDLActivity.nativePause();
+ // Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
}
protected void onResume() {
Log.v("SDL", "onResume()");
super.onResume();
- SDLActivity.nativeResume();
- }
+ // Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
+ }*/
protected void onDestroy() {
super.onDestroy();
@@ -249,12 +249,15 @@
return false;
}
- if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
- Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
- createEGLContext();
+ if (egl.eglGetCurrentContext() != SDLActivity.mEGLContext) {
if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
- Log.e("SDL", "Failed making EGL Context current");
- return false;
+ Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
+ // TODO: Notify the user via a message that the old context could not be restored, and that textures need to be manually restored.
+ createEGLContext();
+ if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
+ Log.e("SDL", "Failed making EGL Context current");
+ return false;
+ }
}
}
SDLActivity.mEGLSurface = surface;
@@ -426,7 +429,6 @@
public void surfaceCreated(SurfaceHolder holder) {
Log.v("SDL", "surfaceCreated()");
holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
- SDLActivity.createEGLSurface();
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
}
--- a/src/core/android/SDL_android.cpp Tue Jun 19 12:29:53 2012 -0400
+++ b/src/core/android/SDL_android.cpp Tue Jun 19 13:57:42 2012 -0300
@@ -176,6 +176,8 @@
JNIEnv* env, jclass cls)
{
if (Android_Window) {
+ /* Signal the pause semaphore so the event loop knows to pause and (optionally) block itself */
+ if (!SDL_SemValue(Android_PauseSem)) SDL_SemPost(Android_PauseSem);
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}
@@ -186,6 +188,11 @@
JNIEnv* env, jclass cls)
{
if (Android_Window) {
+ /* Signal the resume semaphore so the event loop knows to resume and restore the GL Context
+ * We can't restore the GL Context here because it needs to be done on the SDL main thread
+ * and this function will be called from the Java thread instead.
+ */
+ if (!SDL_SemValue(Android_ResumeSem)) SDL_SemPost(Android_ResumeSem);
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
}
--- a/src/video/android/SDL_androidevents.c Tue Jun 19 12:29:53 2012 -0400
+++ b/src/video/android/SDL_androidevents.c Tue Jun 19 13:57:42 2012 -0300
@@ -27,7 +27,37 @@
void
Android_PumpEvents(_THIS)
{
+ static int isPaused = 0;
/* No polling necessary */
+
+ /*
+ * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
+ * When the pause semaphoe is signaled, if SDL_ANDROID_BLOCK_ON_PAUSE is defined the event loop will block until the resume signal is emitted.
+ * When the resume semaphore is signaled, SDL_GL_CreateContext is called which in turn calls Java code
+ * SDLActivity::createGLContext -> SDLActivity:: initEGL -> SDLActivity::createEGLSurface -> SDLActivity::createEGLContext
+ */
+ if (isPaused) {
+#if SDL_ANDROID_BLOCK_ON_PAUSE
+ if(SDL_SemWait(Android_ResumeSem) == 0) {
+#else
+ if(SDL_SemTryWait(Android_ResumeSem) == 0) {
+#endif
+ isPaused = 0;
+ /* TODO: Should we double check if we are on the same thread as the one that made the original GL context?
+ * This call will go through the following chain of calls in Java:
+ * SDLActivity::createGLContext -> SDLActivity:: initEGL -> SDLActivity::createEGLSurface -> SDLActivity::createEGLContext
+ * SDLActivity::createEGLContext will attempt to restore the GL context first, and if that fails it will create a new one
+ * If a new GL context is created, the user needs to restore the textures manually (TODO: notify the user that this happened with a message)
+ */
+ SDL_GL_CreateContext(Android_Window);
+ }
+ }
+ else {
+ if(SDL_SemTryWait(Android_PauseSem) == 0) {
+ /* If we fall in here, the system is/was paused */
+ isPaused = 1;
+ }
+ }
}
#endif /* SDL_VIDEO_DRIVER_ANDROID */
--- a/src/video/android/SDL_androidvideo.c Tue Jun 19 12:29:53 2012 -0400
+++ b/src/video/android/SDL_androidvideo.c Tue Jun 19 13:57:42 2012 -0300
@@ -64,6 +64,7 @@
int Android_ScreenWidth = 0;
int Android_ScreenHeight = 0;
Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_UNKNOWN;
+SDL_sem *Android_PauseSem = NULL, *Android_ResumeSem = NULL;
/* Currently only one window */
SDL_Window *Android_Window = NULL;
--- a/src/video/android/SDL_androidvideo.h Tue Jun 19 12:29:53 2012 -0400
+++ b/src/video/android/SDL_androidvideo.h Tue Jun 19 13:57:42 2012 -0300
@@ -23,6 +23,7 @@
#ifndef _SDL_androidvideo_h
#define _SDL_androidvideo_h
+#include "SDL_mutex.h"
#include "../SDL_sysvideo.h"
/* Called by the JNI layer when the screen changes size or format */
@@ -33,8 +34,10 @@
extern int Android_ScreenWidth;
extern int Android_ScreenHeight;
extern Uint32 Android_ScreenFormat;
+extern SDL_sem *Android_PauseSem, *Android_ResumeSem;
extern SDL_Window *Android_Window;
+
#endif /* _SDL_androidvideo_h */
/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/android/SDL_androidwindow.c Tue Jun 19 12:29:53 2012 -0400
+++ b/src/video/android/SDL_androidwindow.c Tue Jun 19 13:57:42 2012 -0300
@@ -35,6 +35,8 @@
return -1;
}
Android_Window = window;
+ Android_PauseSem = SDL_CreateSemaphore(0);
+ Android_ResumeSem = SDL_CreateSemaphore(0);
/* Adjust the window data to match the screen */
window->x = 0;
@@ -62,6 +64,10 @@
{
if (window == Android_Window) {
Android_Window = NULL;
+ if (Android_PauseSem) SDL_DestroySemaphore(Android_PauseSem);
+ if (Android_ResumeSem) SDL_DestroySemaphore(Android_ResumeSem);
+ Android_PauseSem = NULL;
+ Android_ResumeSem = NULL;
}
}