Selaa lähdekoodia

Fixes Android activity (app) life cycle issues.
Fixes automatic audio source pausing from Game::pause().
Minor cleanup in the development guide.
Cleaned up the Maya files for the mesh and character samples.

Chris Culy 13 vuotta sitten
vanhempi
sitoutus
39a5e125a9

+ 10 - 1
.gitignore

@@ -156,4 +156,13 @@ Thumbs.db
 /gameplay-samples/sample04-particles/Device-Debug
 /gameplay-samples/sample04-particles/Debug
 /gameplay-samples/sample04-particles/DebugMem
-/gameplay-samples/sample03-character/res/gamepad.xcf
+/gameplay-samples/sample03-character/res/gamepad.xcf
+/gameplay-samples/sample04-particles/android/src
+/gameplay-samples/sample04-particles/android/assets
+/gameplay-samples/sample04-particles/android/bin
+/gameplay-samples/sample04-particles/android/gen
+/gameplay-samples/sample04-particles/android/libs
+/gameplay-samples/sample04-particles/android/obj
+/gameplay-samples/sample04-particles/android/proguard.cfg
+/gameplay-samples/sample04-particles/android/local.properties
+/gameplay-samples/sample04-particles/android/project.properties

+ 67 - 70
gameplay/src/AudioController.cpp

@@ -8,18 +8,15 @@
 namespace gameplay
 {
 
-std::list<AudioSource*> AudioController::_playingSources;
-
-
 #ifndef __ANDROID__
 AudioController::AudioController() 
-    : _alcDevice(NULL), _alcContext(NULL)
+    : _alcDevice(NULL), _alcContext(NULL), _pausingSource(NULL)
 {
 }
 #else
 AudioController::AudioController() 
     : _engineObject(NULL), _engineEngine(NULL), _outputMixObject(NULL), _listenerObject(NULL),
-    _listenerDoppler(NULL), _listenerLocation(NULL)
+    _listenerDoppler(NULL), _listenerLocation(NULL), _pausingSource(NULL)
 {
 }
 #endif
@@ -93,6 +90,42 @@ void AudioController::initialize()
         LOG_ERROR("AudioController::initialize() error. Unable to realize OpenSL output mix.");
         return;
     }
+
+    // Load the listener and its supported interfaces.
+    if (!_listenerObject)
+    {
+        const SLInterfaceID interfaces[3] = {SL_IID_3DDOPPLER, SL_IID_3DLOCATION};
+        const SLboolean required[3] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};
+        SLresult result = (*_engineEngine)->CreateListener(_engineEngine, &_listenerObject, 2, interfaces, required);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN_VARG("AudioController: failed to create listener (%u).", result);
+            return;
+        }
+
+        result = (*_listenerObject)->Realize(_listenerObject, SL_BOOLEAN_FALSE);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: failed to realize listener.");
+            return;
+        }
+
+        // Get the doppler interface in order to set the listener's velocity.
+        result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DDOPPLER, &_listenerDoppler);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to retrieve listener doppler interface.");
+            return;
+        }
+
+        // Get the location interface in order to set the listener's position and orientation.
+        result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DLOCATION, &_listenerLocation);
+        if (result != SL_RESULT_SUCCESS)
+        {
+            WARN("AudioController: Unable to retrieve listener location interface.");
+            return;
+        }
+    }
 #endif
 }
 
@@ -128,17 +161,16 @@ void AudioController::finalize()
 
 void AudioController::pause()
 {
-    std::list<AudioSource*>::iterator itr = _playingSources.begin();
+    std::set<AudioSource*>::iterator itr = _playingSources.begin();
 
     // For each source that is playing, pause it.
     AudioSource* source = NULL;
     while (itr != _playingSources.end())
     {
         source = *itr;
-        if (source->getState() == AudioSource::PLAYING)
-        {
-            source->pause();
-        }
+        _pausingSource = source;
+        source->pause();
+        _pausingSource = NULL;
         itr++;
     }
 }
@@ -148,17 +180,14 @@ void AudioController::resume()
 #ifndef __ANDROID__    
     alcMakeContextCurrent(_alcContext);
 #endif
