Imported Upstream version 2.0.14
[platform/upstream/SDL.git] / src / video / android / SDL_androidevents.c
old mode 100755 (executable)
new mode 100644 (file)
index 6cf9af2..dfd6212
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
 
 #if SDL_VIDEO_DRIVER_ANDROID
 
-/* We're going to do this by default */
-#define SDL_ANDROID_BLOCK_ON_PAUSE  1
-
 #include "SDL_androidevents.h"
 #include "SDL_events.h"
+#include "SDL_androidkeyboard.h"
 #include "SDL_androidwindow.h"
+#include "../SDL_sysvideo.h"
+#include "../../events/SDL_events_c.h"
 
-#if !SDL_AUDIO_DISABLED
 /* Can't include sysaudio "../../audio/android/SDL_androidaudio.h"
  * because of THIS redefinition */
+
+#if !SDL_AUDIO_DISABLED && SDL_AUDIO_DRIVER_ANDROID
 extern void ANDROIDAUDIO_ResumeDevices(void);
 extern void ANDROIDAUDIO_PauseDevices(void);
 #else
@@ -39,82 +40,197 @@ static void ANDROIDAUDIO_ResumeDevices(void) {}
 static void ANDROIDAUDIO_PauseDevices(void) {}
 #endif
 
-static void 
-android_egl_context_restore() 
+#if !SDL_AUDIO_DISABLED && SDL_AUDIO_DRIVER_OPENSLES
+extern void openslES_ResumeDevices(void);
+extern void openslES_PauseDevices(void);
+#else
+static void openslES_ResumeDevices(void) {}
+static void openslES_PauseDevices(void) {}
+#endif
+
+/* Number of 'type' events in the event queue */
+static int
+SDL_NumberOfEvents(Uint32 type)
+{
+    return SDL_PeepEvents(NULL, 0, SDL_PEEKEVENT, type, type);
+}
+
+static void
+android_egl_context_restore(SDL_Window *window)
 {
-    SDL_Event event;
-    SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
-    if (SDL_GL_MakeCurrent(Android_Window, (SDL_GLContext) data->egl_context) < 0) {
-        /* The context is no longer valid, create a new one */
-        data->egl_context = (EGLContext) SDL_GL_CreateContext(Android_Window);
-        SDL_GL_MakeCurrent(Android_Window, (SDL_GLContext) data->egl_context);
-        event.type = SDL_RENDER_DEVICE_RESET;
-        SDL_PushEvent(&event);
+    if (window) {
+        SDL_Event event;
+        SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+        if (SDL_GL_MakeCurrent(window, (SDL_GLContext) data->egl_context) < 0) {
+            /* The context is no longer valid, create a new one */
+            data->egl_context = (EGLContext) SDL_GL_CreateContext(window);
+            SDL_GL_MakeCurrent(window, (SDL_GLContext) data->egl_context);
+            event.type = SDL_RENDER_DEVICE_RESET;
+            SDL_PushEvent(&event);
+        }
+        data->backup_done = 0;
     }
 }
 
-static void 
-android_egl_context_backup(
+static void
+android_egl_context_backup(SDL_Window *window)
 {
-    /* Keep a copy of the EGL Context so we can try to restore it when we resume */
-    SDL_WindowData *data = (SDL_WindowData *) Android_Window->driverdata;
-    data->egl_context = SDL_GL_GetCurrentContext();
-    /* We need to do this so the EGLSurface can be freed */
-    SDL_GL_MakeCurrent(Android_Window, NULL);
+    if (window) {
+        /* Keep a copy of the EGL Context so we can try to restore it when we resume */
+        SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+        data->egl_context = SDL_GL_GetCurrentContext();
+        /* We need to do this so the EGLSurface can be freed */
+        SDL_GL_MakeCurrent(window, NULL);
+        data->backup_done = 1;
+    }
 }
 
+
+/*
+ * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
+ * When the pause semaphore is signaled, if Android_PumpEvents_Blocking is used, the event loop will block until the resume signal is emitted.
+ *
+ * No polling necessary
+ */
+
 void
-Android_PumpEvents(_THIS)
+Android_PumpEvents_Blocking(_THIS)
 {
-    static int isPaused = 0;
-#if SDL_ANDROID_BLOCK_ON_PAUSE
-    static int isPausing = 0;
-#endif
-    /* No polling necessary */
+    SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
 
-    /*
-     * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
-     * When the pause semaphore is signaled, if SDL_ANDROID_BLOCK_ON_PAUSE is defined the event loop will block until the resume signal is emitted.
-     */
+    if (videodata->isPaused) {
+        SDL_bool isContextExternal = SDL_IsVideoContextExternal();
 
-#if SDL_ANDROID_BLOCK_ON_PAUSE
-    if (isPaused && !isPausing) {
         /* Make sure this is the last thing we do before pausing */
-        android_egl_context_backup();
+        if (!isContextExternal) {
+            SDL_LockMutex(Android_ActivityMutex);
+            android_egl_context_backup(Android_Window);
+            SDL_UnlockMutex(Android_ActivityMutex);
+        }
+
         ANDROIDAUDIO_PauseDevices();
-        if(SDL_SemWait(Android_ResumeSem) == 0) {
-#else
-    if (isPaused) {
-        if(SDL_SemTryWait(Android_ResumeSem) == 0) {
-#endif
-            isPaused = 0;
+        openslES_PauseDevices();
+
+        if (SDL_SemWait(Android_ResumeSem) == 0) {
+
+            videodata->isPaused = 0;
+
+            /* Android_ResumeSem was signaled */
+            SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
+            SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
+            SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
+
             ANDROIDAUDIO_ResumeDevices();
+            openslES_ResumeDevices();
+
             /* Restore the GL Context from here, as this operation is thread dependent */
-            if (!SDL_HasEvent(SDL_QUIT)) {
-                android_egl_context_restore();
+            if (!isContextExternal && !SDL_HasEvent(SDL_QUIT)) {
+                SDL_LockMutex(Android_ActivityMutex);
+                android_egl_context_restore(Android_Window);
+                SDL_UnlockMutex(Android_ActivityMutex);
+            }
+
+            /* Make sure SW Keyboard is restored when an app becomes foreground */
+            if (SDL_IsTextInputActive()) {
+                Android_StartTextInput(_this); /* Only showTextInput */
+            }
+        }
+    } else {
+        if (videodata->isPausing || SDL_SemTryWait(Android_PauseSem) == 0) {
+
+            /* Android_PauseSem was signaled */
+            if (videodata->isPausing == 0) {
+                SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+                SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
+                SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
+            }
+
+            /* We've been signaled to pause (potentially several times), but before we block ourselves,
+             * we need to make sure that the very last event (of the first pause sequence, if several)
+             * has reached the app */
+            if (SDL_NumberOfEvents(SDL_APP_DIDENTERBACKGROUND) > SDL_SemValue(Android_PauseSem)) {
+                videodata->isPausing = 1;
+            } else {
+                videodata->isPausing = 0;
+                videodata->isPaused = 1;
             }
         }
     }
-    else {
-#if SDL_ANDROID_BLOCK_ON_PAUSE
-        if( isPausing || SDL_SemTryWait(Android_PauseSem) == 0 ) {
-            /* We've been signaled to pause, but before we block ourselves, 
-            we need to make sure that certain key events have reached the app */
-            if (SDL_HasEvent(SDL_WINDOWEVENT) || SDL_HasEvent(SDL_APP_WILLENTERBACKGROUND) || SDL_HasEvent(SDL_APP_DIDENTERBACKGROUND) ) {
-                isPausing = 1;
+}
+
+void
+Android_PumpEvents_NonBlocking(_THIS)
+{
+    SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
+    static int backup_context = 0;
+
+    if (videodata->isPaused) {
+
+        SDL_bool isContextExternal = SDL_IsVideoContextExternal();
+        if (backup_context) {
+
+            if (!isContextExternal) {
+                SDL_LockMutex(Android_ActivityMutex);
+                android_egl_context_backup(Android_Window);
+                SDL_UnlockMutex(Android_ActivityMutex);
             }
-            else {
-                isPausing = 0;
-                isPaused = 1;
+
+            if (videodata->pauseAudio) {
+                ANDROIDAUDIO_PauseDevices();
+                openslES_PauseDevices();
             }
+
+            backup_context = 0;
         }
-#else
-        if(SDL_SemTryWait(Android_PauseSem) == 0) {
-            android_egl_context_backup();
-            ANDROIDAUDIO_PauseDevices();
-            isPaused = 1;
+
+
+        if (SDL_SemTryWait(Android_ResumeSem) == 0) {
+
+            videodata->isPaused = 0;
+
+            /* Android_ResumeSem was signaled */
+            SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
+            SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
+            SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_RESTORED, 0, 0);
+
+            if (videodata->pauseAudio) {
+                ANDROIDAUDIO_ResumeDevices();
+                openslES_ResumeDevices();
+            }
+
+            /* Restore the GL Context from here, as this operation is thread dependent */
+            if (!isContextExternal && !SDL_HasEvent(SDL_QUIT)) {
+                SDL_LockMutex(Android_ActivityMutex);
+                android_egl_context_restore(Android_Window);
+                SDL_UnlockMutex(Android_ActivityMutex);
+            }
+
+            /* Make sure SW Keyboard is restored when an app becomes foreground */
+            if (SDL_IsTextInputActive()) {
+                Android_StartTextInput(_this); /* Only showTextInput */
+            }
+        }
+    } else {
+        if (videodata->isPausing || SDL_SemTryWait(Android_PauseSem) == 0) {
+
+            /* Android_PauseSem was signaled */
+            if (videodata->isPausing == 0) {
+                SDL_SendWindowEvent(Android_Window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+                SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
+                SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
+            }
+
+            /* We've been signaled to pause (potentially several times), but before we block ourselves,
+             * we need to make sure that the very last event (of the first pause sequence, if several)
+             * has reached the app */
+            if (SDL_NumberOfEvents(SDL_APP_DIDENTERBACKGROUND) > SDL_SemValue(Android_PauseSem)) {
+                videodata->isPausing = 1;
+            } else {
+                videodata->isPausing = 0;
+                videodata->isPaused = 1;
+                backup_context = 1;
+            }
         }
-#endif
     }
 }