SDL_androidevents.c 7.9 KB

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