-    std::list<AudioSource*>::iterator itr = _playingSources.begin();
+    std::set<AudioSource*>::iterator itr = _playingSources.begin();
 
     // For each source that is playing, resume it.
     AudioSource* source = NULL;
     while (itr != _playingSources.end())
     {
         source = *itr;
-        if (source->getState() == AudioSource::PAUSED)
-        {
-            source->play();
-        }
+        source->resume();
         itr++;
     }
 }
@@ -174,74 +203,42 @@ void AudioController::update(long elapsedTime)
         alListenerfv(AL_VELOCITY, (ALfloat*)&listener->getVelocity());
         alListenerfv(AL_POSITION, (ALfloat*)&listener->getPosition());
 #else
-        if (!_listenerObject)
+        if (_listenerObject)
         {
-            const SLInterfaceID interfaces[3] = {SL_IID_3DDOPPLER, SL_IID_3DLOCATION};
-            const SLboolean required[3] = {SL_BOOLEAN_FALSE, SL_BOOLEAN_FALSE};
-            SLresult result = (*_engineEngine)->CreateListener(_engineEngine, &_listenerObject, 2, interfaces, required);
-            if (result != SL_RESULT_SUCCESS)
-            {
-                WARN_VARG("AudioController: failed to create listener (%u).", result);
-                return;
-            }
-
-            result = (*_listenerObject)->Realize(_listenerObject, SL_BOOLEAN_FALSE);
+            SLVec3D f;
+            f.x = listener->getOrientationForward().x;
+            f.y = listener->getOrientationForward().y;
+            f.z = listener->getOrientationForward().z;
+            SLVec3D a;
+            a.x = listener->getOrientationUp().x;
+            a.y = listener->getOrientationUp().y;
+            a.z = listener->getOrientationUp().z;
+            SLresult result = (*_listenerLocation)->SetOrientationVectors(_listenerLocation, &f, &a);
             if (result != SL_RESULT_SUCCESS)
             {
-                WARN("AudioController: failed to realize listener.");
-                return;
+                WARN("AudioController: Unable to set listener orientation.");
             }
 
-            // Get the doppler interface in order to set the listener's velocity.
-            result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DDOPPLER, &_listenerDoppler);
+            SLVec3D p;
+            p.x = listener->getPosition().x;
+            p.y = listener->getPosition().y;
+            p.z = listener->getPosition().z;
+            result = (*_listenerLocation)->SetLocationCartesian(_listenerLocation, &p);
             if (result != SL_RESULT_SUCCESS)
             {
-                WARN("AudioController: Unable to retrieve listener doppler interface.");
-                return;
+                WARN("AudioController: Unable to set listener location.");
             }
 
-            // Get the location interface in order to set the listener's position and orientation.
-            result = (*_listenerObject)->GetInterface(_listenerObject, SL_IID_3DLOCATION, &_listenerLocation);
+            SLVec3D v;
+            v.x = listener->getVelocity().x;
+            v.y = listener->getVelocity().y;
+            v.z = listener->getVelocity().z;
+            result = (*_listenerDoppler)->SetVelocityCartesian(_listenerDoppler, &v);
             if (result != SL_RESULT_SUCCESS)
             {
-                WARN("AudioController: Unable to retrieve listener location interface.");
-                return;
+                WARN("AudioController: Unable to set listener velocity.");
             }
         }
-        
-        SLVec3D f;
-        f.x = listener->getOrientationForward().x;
-        f.y = listener->getOrientationForward().y;
-        f.z = listener->getOrientationForward().z;
-        SLVec3D a;
-        a.x = listener->getOrientationUp().x;
-        a.y = listener->getOrientationUp().y;
-        a.z = listener->getOrientationUp().z;
-        SLresult result = (*_listenerLocation)->SetOrientationVectors(_listenerLocation, &f, &a);
-        if (result != SL_RESULT_SUCCESS)
-        {
-            WARN("AudioController: Unable to set listener orientation.");
-        }
-
-        SLVec3D p;
-        p.x = listener->getPosition().x;
-        p.y = listener->getPosition().y;
-        p.z = listener->getPosition().z;
-        result = (*_listenerLocation)->SetLocationCartesian(_listenerLocation, &p);
-        if (result != SL_RESULT_SUCCESS)
-        {
-            WARN("AudioController: Unable to set listener location.");
-        }
-
-        SLVec3D v;
-        v.x = listener->getVelocity().x;
-        v.y = listener->getVelocity().y;
-        v.z = listener->getVelocity().z;
-        result = (*_listenerDoppler)->SetVelocityCartesian(_listenerDoppler, &v);
-        if (result != SL_RESULT_SUCCESS)
-        {
-            WARN("AudioController: Unable to set listener velocity.");
-        }
 #endif
     }
 }

