Atlas - SDL_androidevents.c
Home / ext / SDL / src / video / android Lines: 1 | Size: 7889 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_DRIVER_ANDROID 24 25#include "SDL_androidevents.h" 26#include "SDL_androidkeyboard.h" 27#include "SDL_androidwindow.h" 28#include "../SDL_sysvideo.h" 29#include "../../events/SDL_events_c.h" 30 31#include "../../audio/aaudio/SDL_aaudio.h" 32#include "../../audio/openslES/SDL_openslES.h" 33 34 35#ifdef SDL_VIDEO_OPENGL_EGL 36static void android_egl_context_restore(SDL_Window *window) 37{ 38 if (window) { 39 SDL_WindowData *data = window->internal; 40 SDL_GL_MakeCurrent(window, NULL); 41 if (!SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context)) { 42 // The context is no longer valid, create a new one 43 data->egl_context = (EGLContext)SDL_GL_CreateContext(window); 44 SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context); 45 SDL_Event event; 46 SDL_zero(event); 47 event.type = SDL_EVENT_RENDER_DEVICE_RESET; 48 event.render.windowID = SDL_GetWindowID(window); 49 SDL_PushEvent(&event); 50 } 51 data->backup_done = false; 52 53 SDL_GL_SetSwapInterval(data->swap_interval); 54 } 55} 56 57static void android_egl_context_backup(SDL_Window *window) 58{ 59 if (window) { 60 int interval = 0; 61 // Keep a copy of the EGL Context so we can try to restore it when we resume 62 SDL_WindowData *data = window->internal; 63 data->egl_context = SDL_GL_GetCurrentContext(); 64 65 // Save/Restore the swap interval / vsync 66 if (SDL_GL_GetSwapInterval(&interval)) { 67 data->has_swap_interval = 1; 68 data->swap_interval = interval; 69 } 70 71 // We need to do this so the EGLSurface can be freed 72 SDL_GL_MakeCurrent(window, NULL); 73 data->backup_done = true; 74 } 75} 76#endif 77 78/* 79 * Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume 80 */ 81static bool Android_EventsInitialized; 82static bool Android_BlockOnPause = true; 83static bool Android_Paused; 84static bool Android_PausedAudio; 85static bool Android_Destroyed; 86 87void Android_InitEvents(void) 88{ 89 if (!Android_EventsInitialized) { 90 Android_BlockOnPause = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, true); 91 Android_Paused = false; 92 Android_Destroyed = false; 93 Android_EventsInitialized = true; 94 } 95} 96 97static void Android_PauseAudio(void) 98{ 99 OPENSLES_PauseDevices(); 100 AAUDIO_PauseDevices(); 101 Android_PausedAudio = true; 102} 103 104static void Android_ResumeAudio(void) 105{ 106 if (Android_PausedAudio) { 107 OPENSLES_ResumeDevices(); 108 AAUDIO_ResumeDevices(); 109 Android_PausedAudio = false; 110 } 111} 112 113static void Android_OnPause(void) 114{ 115 SDL_OnApplicationWillEnterBackground(); 116 SDL_OnApplicationDidEnterBackground(); 117 118 /* The semantics are that as soon as the enter background event 119 * has been queued, the app will block. The application should 120 * do any life cycle handling in an event filter while the event 121 * was being queued. 122 */ 123#ifdef SDL_VIDEO_OPENGL_EGL 124 if (Android_Window && !Android_Window->external_graphics_context) { 125 Android_LockActivityMutex(); 126 android_egl_context_backup(Android_Window); 127 Android_UnlockActivityMutex(); 128 } 129#endif 130 131 if (Android_BlockOnPause) { 132 // We're blocking, also pause audio 133 Android_PauseAudio(); 134 } 135 136 Android_Paused = true; 137} 138 139static void Android_OnResume(void) 140{ 141 Android_Paused = false; 142 143 SDL_OnApplicationWillEnterForeground(); 144 145 Android_ResumeAudio(); 146 147#ifdef SDL_VIDEO_OPENGL_EGL 148 // Restore the GL Context from here, as this operation is thread dependent 149 if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) { 150 Android_LockActivityMutex(); 151 android_egl_context_restore(Android_Window); 152 Android_UnlockActivityMutex(); 153 } 154#endif 155 156 SDL_OnApplicationDidEnterForeground(); 157} 158 159static void Android_OnLowMemory(void) 160{ 161 SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY); 162} 163 164static void Android_OnDestroy(void) 165{ 166 // Make sure we unblock any audio processing before we quit 167 Android_ResumeAudio(); 168 169 /* Discard previous events. The user should have handled state storage 170 * in SDL_EVENT_WILL_ENTER_BACKGROUND. After nativeSendQuit() is called, no 171 * events other than SDL_EVENT_QUIT and SDL_EVENT_TERMINATING should fire */ 172 SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST); 173 SDL_SendQuit(); 174 SDL_SendAppEvent(SDL_EVENT_TERMINATING); 175 176 Android_Destroyed = true; 177} 178 179static void Android_HandleLifecycleEvent(SDL_AndroidLifecycleEvent event) 180{ 181 switch (event) { 182 case SDL_ANDROID_LIFECYCLE_WAKE: 183 // Nothing to do, just return 184 break; 185 case SDL_ANDROID_LIFECYCLE_PAUSE: 186 Android_OnPause(); 187 break; 188 case SDL_ANDROID_LIFECYCLE_RESUME: 189 Android_OnResume(); 190 break; 191 case SDL_ANDROID_LIFECYCLE_LOWMEMORY: 192 Android_OnLowMemory(); 193 break; 194 case SDL_ANDROID_LIFECYCLE_DESTROY: 195 Android_OnDestroy(); 196 break; 197 default: 198 break; 199 } 200} 201 202static Sint64 GetLifecycleEventTimeout(bool paused, Sint64 timeoutNS) 203{ 204 if (Android_Paused) { 205 if (Android_BlockOnPause) { 206 timeoutNS = -1; 207 } else if (timeoutNS == 0) { 208 timeoutNS = SDL_MS_TO_NS(100); 209 } 210 } 211 return timeoutNS; 212} 213 214void Android_PumpEvents(Sint64 timeoutNS) 215{ 216 SDL_AndroidLifecycleEvent event; 217 bool paused = Android_Paused; 218 219 while (!Android_Destroyed && 220 Android_WaitLifecycleEvent(&event, GetLifecycleEventTimeout(paused, timeoutNS))) { 221 Android_HandleLifecycleEvent(event); 222 223 switch (event) { 224 case SDL_ANDROID_LIFECYCLE_WAKE: 225 // Finish handling events quickly if we're not paused 226 timeoutNS = 0; 227 break; 228 case SDL_ANDROID_LIFECYCLE_PAUSE: 229 // Finish handling events at the current timeout and return to process events one more time before blocking. 230 break; 231 case SDL_ANDROID_LIFECYCLE_RESUME: 232 // Finish handling events at the resume state timeout 233 paused = false; 234 break; 235 default: 236 break; 237 } 238 } 239} 240 241bool Android_WaitActiveAndLockActivity(void) 242{ 243 /* Make sure we have pumped all events so that Android_Paused state is correct */ 244 SDL_AndroidLifecycleEvent event; 245 while (!Android_Destroyed && Android_WaitLifecycleEvent(&event, 0)) { 246 Android_HandleLifecycleEvent(event); 247 } 248 249 while (Android_Paused && !Android_Destroyed) { 250 Android_PumpEvents(-1); 251 } 252 253 if (Android_Destroyed) { 254 SDL_SetError("Android activity has been destroyed"); 255 return false; 256 } 257 258 Android_LockActivityMutex(); 259 return true; 260} 261 262void Android_QuitEvents(void) 263{ 264 Android_EventsInitialized = false; 265} 266 267#endif // SDL_VIDEO_DRIVER_ANDROID 268[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.