From e91c37f4dd1933c44acc3d5eb4b58ae1420fbe85 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 30 Dec 2024 12:23:00 -0800 Subject: [PATCH] Added support for inset handling on Android 15 --- android-project/app/build.gradle | 4 +-- .../main/java/org/libsdl/app/SDLActivity.java | 4 +++ docs/README-android.md | 35 ++++++++++--------- src/core/android/SDL_android.c | 4 +-- src/video/android/SDL_androidvideo.c | 16 +++++++++ src/video/android/SDL_androidvideo.h | 5 +++ src/video/android/SDL_androidwindow.c | 2 ++ 7 files changed, 48 insertions(+), 22 deletions(-) diff --git a/android-project/app/build.gradle b/android-project/app/build.gradle index 514e594a4c..a95bb8aff5 100644 --- a/android-project/app/build.gradle +++ b/android-project/app/build.gradle @@ -6,10 +6,10 @@ def buildWithCMake = project.hasProperty('BUILD_WITH_CMAKE'); android { namespace "org.libsdl.app" - compileSdkVersion 34 + compileSdkVersion 35 defaultConfig { minSdkVersion 19 - targetSdkVersion 34 + targetSdkVersion 35 versionCode 1 versionName "1.0" externalNativeBuild { diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 6067fa74dc..7458b22d7e 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -928,6 +928,10 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) { window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; } + if (Build.VERSION.SDK_INT >= 30 /* Android 11 (R) */ && + Build.VERSION.SDK_INT < 35 /* Android 15 */) { + SDLActivity.onNativeInsetsChanged(0, 0, 0, 0); + } } } else { Log.e(TAG, "error handling message, getContext() returned no Activity"); diff --git a/docs/README-android.md b/docs/README-android.md index 722a886b1e..606eba6152 100644 --- a/docs/README-android.md +++ b/docs/README-android.md @@ -10,7 +10,7 @@ The rest of this README covers the Android gradle style build process. Requirements ================================================================================ -Android SDK (version 34 or later) +Android SDK (version 35 or later) https://developer.android.com/sdk/index.html Android NDK r15c or later @@ -316,6 +316,17 @@ You can control activity re-creation (eg. onCreate()) behaviour. This allows you to choose whether to keep or re-initialize java and native static datas, see SDL_HINT_ANDROID_ALLOW_RECREATE_ACTIVITY in SDL_hints.h. + +Insets and Safe Areas +================================================================================ + +As of Android 15, SDL windows cover the entire screen, extending under notches +and system bars. The OS expects you to take those into account when displaying +content and SDL provides the function SDL_GetWindowSafeArea() so you know what +area is available for interaction. Outside of the safe area can be potentially +covered by system bars or used by OS gestures. + + Mouse / Touch events ================================================================================ @@ -325,6 +336,7 @@ To enable/disable this behavior, see SDL_hints.h: - SDL_HINT_TOUCH_MOUSE_EVENTS - SDL_HINT_MOUSE_TOUCH_EVENTS + Misc ================================================================================ @@ -334,6 +346,7 @@ before creating a window: SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + Threads and the Java VM ================================================================================ @@ -359,6 +372,7 @@ in your native thread. see: https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class + Using STL ================================================================================ @@ -526,15 +540,6 @@ The Tegra Graphics Debugger is available from NVidia here: https://developer.nvidia.com/tegra-graphics-debugger -Why is API level 19 the minimum required? -================================================================================ - -The latest NDK toolchain doesn't support targeting earlier than API level 19. -As of this writing, according to https://www.composables.com/tools/distribution-chart -about 99.7% of the Android devices accessing Google Play support API level 19 or -higher (August 2023). - - A note regarding the use of the "dirty rectangles" rendering technique ================================================================================ @@ -545,12 +550,6 @@ This is caused by SDL's use of EGL as the support system to handle OpenGL ES/ES2 contexts, in particular the use of the eglSwapBuffers function. As stated in the documentation for the function "The contents of ancillary buffers are always undefined after calling eglSwapBuffers". -Setting the EGL_SWAP_BEHAVIOR attribute of the surface to EGL_BUFFER_PRESERVED -is not possible for SDL as it requires EGL 1.4, available only on the API level -17+, so the only workaround available on this platform is to redraw the entire -screen each frame. - -Reference: http://www.khronos.org/registry/egl/specs/EGLTechNote0001.html Ending your application @@ -570,12 +569,14 @@ Don't call exit() as it stops the activity badly. NB: "Back button" can be handled as a SDL_EVENT_KEY_DOWN/UP events, with Keycode SDLK_AC_BACK, for any purpose. + Known issues ================================================================================ - The number of buttons reported for each joystick is hardcoded to be 36, which is the current maximum number of buttons Android can report. + Building the SDL tests ================================================================================ @@ -651,4 +652,4 @@ There is also a convenience target which will build, install and start a test: cmake --build . --target build-install-start-testsprite ``` -Not all tests provide a GUI. For those, you can use `adb logcat` to read the output of stdout. +Not all tests provide a GUI. For those, you can use `adb logcat` to read the output. diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 2835ad3e21..419d4c29f1 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -1077,9 +1077,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeInsetsChanged)( { SDL_LockMutex(Android_ActivityMutex); - if (Android_Window) { - SDL_SetWindowSafeAreaInsets(Android_Window, left, right, top, bottom); - } + Android_SetWindowSafeAreaInsets(left, right, top, bottom); SDL_UnlockMutex(Android_ActivityMutex); } diff --git a/src/video/android/SDL_androidvideo.c b/src/video/android/SDL_androidvideo.c index ee8d889394..ab360a11c4 100644 --- a/src/video/android/SDL_androidvideo.c +++ b/src/video/android/SDL_androidvideo.c @@ -63,6 +63,10 @@ static int Android_DeviceHeight = 0; static Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_RGB565; // Default SurfaceView format, in case this is queried before being filled float Android_ScreenDensity = 1.0f; static float Android_ScreenRate = 0.0f; +int Android_SafeInsetLeft = 0; +int Android_SafeInsetRight = 0; +int Android_SafeInsetTop = 0; +int Android_SafeInsetBottom = 0; static SDL_SystemTheme Android_SystemTheme; static bool Android_SuspendScreenSaver(SDL_VideoDevice *_this) @@ -271,6 +275,18 @@ void Android_SendResize(SDL_Window *window) } } +void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom) +{ + Android_SafeInsetLeft = left; + Android_SafeInsetRight = right; + Android_SafeInsetTop = top; + Android_SafeInsetBottom = bottom; + + if (Android_Window) { + SDL_SetWindowSafeAreaInsets(Android_Window, left, right, top, bottom); + } +} + void Android_SetDarkMode(bool enabled) { SDL_VideoDevice *device = SDL_GetVideoDevice(); diff --git a/src/video/android/SDL_androidvideo.h b/src/video/android/SDL_androidvideo.h index baead920ae..bcc234f5d0 100644 --- a/src/video/android/SDL_androidvideo.h +++ b/src/video/android/SDL_androidvideo.h @@ -29,6 +29,7 @@ extern void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate); extern void Android_SetFormat(int format_wanted, int format_got); extern void Android_SendResize(SDL_Window *window); +extern void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom); extern void Android_SetDarkMode(bool enabled); // Private display data @@ -42,5 +43,9 @@ struct SDL_VideoData extern int Android_SurfaceWidth; extern int Android_SurfaceHeight; extern float Android_ScreenDensity; +extern int Android_SafeInsetLeft; +extern int Android_SafeInsetRight; +extern int Android_SafeInsetTop; +extern int Android_SafeInsetBottom; #endif // SDL_androidvideo_h_ diff --git a/src/video/android/SDL_androidwindow.c b/src/video/android/SDL_androidwindow.c index f2a5757be7..a4ac97c8a6 100644 --- a/src/video/android/SDL_androidwindow.c +++ b/src/video/android/SDL_androidwindow.c @@ -93,6 +93,8 @@ bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Proper SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER, data->egl_surface); #endif + SDL_SetWindowSafeAreaInsets(window, Android_SafeInsetLeft, Android_SafeInsetRight, Android_SafeInsetTop, Android_SafeInsetBottom); + window->internal = data; Android_Window = window;