+ 2 - 1
gameplay/src/AudioController.h

@@ -65,7 +65,8 @@ private:
     SL3DDopplerItf _listenerDoppler;
     SL3DLocationItf _listenerLocation;
 #endif
-    static std::list<AudioSource*> _playingSources;     // List of currently running sources.
+    std::set<AudioSource*> _playingSources;
+    AudioSource* _pausingSource;
 };
 
 }

+ 25 - 1
gameplay/src/AudioSource.cpp

@@ -274,6 +274,11 @@ void AudioSource::play()
         }
     }
 #endif
+
+    // Add the source to the controller's list of currently playing sources.
+    AudioController* audioController = Game::getInstance()->getAudioController();
+    if (audioController->_playingSources.find(this) == audioController->_playingSources.end())
+        audioController->_playingSources.insert(this);
 }
 
 void AudioSource::pause()
@@ -290,6 +295,19 @@ void AudioSource::pause()
         }
     }
 #endif
+
+    // Remove the source from the controller's set of currently playing sources
+    // if the source is being paused by the user and not the controller itself.
+    AudioController* audioController = Game::getInstance()->getAudioController();
+    if (audioController->_pausingSource != this)
+    {
+        std::set<AudioSource*>::iterator iter = audioController->_playingSources.find(this);
+        if (iter != audioController->_playingSources.end())
+        {
+            WARN("\n\nRemoving an audio source from the list of playing sources...\n\n\n");
+            audioController->_playingSources.erase(iter);
+        }
+    }
 }
 
 void AudioSource::resume()
@@ -313,7 +331,13 @@ void AudioSource::stop()
             WARN("AudioSource::stop() failed to set player state.");
         }
     }
-#endif 
+#endif
+
+    // Remove the source from the controller's set of currently playing sources.
+    AudioController* audioController = Game::getInstance()->getAudioController();
+    std::set<AudioSource*>::iterator iter = audioController->_playingSources.find(this);
+    if (iter != audioController->_playingSources.end())
+        audioController->_playingSources.erase(iter);
 }
 
 void AudioSource::rewind()

+ 9 - 6
gameplay/src/FileSystem.cpp

@@ -162,13 +162,16 @@ FILE* FileSystem::openFile(const char* path, const char* mode)
     if (stat(fullPath.c_str(), &s) != 0)
     {
         AAsset* asset = AAssetManager_open(__assetManager, path, AASSET_MODE_RANDOM);
-        const void* data = AAsset_getBuffer(asset);
-        int length = AAsset_getLength(asset);
-        FILE* file = fopen(fullPath.c_str(), "wb");
+        if (asset)
+        {
+            const void* data = AAsset_getBuffer(asset);
+            int length = AAsset_getLength(asset);
+            FILE* file = fopen(fullPath.c_str(), "wb");
         
-        int ret = fwrite(data, sizeof(unsigned char), length, file);
-        assert(ret == length);
-        fclose(file);
+            int ret = fwrite(data, sizeof(unsigned char), length, file);
+            assert(ret == length);
+            fclose(file);
+        }
     }
 #endif
     

+ 133 - 107
gameplay/src/PlatformAndroid.cpp

@@ -13,38 +13,32 @@
 #include <android/log.h>
 #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
 
-#define TOUCH_COUNT_MAX     4
-
-using namespace std;
-
+// Externally referenced global variables.
 struct android_app* __state;
 AAssetManager* __assetManager;
-std::string __assetsPath;
-bool __initialized = false;
-bool __destroyed = false;
 
+static bool __initialized;
+static bool __suspended;
 static EGLDisplay __eglDisplay = EGL_NO_DISPLAY;
 static EGLContext __eglContext = EGL_NO_CONTEXT;
 static EGLSurface __eglSurface = EGL_NO_SURFACE;
 static EGLConfig __eglConfig = 0;
-int __width;
-int __height;
-
-struct timespec __timespec;
+static int __width;
+static int __height;
+static struct timespec __timespec;
 static long __timeStart;
 static long __timeAbsolute;
 static bool __vsync = WINDOW_VSYNC;
