Fixes Bug 1896 - Android app is running while the screen is locked
authorGabriel Jacobo <gabomdq@gmail.com>
Sat, 06 Jul 2013 15:22:49 -0300
changeset 73581aadd7170248
parent 7357 9bd0b241c941
child 7359 96ac247b672e
Fixes Bug 1896 - Android app is running while the screen is locked
Original patch by ny00@outlook.com
android-project/src/org/libsdl/app/SDLActivity.java
     1.1 --- a/android-project/src/org/libsdl/app/SDLActivity.java	Sat Jul 06 16:05:09 2013 +0200
     1.2 +++ b/android-project/src/org/libsdl/app/SDLActivity.java	Sat Jul 06 15:22:49 2013 -0300
     1.3 @@ -28,7 +28,7 @@
     1.4      private static final String TAG = "SDL";
     1.5  
     1.6      // Keep track of the paused state
     1.7 -    public static boolean mIsPaused = false;
     1.8 +    public static boolean mIsPaused = false, mIsSurfaceReady = false;
     1.9  
    1.10      // Main components
    1.11      protected static SDLActivity mSingleton;
    1.12 @@ -70,6 +70,7 @@
    1.13          mSingleton = this;
    1.14  
    1.15          // Set up the surface
    1.16 +        mEGLSurface = EGL10.EGL_NO_SURFACE;
    1.17          mSurface = new SDLSurface(getApplication());
    1.18  
    1.19          mLayout = new AbsoluteLayout(this);
    1.20 @@ -83,14 +84,14 @@
    1.21      protected void onPause() {
    1.22          Log.v("SDL", "onPause()");
    1.23          super.onPause();
    1.24 -        // Don't call SDLActivity.nativePause(); here, it will be called by SDLSurface::surfaceDestroyed
    1.25 +        SDLActivity.handlePause();
    1.26      }
    1.27  
    1.28      @Override
    1.29      protected void onResume() {
    1.30          Log.v("SDL", "onResume()");
    1.31          super.onResume();
    1.32 -        // Don't call SDLActivity.nativeResume(); here, it will be called via SDLSurface::surfaceChanged->SDLActivity::startApp
    1.33 +        SDLActivity.handleResume();
    1.34      }
    1.35  
    1.36      @Override
    1.37 @@ -120,6 +121,32 @@
    1.38          }
    1.39      }
    1.40  
    1.41 +
    1.42 +    /** Called by onPause or surfaceDestroyed. Even if surfaceDestroyed
    1.43 +     *  is the first to be called, mIsSurfaceReady should still be set
    1.44 +     *  to 'true' during the call to onPause (in a usual scenario).
    1.45 +     */
    1.46 +    public static void handlePause() {
    1.47 +        if (!SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) {
    1.48 +            SDLActivity.mIsPaused = true;
    1.49 +            SDLActivity.nativePause();
    1.50 +            mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false);
    1.51 +        }
    1.52 +    }
    1.53 +
    1.54 +    /** Called by onResume or surfaceCreated. An actual resume should be done only when the surface is ready.
    1.55 +     * Note: Some Android variants may send multiple surfaceChanged events, so we don't need to resume
    1.56 +     * every time we get one of those events, only if it comes after surfaceDestroyed
    1.57 +     */
    1.58 +    public static void handleResume() {
    1.59 +        if (SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) {
    1.60 +            SDLActivity.mIsPaused = false;
    1.61 +            SDLActivity.nativeResume();
    1.62 +            mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
    1.63 +        }
    1.64 +    }
    1.65 +
    1.66 +
    1.67      // Messages from the SDLMain thread
    1.68      static final int COMMAND_CHANGE_TITLE = 1;
    1.69      static final int COMMAND_UNUSED = 2;
    1.70 @@ -227,24 +254,6 @@
    1.71          return mSingleton;
    1.72      }
    1.73  
    1.74 -    public static void startApp() {
    1.75 -        // Start up the C app thread
    1.76 -        if (mSDLThread == null) {
    1.77 -            mSDLThread = new Thread(new SDLMain(), "SDLThread");
    1.78 -            mSDLThread.start();
    1.79 -        }
    1.80 -        else {
    1.81 -            /*
    1.82 -             * Some Android variants may send multiple surfaceChanged events, so we don't need to resume every time
    1.83 -             * every time we get one of those events, only if it comes after surfaceDestroyed
    1.84 -             */
    1.85 -            if (mIsPaused) {
    1.86 -                SDLActivity.nativeResume();
    1.87 -                SDLActivity.mIsPaused = false;
    1.88 -            }
    1.89 -        }
    1.90 -    }
    1.91 -    
    1.92      static class ShowTextInputTask implements Runnable {
    1.93          /*
    1.94           * This is used to regulate the pan&scan method to have some offset from
    1.95 @@ -343,25 +352,30 @@
    1.96              EGL10 egl = (EGL10)EGLContext.getEGL();
    1.97              if (SDLActivity.mEGLContext == null) createEGLContext();
    1.98  
    1.99 -            Log.v("SDL", "Creating new EGL Surface");
   1.100 -            EGLSurface surface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity.mSurface, null);
   1.101 -            if (surface == EGL10.EGL_NO_SURFACE) {
   1.102 -                Log.e("SDL", "Couldn't create surface");
   1.103 -                return false;
   1.104 +            if (SDLActivity.mEGLSurface == EGL10.EGL_NO_SURFACE) {
   1.105 +                Log.v("SDL", "Creating new EGL Surface");
   1.106 +                SDLActivity.mEGLSurface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity.mSurface, null);
   1.107 +                if (SDLActivity.mEGLSurface == EGL10.EGL_NO_SURFACE) {
   1.108 +                    Log.e("SDL", "Couldn't create surface");
   1.109 +                    return false;
   1.110 +                }
   1.111              }
   1.112 +            else Log.v("SDL", "EGL Surface remains valid");
   1.113  
   1.114              if (egl.eglGetCurrentContext() != SDLActivity.mEGLContext) {
   1.115 -                if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
   1.116 +                if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, SDLActivity.mEGLSurface, SDLActivity.mEGLSurface, SDLActivity.mEGLContext)) {
   1.117                      Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
   1.118                      // TODO: Notify the user via a message that the old context could not be restored, and that textures need to be manually restored.
   1.119                      createEGLContext();
   1.120 -                    if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
   1.121 +                    if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, SDLActivity.mEGLSurface, SDLActivity.mEGLSurface, SDLActivity.mEGLContext)) {
   1.122                          Log.e("SDL", "Failed making EGL Context current");
   1.123                          return false;
   1.124                      }
   1.125                  }
   1.126 +                else Log.v("SDL", "EGL Context made current");
   1.127              }
   1.128 -            SDLActivity.mEGLSurface = surface;
   1.129 +            else Log.v("SDL", "EGL Context remains current");
   1.130 +
   1.131              return true;
   1.132          } else {
   1.133              Log.e("SDL", "Surface creation failed, display = " + SDLActivity.mEGLDisplay + ", config = " + SDLActivity.mEGLConfig);
   1.134 @@ -533,18 +547,27 @@
   1.135      public void surfaceCreated(SurfaceHolder holder) {
   1.136          Log.v("SDL", "surfaceCreated()");
   1.137          holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
   1.138 -        enableSensor(Sensor.TYPE_ACCELEROMETER, true);
   1.139 +        // Set mIsSurfaceReady to 'true' *before* any call to handleResume
   1.140 +        SDLActivity.mIsSurfaceReady = true;
   1.141      }
   1.142  
   1.143      // Called when we lose the surface
   1.144      @Override
   1.145      public void surfaceDestroyed(SurfaceHolder holder) {
   1.146          Log.v("SDL", "surfaceDestroyed()");
   1.147 -        if (!SDLActivity.mIsPaused) {
   1.148 -            SDLActivity.mIsPaused = true;
   1.149 -            SDLActivity.nativePause();
   1.150 -        }
   1.151 -        enableSensor(Sensor.TYPE_ACCELEROMETER, false);
   1.152 +        // Call this *before* setting mIsSurfaceReady to 'false'
   1.153 +        SDLActivity.handlePause();
   1.154 +        SDLActivity.mIsSurfaceReady = false;
   1.155 +
   1.156 +        /* We have to clear the current context and destroy the egl surface here
   1.157 +         * Otherwise there's BAD_NATIVE_WINDOW errors coming from eglCreateWindowSurface on resume
   1.158 +         * Ref: http://stackoverflow.com/questions/8762589/eglcreatewindowsurface-on-ics-and-switching-from-2d-to-3d
   1.159 +         */
   1.160 +        
   1.161 +        EGL10 egl = (EGL10)EGLContext.getEGL();
   1.162 +        egl.eglMakeCurrent(SDLActivity.mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
   1.163 +        egl.eglDestroySurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLSurface);
   1.164 +        SDLActivity.mEGLSurface = EGL10.EGL_NO_SURFACE;
   1.165      }
   1.166  
   1.167      // Called when the surface is resized
   1.168 @@ -603,7 +626,22 @@
   1.169          SDLActivity.onNativeResize(width, height, sdlFormat);
   1.170          Log.v("SDL", "Window size:" + width + "x"+height);
   1.171  
   1.172 -        SDLActivity.startApp();
   1.173 +        // Set mIsSurfaceReady to 'true' *before* making a call to handleResume
   1.174 +        SDLActivity.mIsSurfaceReady = true;
   1.175 +
   1.176 +        if (SDLActivity.mSDLThread == null) {
   1.177 +            // This is the entry point to the C app.
   1.178 +            // Start up the C app thread and enable sensor input for the first time
   1.179 +
   1.180 +            SDLActivity.mSDLThread = new Thread(new SDLMain(), "SDLThread");
   1.181 +            enableSensor(Sensor.TYPE_ACCELEROMETER, true);
   1.182 +            SDLActivity.mSDLThread.start();
   1.183 +        } else {
   1.184 +            // The app already exists, we resume via handleResume
   1.185 +            // Multiple sequential calls to surfaceChanged are handled internally by handleResume
   1.186 +
   1.187 +            SDLActivity.handleResume();
   1.188 +        }
   1.189      }
   1.190  
   1.191      // unused