-
-ASensorManager* __sensorManager;
-ASensorEventQueue* __sensorEventQueue;
-ASensorEvent __sensorEvent;
-const ASensor* __accelerometerSensor;
-
-static int __orientationAngle = 90; // Landscape by default.
+static ASensorManager* __sensorManager;
+static ASensorEventQueue* __sensorEventQueue;
+static ASensorEvent __sensorEvent;
+static const ASensor* __accelerometerSensor;
+static int __orientationAngle = 90;
 static bool __multiTouch = false;
 static int __primaryTouchId = -1;
-bool __displayKeyboard = false;
+static bool __displayKeyboard = false;
 
+// OpenGL VAO functions.
 static const char* __glExtensions;
 PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL;
 PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL;
@@ -54,7 +48,7 @@ PFNGLISVERTEXARRAYOESPROC glIsVertexArray = NULL;
 namespace gameplay
 {
 
-long timespec2millis(struct timespec *a)
+static long timespec2millis(struct timespec *a)
 {
     return a->tv_sec*1000 + a->tv_nsec/1000000;
 }
@@ -67,7 +61,7 @@ extern void printError(const char* format, ...)
     va_end(argptr);
 }
 
-EGLenum checkErrorEGL(const char* msg)
+static EGLenum checkErrorEGL(const char* msg)
 {
     static const char* errmsg[] =
     {
@@ -93,7 +87,7 @@ EGLenum checkErrorEGL(const char* msg)
 }
 
 // Initialized EGL resources.
-bool initEGL()
+static bool initEGL()
 {
     // Hard-coded to 32-bit/OpenGL ES 2.0.
     const EGLint eglConfigAttrs[] =
@@ -122,31 +116,34 @@ bool initEGL()
         EGL_NONE
     };
 
-    // Get the EGL display and initialize.
-    __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (__eglDisplay == EGL_NO_DISPLAY)
+    if (__eglDisplay == EGL_NO_DISPLAY && __eglContext == EGL_NO_CONTEXT)
     {
-        checkErrorEGL("eglGetDisplay");
-        goto error;
-    }
+        // Get the EGL display and initialize.
+        __eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        if (__eglDisplay == EGL_NO_DISPLAY)
+        {
+            checkErrorEGL("eglGetDisplay");
+            goto error;
+        }
     
-    if (eglInitialize(__eglDisplay, NULL, NULL) != EGL_TRUE)
-    {
-        checkErrorEGL("eglInitialize");
-        goto error;
-    }
+        if (eglInitialize(__eglDisplay, NULL, NULL) != EGL_TRUE)
+        {
+            checkErrorEGL("eglInitialize");
+            goto error;
+        }
     
-    if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
-    {
-        checkErrorEGL("eglChooseConfig");
-        goto error;
-    }
+        if (eglChooseConfig(__eglDisplay, eglConfigAttrs, &__eglConfig, 1, &eglConfigCount) != EGL_TRUE || eglConfigCount == 0)
+        {
+            checkErrorEGL("eglChooseConfig");
+            goto error;
+        }
     
-    __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
-    if (__eglContext == EGL_NO_CONTEXT)
-    {
-        checkErrorEGL("eglCreateContext");
-        goto error;
+        __eglContext = eglCreateContext(__eglDisplay, __eglConfig, EGL_NO_CONTEXT, eglContextAttrs);
+        if (__eglContext == EGL_NO_CONTEXT)
+        {
+            checkErrorEGL("eglCreateContext");
+            goto error;
+        }
     }
     
     // EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
@@ -191,12 +188,42 @@ bool initEGL()
     return true;
     
 error:
-
     return false;
 }
 
+static void destroyEGLSurface()
+{
+    if (__eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglMakeCurrent(__eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    }
+
+    if (__eglSurface != EGL_NO_SURFACE)
+    {
+        eglDestroySurface(__eglDisplay, __eglSurface);
+        __eglSurface = EGL_NO_SURFACE;
+    }
+}
+
+static void destroyEGLMain()
+{
+    destroyEGLSurface();
+
+    if (__eglContext != EGL_NO_CONTEXT)
+    {
+        eglDestroyContext(__eglDisplay, __eglContext);
+        __eglContext = EGL_NO_CONTEXT;
+    }
+
+    if (__eglDisplay != EGL_NO_DISPLAY)
+    {
+        eglTerminate(__eglDisplay);
+        __eglDisplay = EGL_NO_DISPLAY;
+    }
+}
+
 // Display the android virtual keyboard.
-void displayKeyboard(android_app* state, bool show)
+static void displayKeyboard(android_app* state, bool show)
 { 
     // The following functions is supposed to show / hide functins from a native activity.. but currently do not work. 
     // ANativeActivity_showSoftInput(state->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT);
@@ -256,7 +283,7 @@ void displayKeyboard(android_app* state, bool show)
 }
 
 // Gets the Keyboard::Key enumeration constant that corresponds to the given Android key code.
-Keyboard::Key getKey(int keycode, int metastate)
+static Keyboard::Key getKey(int keycode, int metastate)
 {
     bool shiftOn = (metastate == AMETA_SHIFT_ON);
     
@@ -604,7 +631,7 @@ static int32_t engine_handle_input(struct android_app* app, AInputEvent* event)
 }
 
 // Process the next main command.
-static void engine_handle_cmd(struct android_app* app, int32_t cmd) 
+static void engine_handle_cmd(struct android_app* app, int32_t cmd)
 {
     switch (cmd) 
     {
@@ -612,23 +639,47 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             // The window is being shown, get it ready.
             if (app->window != NULL)
             {
+                initEGL();
                 __initialized = true;
             }
             break;
         case APP_CMD_TERM_WINDOW:
-            {
-                __destroyed = true;
-                break;
-            }
+            destroyEGLSurface();
+            __initialized = false;
+            break;
+        case APP_CMD_DESTROY:
+            Game::getInstance()->exit();
+            destroyEGLMain();
+            __initialized = false;
+            break;
         case APP_CMD_GAINED_FOCUS:
             // When our app gains focus, we start monitoring the accelerometer.
             if (__accelerometerSensor != NULL) 
             {
                 ASensorEventQueue_enableSensor(__sensorEventQueue, __accelerometerSensor);
-                // We'd like to get 60 events per second (in us).
+                // We'd like to get 60 events per second (in microseconds).
                 ASensorEventQueue_setEventRate(__sensorEventQueue, __accelerometerSensor, (1000L/60)*1000);
             }
-            Game::getInstance()->resume();
+
+            if (Game::getInstance()->getState() == Game::UNINITIALIZED)
+            {
+                Game::getInstance()->run(__width, __height);
+            }
+            else
+            {
+                Game::getInstance()->resume();
+            }
+            break;
+        case APP_CMD_RESUME:
+            if (__initialized)
+            {
+                Game::getInstance()->resume();
+            }
+            __suspended = false;
+            break;
+        case APP_CMD_PAUSE:
+            Game::getInstance()->pause();
+            __suspended = true;
             break;
         case APP_CMD_LOST_FOCUS:
             // When our app loses focus, we stop monitoring the accelerometer.
@@ -637,7 +688,6 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd)
             {
                 ASensorEventQueue_disableSensor(__sensorEventQueue, __accelerometerSensor);
             }
-            Game::getInstance()->pause();
             break;
     }
 }
@@ -654,28 +704,6 @@ Platform::Platform(const Platform& copy)
 
 Platform::~Platform()
 {
-    if (__eglDisplay != EGL_NO_DISPLAY)
-    {
-        eglMakeCurrent(__eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    }
-
-    if (__eglSurface != EGL_NO_SURFACE)
-    {
-        eglDestroySurface(__eglDisplay, __eglSurface);
-        __eglSurface = EGL_NO_SURFACE;
-    }
-
-    if (__eglContext != EGL_NO_CONTEXT)
-    {
-        eglDestroyContext(__eglDisplay, __eglContext);
-        __eglContext = EGL_NO_CONTEXT;
-    }
-
-    if (__eglDisplay != EGL_NO_DISPLAY)
-    {
-        eglTerminate(__eglDisplay);
-        __eglDisplay = EGL_NO_DISPLAY;
-    }
 }
 
 Platform* Platform::create(Game* game)
@@ -687,6 +715,9 @@ Platform* Platform::create(Game* game)
 
 int Platform::enterMessagePump()
 {
+    __initialized = false;
+    __suspended = false;
+
     // Get the android application's activity.
     ANativeActivity* activity = __state->activity;
     JavaVM* jvm = __state->activity->vm;
@@ -702,12 +733,13 @@ int Platform::enterMessagePump()
     const char* packageName;
     jboolean isCopy;
     packageName = env->GetStringUTFChars((jstring)result, &isCopy);
+    jvm->DetachCurrentThread();
     
     // Set the default path to store the resources.
-    __assetsPath = "/mnt/sdcard/android/data/";
-    __assetsPath += packageName;
-    __assetsPath += "/";
-    FileSystem::setResourcePath(__assetsPath.c_str());    
+    std::string assetsPath = "/mnt/sdcard/android/data/";
+    assetsPath += packageName;
+    assetsPath += "/";
+    FileSystem::setResourcePath(assetsPath.c_str());    
         
     // Get the asset manager to get the resources from the .apk file.
     __assetManager = __state->activity->assetManager; 
@@ -726,8 +758,6 @@ int Platform::enterMessagePump()
     __timeStart = timespec2millis(&__timespec);
     __timeAbsolute = 0L;
     
-    bool initializeGame = true;
-    
     while (true)
     {
         // Read all pending events.
@@ -735,12 +765,10 @@ int Platform::enterMessagePump()
         int events;
         struct android_poll_source* source;
         
-        bool _shouldPoll = !(__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED) && (Game::getInstance()->getState() != Game::PAUSED);
-        
-        while ((ident=ALooper_pollAll( _shouldPoll ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
+        while ((ident=ALooper_pollAll(!__suspended ? 0 : -1, NULL, &events, (void**)&source)) >= 0) 
         {
             // Process this event.
-            if (source != NULL) 
+            if (source != NULL)
                 source->process(__state, source);
             
             // If a sensor has data, process it now.
@@ -748,20 +776,14 @@ int Platform::enterMessagePump()
                 ASensorEventQueue_getEvents(__sensorEventQueue, &__sensorEvent, 1);
             
             if (__state->destroyRequested != 0)
-                break;
-        }
-        
-        if (__initialized && initializeGame)
-        {
-            gameplay::initEGL();
-            WARN_VARG("Platform::enterMessagePump() - width: %d  height: %d assetsPath: %s", __width, __height, __assetsPath.c_str());
-            _game->run(__width, __height);
-            initializeGame = false;
+            {
+                return 0;
+            }
         }
         
         // Idle time (no events left to process) is spent rendering.
         // We skip rendering when the app is paused.
-        if (__initialized && _game->getState() != Game::PAUSED)
+        if (__initialized && !__suspended)
         {
             _game->frame();
 
@@ -781,23 +803,27 @@ int Platform::enterMessagePump()
             int rc = eglSwapBuffers(__eglDisplay, __eglSurface);
             if (rc != EGL_TRUE)
             {
-                perror("eglSwapBuffers");
-                _game->exit();
-                break;
+                EGLint error = eglGetError();
+                if (error == EGL_BAD_NATIVE_WINDOW)
+                {
+                    if (__state->window != NULL)
+                    {
+                        destroyEGLSurface();
+                        initEGL();
+                    }
+                    __initialized = true;
+                }
+                else
+                {
+                    perror("eglSwapBuffers");
+                    break;
+                }
             }
         }
-        
-        // Check if we are exiting.
-        if ((__state->destroyRequested != 0) || (__initialized && Game::getInstance()->getState() == Game::UNINITIALIZED))
-        {
-            break;
-        }
             
         // Display the keyboard.
         gameplay::displayKeyboard(__state, __displayKeyboard);
     }
-
-    jvm->DetachCurrentThread();
 }
 
 void Platform::signalShutdown() 

+ 2 - 5
gameplay/src/gameplay-main-android.cpp

@@ -18,15 +18,12 @@ void android_main(struct android_app* state)
     
     __state = state;
     Game* game = Game::getInstance();
-    assert(game != NULL);
     Platform* platform = Platform::create(game);
-    assert(platform != NULL);
     platform->enterMessagePump();
-    Game::getInstance()->exit();
     delete platform;
     
-    // Android specific : the process needs to exit to 
-    // to trigger cleanup of global resources (such as game).
+    // Android specific : the process needs to exit to trigger
+    // cleanup of global and static resources (such as the game).
     exit(0);
 }