cmake: create Android jars + apks for tests

pull/7923/head
Anonymous Maarten 2023-03-27 12:03:42 +02:00 committed by Anonymous Maarten
parent 58882425fc
commit a4bb4eef73
30 changed files with 1387 additions and 3 deletions

View File

@ -16,7 +16,7 @@ jobs:
matrix:
platform:
- { name: Android.mk }
- { name: CMake, cmake: 1, android_abi: "arm64-v8a", android_platform: 23, arch: "aarch64", artifact: "SDL-android-arm64" }
- { name: CMake, cmake: 1, android_abi: "arm64-v8a", android_platform: 23, arch: "aarch64", artifact: "SDL-android-arm64", apk-artifact: "SDL-android-apks-arm64" }
steps:
- uses: actions/checkout@v3
@ -28,6 +28,11 @@ jobs:
if: ${{ matrix.platform.name == 'Android.mk' }}
run: |
./build-scripts/androidbuildlibs.sh
- uses: actions/setup-java@v3
if: ${{ matrix.platform.name == 'CMake' }}
with:
distribution: 'temurin'
java-version: '11'
- name: Setup (CMake)
if: ${{ matrix.platform.name == 'CMake' }}
run: |
@ -56,6 +61,10 @@ jobs:
if: ${{ matrix.platform.name == 'CMake' }}
run: |
cmake --build build --config Release --parallel --verbose
- name: Build test apk's (CMake)
if: ${{ matrix.platform.name == 'CMake' }}
run: |
cmake --build build --config Release --parallel --verbose --target testaudiocapture-apk testcontroller-apk testmultiaudio-apk testsprite-apk
- name: Install (CMake)
if: ${{ matrix.platform.name == 'CMake' }}
run: |
@ -88,3 +97,9 @@ jobs:
if-no-files-found: error
name: ${{ matrix.platform.artifact }}
path: build/dist/SDL3*
- uses: actions/upload-artifact@v3
if: ${{ matrix.platform.name == 'CMake' }}
with:
if-no-files-found: error
name: ${{ matrix.platform.apk-artifact }}
path: build/test/*.apk

View File

@ -368,9 +368,11 @@ endforeach()
# Allow some projects to be built conditionally.
set_option(SDL_DISABLE_INSTALL "Disable installation of SDL3" ${SDL3_SUBPROJECT})
cmake_dependent_option(SDL_DISABLE_INSTALL_CPACK "Create binary SDL3 archive using CPack" ${SDL3_SUBPROJECT} "NOT SDL_DISABLE_INSTALL" ON)
cmake_dependent_option(SDL_DISABLE_INSTALL_MAN "Install man pages for SDL3" ${SDL3_SUBPROJECT} "NOT SDL_DISABLE_INSTALL;NOT SDL_FRAMEWORK" ON)
cmake_dependent_option(SDL_DISABLE_INSTALL_DOCS "Install docs for SDL3" ${SDL3_SUBPROJECT} "NOT SDL_DISABLE_INSTALL;NOT SDL_FRAMEWORK" ON)
set_option(SDL_DISABLE_UNINSTALL "Disable uninstallation of SDL3" OFF)
cmake_dependent_option(SDL_DISABLE_ANDROID_JAR "Disable creation of SDL3.jar" ${SDL3_SUBPROJECT} "ANDROID" ON)
option_string(SDL_ASSERTIONS "Enable internal sanity checks (auto/disabled/release/enabled/paranoid)" "auto")
#set_option(SDL_DEPENDENCY_TRACKING "Use gcc -MMD -MT dependency tracking" ON)
set_option(SDL_ASSEMBLY "Enable assembly routines" ${SDL_ASSEMBLY_DEFAULT})
@ -1310,6 +1312,8 @@ endif()
# Platform-specific options and settings
if(ANDROID)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android")
file(GLOB ANDROID_CORE_SOURCES ${SDL3_SOURCE_DIR}/src/core/android/*.c)
list(APPEND SOURCE_FILES ${ANDROID_CORE_SOURCES} ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
set_property(SOURCE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
@ -1442,6 +1446,50 @@ if(ANDROID)
set(HAVE_CLOCK_GETTIME 1)
endif()
if(NOT SDL_DISABLE_ANDROID_JAR)
find_package(Java)
find_package(SdlAndroidPlatform MODULE)
if(Java_FOUND AND SdlAndroidPlatform_FOUND)
include(UseJava)
set(path_android_jar "${SDL_ANDROID_PLATFORM_ROOT}/android.jar")
set(android_java_sources_root "${SDL3_SOURCE_DIR}/android-project/app/src/main/java")
file(GLOB SDL_JAVA_SOURCES "${android_java_sources_root}/org/libsdl/app/*.java")
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding;utf-8")
add_jar(SDL3-jar
SOURCES ${SDL_JAVA_SOURCES}
INCLUDE_JARS "${path_android_jar}"
OUTPUT_NAME "SDL3"
VERSION "${SDL3_VERSION}"
)
set_property(TARGET SDL3-jar PROPERTY OUTPUT "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}.jar")
set(javasourcesjar "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}-sources.jar")
string(REGEX REPLACE "${android_java_sources_root}/" "" sdl_relative_java_sources "${SDL_JAVA_SOURCES}")
add_custom_command(
OUTPUT "${javasourcesjar}"
COMMAND ${Java_JAR_EXECUTABLE} cf "${javasourcesjar}" ${sdl_relative_java_sources}
WORKING_DIRECTORY "${android_java_sources_root}"
DEPENDS ${SDL_JAVA_SOURCES}
)
add_custom_target(SDL3-javasources ALL DEPENDS "${javasourcesjar}")
if(NOT SDL_DISABLE_INSTALL_DOCS)
set(javadocdir "${SDL3_BINARY_DIR}/docs/javadoc")
set(javadocjar "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}-javadoc.jar")
set(javadoc_index_html "${javadocdir}/index.html")
add_custom_command(
OUTPUT "${javadoc_index_html}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${javadocdir}"
COMMAND ${Java_JAVADOC_EXECUTABLE} -encoding utf8 -d "${javadocdir}"
-classpath "${path_android_jar}"
-author -use -version ${SDL_JAVA_SOURCES}
DEPENDS ${SDL_JAVA_SOURCES} "${path_android_jar}"
)
add_custom_target(SDL3-javadoc ALL DEPENDS "${javadoc_index_html}")
set_property(TARGET SDL3-javadoc PROPERTY OUTPUT_DIR "${javadocdir}")
endif()
endif()
endif()
elseif(EMSCRIPTEN)
# Hide noisy warnings that intend to aid mostly during initial stages of porting a new
# project. Uncomment at will for verbose cross-compiling -I/../ path info.
@ -3695,11 +3743,28 @@ if(NOT SDL_DISABLE_INSTALL)
include(CPack)
endif()
if(NOT SDL_DISABLE_INSTALL_MAN)
if(ANDROID)
set(SDL_INSTALL_JAVADIR "${CMAKE_INSTALL_DATAROOTDIR}/java" CACHE PATH "Path where to install java clases + java sources")
if(TARGET SDL3-jar)
install(FILES "${SDL3_BINARY_DIR}/SDL3.jar" "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}.jar"
DESTINATION "${SDL_INSTALL_JAVADIR}/SDL3")
endif()
if(TARGET SDL3-javasources)
install(FILES "${SDL3_BINARY_DIR}/SDL3-${SDL3_VERSION}-sources.jar"
DESTINATION "${SDL_INSTALL_JAVADIR}/SDL3")
endif()
endif()
if(NOT SDL_DISABLE_INSTALL_DOCS)
SDL_generate_manpages(
SYMBOL "SDL_Init"
WIKIHEADERS_PL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build-scripts/wikiheaders.pl"
)
if(TARGET SDL3-javadoc)
set(SDL_INSTALL_JAVADOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/javadoc" CACHE PATH "Path where to install SDL3 javadoc")
install(DIRECTORY "${SDL3_BINARY_DIR}/docs/javadoc/"
DESTINATION "${SDL_INSTALL_JAVADOCDIR}/SDL3")
endif()
endif()
endif()

View File

@ -0,0 +1,103 @@
#[=======================================================================[
FindSdlAndroid
----------------------
Locate various executables that are essential to creating an Android APK archive.
This find module uses the FindSdlAndroidBuildTools module to locate some Android utils.
Imported targets
^^^^^^^^^^^^^^^^
This module defines the following :prop_tgt:`IMPORTED` target(s):
`` SdlAndroid::aapt2 ``
Imported executable for the "android package tool" v2
`` SdlAndroid::apksigner``
Imported executable for the APK signer tool
`` SdlAndroid::d8 ``
Imported executable for the dex compiler
`` SdlAndroid::zipalign ``
Imported executable for the zipalign util
`` SdlAndroid::adb ``
Imported executable for the "android debug bridge" tool
`` SdlAndroid::keytool ``
Imported executable for the keytool, a key and certificate management utility
`` SdlAndroid::zip ``
Imported executable for the zip, for packaging and compressing files
Result variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
`` AAPT2_BIN ``
Path of aapt2
`` APKSIGNER_BIN ``
Path of apksigner
`` D8_BIN ``
Path of d8
`` ZIPALIGN_BIN ``
Path of zipalign
`` ADB_BIN ``
Path of adb
`` KEYTOOL_BIN ``
Path of keytool
`` ZIP_BIN ``
Path of zip
#]=======================================================================]
cmake_minimum_required(VERSION 3.7)
if(NOT PROJECT_NAME MATCHES "^SDL.*")
message(WARNING "This module is internal to SDL and is currently not supported.")
endif()
find_package(SdlAndroidBuildTools MODULE)
function(_sdl_android_find_create_imported_executable NAME)
string(TOUPPER "${NAME}" NAME_UPPER)
set(varname "${NAME_UPPER}_BIN")
find_program("${varname}" NAMES "${NAME}" PATHS ${SDL_ANDROID_BUILD_TOOLS_ROOT})
if(EXISTS "${${varname}}" AND NOT TARGET SdlAndroid::${NAME})
add_executable(SdlAndroid::${NAME} IMPORTED)
set_property(TARGET SdlAndroid::${NAME} PROPERTY IMPORTED_LOCATION "${${varname}}")
endif()
endfunction()
if(SdlAndroidBuildTools_FOUND)
_sdl_android_find_create_imported_executable(aapt2)
_sdl_android_find_create_imported_executable(apksigner)
_sdl_android_find_create_imported_executable(d8)
_sdl_android_find_create_imported_executable(zipalign)
endif()
_sdl_android_find_create_imported_executable(adb)
_sdl_android_find_create_imported_executable(keytool)
_sdl_android_find_create_imported_executable(zip)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SdlAndroid
VERSION_VAR
REQUIRED_VARS
AAPT2_BIN
APKSIGNER_BIN
D8_BIN
ZIPALIGN_BIN
KEYTOOL_BIN
ZIP_BIN
)

View File

@ -0,0 +1,115 @@
#[=======================================================================[
FindSdlAndroidBuildTools
----------------------
Locate the Android build tools directory.
Imported targets
^^^^^^^^^^^^^^^^
This find module defines the following :prop_tgt:`IMPORTED` target(s):
<none>
Result variables
^^^^^^^^^^^^^^^^
This module will set the following variables in your project:
`` SdlAndroidBuildTools_FOUND
if false, no Android build tools have been found
`` SDL_ANDROID_BUILD_TOOLS_ROOT
path of the Android build tools root directory if found
`` SDL_ANDROID_BUILD_TOOLS_VERSION
the human-readable string containing the android build tools version if found
Cache variables
^^^^^^^^^^^^^^^
These variables may optionally be set to help this module find the correct files:
``SDL_ANDROID_BUILD_TOOLS_ROOT``
path of the Android build tools root directory
Variables for locating Android platform
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This module responds to the flags:
``SDL_ANDROID_HOME
First, this module will look for platforms in this CMake variable.
``ANDROID_HOME
If no platform was found in `SDL_ANDROID_HOME`, then try `ANDROID_HOME`.
``$ENV{ANDROID_HOME}
If no platform was found in neither `SDL_ANDROID_HOME` or `ANDROID_HOME`, then try `ANDROID_HOME}`
#]=======================================================================]
cmake_minimum_required(VERSION 3.7)
if(NOT PROJECT_NAME MATCHES "^SDL.*")
message(WARNING "This module is internal to SDL and is currently not supported.")
endif()
function(_sdl_is_valid_android_build_tools_root RESULT VERSION BUILD_TOOLS_ROOT)
set(result TRUE)
set(version -1)
string(REGEX MATCH "/([0-9.]+)$" root_match "${BUILD_TOOLS_ROOT}")
if(root_match
AND EXISTS "${BUILD_TOOLS_ROOT}/aapt2"
AND EXISTS "${BUILD_TOOLS_ROOT}/apksigner"
AND EXISTS "${BUILD_TOOLS_ROOT}/d8"
AND EXISTS "${BUILD_TOOLS_ROOT}/zipalign")
set(result "${BUILD_TOOLS_ROOT}")
set(version "${CMAKE_MATCH_1}")
endif()
set(${RESULT} ${result} PARENT_SCOPE)
set(${VERSION} ${version} PARENT_SCOPE)
endfunction()
function(_find_sdl_android_build_tools_root ROOT)
cmake_parse_arguments(fsabtr "" "" "" ${ARGN})
set(homes ${SDL_ANDROID_HOME} ${ANDROID_HOME} $ENV{ANDROID_HOME})
set(root ${ROOT}-NOTFOUND)
foreach(home IN LISTS homes)
if(NOT IS_DIRECTORY "${home}")
continue()
endif()
file(GLOB build_tools_roots LIST_DIRECTORIES true "${home}/build-tools/*")
set(max_build_tools_version -1)
set(max_build_tools_root "")
foreach(build_tools_root IN LISTS build_tools_roots)
_sdl_is_valid_android_build_tools_root(is_valid build_tools_version "${build_tools_root}")
if(is_valid AND build_tools_version GREATER max_build_tools_version)
set(max_build_tools_version "${build_tools_version}")
set(max_build_tools_root "${build_tools_root}")
endif()
endforeach()
if(max_build_tools_version GREATER -1)
set(root ${max_build_tools_root})
break()
endif()
endforeach()
set(${ROOT} ${root} PARENT_SCOPE)
endfunction()
if(NOT DEFINED SDL_ANDROID_BUILD_TOOLS_ROOT)
_find_sdl_android_build_tools_root(SDL_ANDROID_BUILD_TOOLS_ROOT)
set(SDL_ANDROID_BUILD_TOOLS_ROOT "${SDL_ANDROID_BUILD_TOOLS_ROOT}" CACHE PATH "Path of Android build tools")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SdlAndroidBuildTools
VERSION_VAR SDL_ANDROID_BUILD_TOOLS_VERSION
REQUIRED_VARS SDL_ANDROID_BUILD_TOOLS_ROOT
)

View File

@ -0,0 +1,123 @@
#[=======================================================================[
FindSdlAndroidPlatform
----------------------
Locate the Android SDK platform.
Imported targets
^^^^^^^^^^^^^^^^
This module defines the following :prop_tgt:`IMPORTED` target(s):
<none>
Result variables
^^^^^^^^^^^^^^^^
This find module will set the following variables in your project:
`` SdlAndroidPlatform_FOUND
if false, no Android platform has been found
`` SDL_ANDROID_PLATFORM_ROOT
path of the Android SDK platform root directory if found
`` SDL_ANDROID_PLATFORM_ANDROID_JAR
path of the Android SDK platform jar file if found
`` SDL_ANDROID_PLATFORM_VERSION
the human-readable string containing the android platform version if found
Cache variables
^^^^^^^^^^^^^^^
These variables may optionally be set to help this module find the correct files:
``SDL_ANDROID_PLATFORM_ROOT``
path of the Android SDK platform root directory
Variables for locating Android platform
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This module responds to the flags:
``SDL_ANDROID_HOME
First, this module will look for platforms in this CMake variable.
``ANDROID_HOME
If no platform was found in `SDL_ANDROID_HOME`, then try `ANDROID_HOME`.
``$ENV{ANDROID_HOME}
If no platform was found in neither `SDL_ANDROID_HOME` or `ANDROID_HOME`, then try `ANDROID_HOME}`
#]=======================================================================]
cmake_minimum_required(VERSION 3.7)
if(NOT PROJECT_NAME MATCHES "^SDL.*")
message(WARNING "This module is internal to SDL and is currently not supported.")
endif()
function(_sdl_is_valid_android_platform_root RESULT VERSION PLATFORM_ROOT)
set(result FALSE)
set(version -1)
string(REGEX MATCH "/android-([0-9]+)$" root_match "${PLATFORM_ROOT}")
if(root_match AND EXISTS "${PLATFORM_ROOT}/android.jar")
set(result TRUE)
set(version "${CMAKE_MATCH_1}")
endif()
set(${RESULT} ${result} PARENT_SCOPE)
set(${VERSION} ${version} PARENT_SCOPE)
endfunction()
function(_sdl_find_android_platform_root ROOT)
cmake_parse_arguments(sfapr "" "" "" ${ARGN})
set(homes ${SDL_ANDROID_HOME} ${ANDROID_HOME} $ENV{ANDROID_HOME})
set(root ${ROOT}-NOTFOUND)
foreach(home IN LISTS homes)
if(NOT IS_DIRECTORY "${home}")
continue()
endif()
file(GLOB platform_roots LIST_DIRECTORIES true "${home}/platforms/*")
set(max_platform_version -1)
set(max_platform_root "")
foreach(platform_root IN LISTS platform_roots)
_sdl_is_valid_android_platform_root(is_valid platform_version "${platform_root}")
if(is_valid AND platform_version GREATER max_platform_version)
set(max_platform_version "${platform_version}")
set(max_platform_root "${platform_root}")
endif()
endforeach()
if(max_platform_version GREATER -1)
set(root ${max_platform_root})
break()
endif()
endforeach()
set(${ROOT} ${root} PARENT_SCOPE)
endfunction()
set(SDL_ANDROID_PLATFORM_ANDROID_JAR "SDL_ANDROID_PLATFORM_ANDROID_JAR-NOTFOUND")
if(NOT DEFINED SDL_ANDROID_PLATFORM_ROOT)
_sdl_find_android_platform_root(SDL_ANDROID_PLATFORM_ROOT)
set(SDL_ANDROID_PLATFORM_ROOT "${SDL_ANDROID_PLATFORM_ROOT}" CACHE PATH "Path of Android platform")
endif()
if(SDL_ANDROID_PLATFORM_ROOT)
_sdl_is_valid_android_platform_root(_valid SDL_ANDROID_PLATFORM_VERSION "${SDL_ANDROID_PLATFORM_ROOT}")
if(_valid)
set(SDL_ANDROID_PLATFORM_ANDROID_JAR "${SDL_ANDROID_PLATFORM_ROOT}/android.jar")
endif()
unset(_valid)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SdlAndroidPlatform
VERSION_VAR SDL_ANDROID_PLATFORM_VERSION
REQUIRED_VARS SDL_ANDROID_PLATFORM_ROOT SDL_ANDROID_PLATFORM_ANDROID_JAR
)

View File

@ -0,0 +1,276 @@
#[=======================================================================[
This CMake script contains functions to build an Android APK.
It is (currently) limited to packaging binaries for a single architecture.
#]=======================================================================]
cmake_minimum_required(VERSION 3.7)
if(NOT PROJECT_NAME MATCHES "^SDL.*")
message(WARNING "This module is internal to SDL and is currently not supported.")
endif()
function(_sdl_create_outdir_for_target OUTDIRECTORY TARGET)
set(outdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TARGET}.dir")
# Some CMake versions have a slow `cmake -E make_directory` implementation
if(NOT IS_DIRECTORY "${outdir}")
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${outdir}")
endif()
set("${OUTDIRECTORY}" "${outdir}" PARENT_SCOPE)
endfunction()
function(sdl_create_android_debug_keystore TARGET)
set(output "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_debug.keystore")
add_custom_command(OUTPUT ${output}
COMMAND ${CMAKE_COMMAND} -E rm -f "${output}"
COMMAND SdlAndroid::keytool -genkey -keystore "${output}" -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "C=US, O=Android, CN=Android Debug"
)
add_custom_target(${TARGET} DEPENDS "${output}")
set_property(TARGET ${TARGET} PROPERTY OUTPUT "${output}")
endfunction()
function(sdl_android_compile_resources TARGET)
cmake_parse_arguments(arg "" "RESFOLDER" "RESOURCES" ${ARGN})
if(NOT arg_RESFOLDER AND NOT arg_RESOURCES)
message(FATAL_ERROR "Missing RESFOLDER or RESOURCES argument (need one or both)")
endif()
_sdl_create_outdir_for_target(outdir "${TARGET}")
set(out_files "")
set(res_files "")
if(arg_RESFOLDER)
get_filename_component(arg_RESFOLDER "${arg_RESFOLDER}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
file(GLOB_RECURSE res_folder_files "${arg_RESFOLDER}/*")
list(APPEND res_files ${res_folder_files})
foreach(res_file IN LISTS res_files)
file(RELATIVE_PATH rel_res_file "${arg_RESFOLDER}" "${res_file}")
string(REPLACE "/" "_" rel_comp_path "${rel_res_file}")
if(res_file MATCHES ".*res/values.*\\.xml$")
string(REGEX REPLACE "\\.xml" ".arsc" rel_comp_path "${rel_comp_path}")
endif()
set(comp_path "${outdir}/${rel_comp_path}.flat")
add_custom_command(
OUTPUT "${comp_path}"
COMMAND SdlAndroid::aapt2 compile -o "${outdir}" "${res_file}"
DEPENDS ${res_file}
)
list(APPEND out_files "${comp_path}")
endforeach()
endif()
if(arg_RESOURCES)
list(APPEND res_files ${arg_RESOURCES})
foreach(res_file IN LISTS arg_RESOURCES)
string(REGEX REPLACE ".*/res/" "" rel_res_file ${res_file})
string(REPLACE "/" "_" rel_comp_path "${rel_res_file}")
if(res_file MATCHES ".*res/values.*\\.xml$")
string(REGEX REPLACE "\\.xml" ".arsc" rel_comp_path "${rel_comp_path}")
endif()
set(comp_path "${outdir}/${rel_comp_path}.flat")
add_custom_command(
OUTPUT "${comp_path}"
COMMAND SdlAndroid::aapt2 compile -o "${outdir}" "${res_file}"
DEPENDS ${res_file}
)
list(APPEND out_files "${comp_path}")
endforeach()
endif()
add_custom_target(${TARGET} DEPENDS ${out_files})
set_property(TARGET "${TARGET}" PROPERTY OUTPUTS "${out_files}")
set_property(TARGET "${TARGET}" PROPERTY SOURCES "${res_files}")
endfunction()
function(sdl_android_link_resources TARGET)
cmake_parse_arguments(arg "NO_DEBUG" "MIN_SDK_VERSION;TARGET_SDK_VERSION;ANDROID_JAR;OUTPUT_APK;MANIFEST;PACKAGE" "RES_TARGETS" ${ARGN})
if(arg_MANIFEST)
get_filename_component(arg_MANIFEST "${arg_MANIFEST}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
else()
message(FATAL_ERROR "sdl_add_android_link_resources_target requires a Android MANIFEST path (${arg_MANIFEST})")
endif()
if(NOT arg_PACKAGE)
file(READ "${arg_MANIFEST}" manifest_contents)
string(REGEX MATCH "package=\"([a-zA-Z0-9_.]+)\"" package_match "${manifest_contents}")
if(NOT package_match)
message(FATAL_ERROR "Could not extract package from Android manifest (${arg_MANIFEST})")
endif()
set(arg_PACKAGE "${CMAKE_MATCH_1}")
endif()
set(depends "")
_sdl_create_outdir_for_target(outdir "${TARGET}")
string(REPLACE "." "/" java_r_path "${arg_PACKAGE}")
get_filename_component(java_r_path "${java_r_path}" ABSOLUTE BASE_DIR "${outdir}")
set(java_r_path "${java_r_path}/R.java")
set(command SdlAndroid::aapt2 link)
if(NOT arg_NO_DEBUG)
list(APPEND command --debug-mode)
endif()
if(arg_MIN_SDK_VERSION)
list(APPEND command --min-sdk-version ${arg_MIN_SDK_VERSION})
endif()
if(arg_TARGET_SDK_VERSION)
list(APPEND command --target-sdk-version ${arg_TARGET_SDK_VERSION})
endif()
if(arg_ANDROID_JAR)
list(APPEND command -I "${arg_ANDROID_JAR}")
else()
list(APPEND command -I "${SDL_ANDROID_PLATFORM_ANDROID_JAR}")
endif()
if(NOT arg_OUTPUT_APK)
set(arg_OUTPUT_APK "${TARGET}.apk")
endif()
get_filename_component(arg_OUTPUT_APK "${arg_OUTPUT_APK}" ABSOLUTE BASE_DIR "${outdir}")
list(APPEND command -o "${arg_OUTPUT_APK}")
list(APPEND command --java "${outdir}")
list(APPEND command --manifest "${arg_MANIFEST}")
foreach(res_target IN LISTS arg_RES_TARGETS)
list(APPEND command $<TARGET_PROPERTY:${res_target},OUTPUTS>)
list(APPEND depends $<TARGET_PROPERTY:${res_target},OUTPUTS>)
endforeach()
add_custom_command(
OUTPUT "${arg_OUTPUT_APK}" "${java_r_path}"
COMMAND ${command}
DEPENDS ${depends} ${arg_MANIFEST}
COMMAND_EXPAND_LISTS
VERBATIM
)
add_custom_target(${TARGET} DEPENDS "${arg_OUTPUT_APK}" "${java_r_path}")
set_property(TARGET ${TARGET} PROPERTY OUTPUT "${arg_OUTPUT_APK}")
set_property(TARGET ${TARGET} PROPERTY JAVA_R "${java_r_path}")
set_property(TARGET ${TARGET} PROPERTY OUTPUTS "${${arg_OUTPUT_APK}};${java_r_path}")
endfunction()
function(sdl_add_to_apk_unaligned TARGET)
cmake_parse_arguments(arg "" "APK_IN;NAME;OUTDIR" "ASSETS;NATIVE_LIBS;DEX" ${ARGN})
if(NOT arg_APK_IN)
message(FATAL_ERROR "Missing APK_IN argument")
endif()
if(NOT TARGET ${arg_APK_IN})
message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
endif()
_sdl_create_outdir_for_target(workdir ${TARGET})
if(NOT arg_OUTDIR)
set(arg_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT arg_NAME)
string(REGEX REPLACE "[:-]+" "." arg_NAME "${TARGET}")
if(NOT arg_NAME MATCHES "\\.apk")
set(arg_NAME "${arg_NAME}.apk")
endif()
endif()
get_filename_component(apk_file "${arg_NAME}" ABSOLUTE BASE_DIR "${arg_OUTDIR}")
set(apk_libdir "lib/${ANDROID_ABI}")
set(depends "")
set(commands
COMMAND "${CMAKE_COMMAND}" -E remove_directory -rf "${apk_libdir}" "assets"
COMMAND "${CMAKE_COMMAND}" -E make_directory "${apk_libdir}" "assets"
COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_PROPERTY:${arg_APK_IN},OUTPUT>" "${apk_file}"
)
set(dex_i "1")
foreach(dex IN LISTS arg_DEX)
set(suffix "${dex_i}")
if(suffix STREQUAL "1")
set(suffix "")
endif()
list(APPEND commands
COMMAND "${CMAKE_COMMAND}" -E copy "$<TARGET_PROPERTY:${dex},OUTPUT>" "classes${suffix}.dex"
COMMAND SdlAndroid::zip -u -q -j "${apk_file}" "classes${suffix}.dex"
)
math(EXPR dex_i "${dex_i}+1")
list(APPEND depends "$<TARGET_PROPERTY:${dex},OUTPUT>")
endforeach()
foreach(native_lib IN LISTS arg_NATIVE_LIBS)
list(APPEND commands
COMMAND "${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${native_lib}> "${apk_libdir}/$<TARGET_FILE_NAME:${native_lib}>"
COMMAND SdlAndroid::zip -u -q "${apk_file}" "${apk_libdir}/$<TARGET_FILE_NAME:${native_lib}>"
)
endforeach()
if(arg_ASSETS)
list(APPEND commands
COMMAND "${CMAKE_COMMAND}" -E copy ${arg_ASSETS} "assets"
COMMAND SdlAndroid::zip -u -r -q "${apk_file}" "assets"
)
endif()
add_custom_command(OUTPUT "${apk_file}"
${commands}
DEPENDS ${arg_NATIVE_LIBS} ${depends} "$<TARGET_PROPERTY:${arg_APK_IN},OUTPUT>"
WORKING_DIRECTORY "${workdir}"
)
add_custom_target(${TARGET} DEPENDS "${apk_file}")
set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
endfunction()
function(sdl_apk_align TARGET APK_IN)
cmake_parse_arguments(arg "" "NAME;OUTDIR" "" ${ARGN})
if(NOT TARGET ${arg_APK_IN})
message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
endif()
if(NOT arg_OUTDIR)
set(arg_OUTDIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT arg_NAME)
string(REGEX REPLACE "[:-]+" "." arg_NAME "${TARGET}")
if(NOT arg_NAME MATCHES "\\.apk")
set(arg_NAME "${arg_NAME}.apk")
endif()
endif()
get_filename_component(apk_file "${arg_NAME}" ABSOLUTE BASE_DIR "${arg_OUTDIR}")
add_custom_command(OUTPUT "${apk_file}"
COMMAND SdlAndroid::zipalign -f 4 "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" "${apk_file}"
DEPENDS "$<TARGET_PROPERTY:${APK_IN},OUTPUT>"
)
add_custom_target(${TARGET} DEPENDS "${apk_file}")
set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
endfunction()
function(sdl_apk_sign TARGET APK_IN)
cmake_parse_arguments(arg "" "OUTPUT;KEYSTORE" "" ${ARGN})
if(NOT TARGET ${arg_APK_IN})
message(FATAL_ERROR "APK_IN (${arg_APK_IN}) must be a target providing an apk")
endif()
if(NOT TARGET ${arg_KEYSTORE})
message(FATAL_ERROR "APK_KEYSTORE (${APK_KEYSTORE}) must be a target providing a keystore")
endif()
if(NOT arg_OUTPUT)
string(REGEX REPLACE "[:-]+" "." arg_OUTPUT "${TARGET}")
if(NOT arg_OUTPUT MATCHES "\\.apk")
set(arg_OUTPUT "${arg_OUTPUT}.apk")
endif()
endif()
get_filename_component(apk_file "${arg_OUTPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_command(OUTPUT "${apk_file}"
COMMAND SdlAndroid::apksigner sign
--ks "$<TARGET_PROPERTY:${arg_KEYSTORE},OUTPUT>"
--ks-pass pass:android --in "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" --out "${apk_file}"
DEPENDS "$<TARGET_PROPERTY:${APK_IN},OUTPUT>" "$<TARGET_PROPERTY:${arg_KEYSTORE},OUTPUT>"
BYPRODUCTS "${apk_file}.idsig"
)
add_custom_target(${TARGET} DEPENDS "${apk_file}")
set_property(TARGET ${TARGET} PROPERTY OUTPUT "${apk_file}")
endfunction()

View File

@ -0,0 +1,74 @@
#[=======================================================================[
This CMake script is meant to be used in CMake script mode (cmake -P).
It wraps commands that communicate with an actual Android device.
Because
#]=======================================================================]
cmake_minimum_required(VERSION 3.16)
if(NOT CMAKE_SCRIPT_MODE_FILE)
message(FATAL_ERROR "This file can only be used in CMake script mode")
endif()
if(NOT ADB)
set(ADB "adb")
endif()
if(NOT ACTION)
message(FATAL_ERROR "Missing ACTION argument")
endif()
if(ACTION STREQUAL "uninstall")
# The uninstall action attempts to uninstall all packages. All failures are ignored.
foreach(package IN LISTS PACKAGES)
message("Uninstalling ${package} ...")
execute_process(
COMMAND ${ADB} uninstall ${package}
RESULT_VARIABLE res
)
message("... result=${res}")
endforeach()
elseif(ACTION STREQUAL "install")
# The install actions attempts to install APK's to an Android device using adb. Failures are ignored.
set(failed_apks "")
foreach(apk IN LISTS APKS)
message("Installing ${apk} ...")
execute_process(
COMMAND ${ADB} install -d -r --streaming ${apk}
RESULT_VARIABLE res
)
message("... result=${res}")
if(NOT res EQUAL 0)
list(APPEND failed_apks ${apk})
endif()
endforeach()
if(failed_apks)
message(FATAL_ERROR "Failed to install ${failed_apks}")
endif()
elseif(ACTION STREQUAL "build-install-run")
if(NOT EXECUTABLES)
message(FATAL_ERROR "Missing EXECUTABLES (don't know what executables to build/install and start")
endif()
if(NOT BUILD_FOLDER)
message(FATAL_ERROR "Missing BUILD_FOLDER (don't know where to build the APK's")
endif()
set(install_targets "")
foreach(executable IN LISTS EXECUTABLES)
list(APPEND install_targets "install-${executable}")
endforeach()
execute_process(
COMMAND ${CMAKE_COMMAND} --build "${BUILD_FOLDER}" --target ${install_targets}
RESULT_VARIABLE res
)
if(NOT res EQUAL 0)
message(FATAL_ERROR "Failed to install APK(s) for ${EXECUTABLES}")
endif()
list(GET EXECUTABLES 0 start_executable)
execute_process(
COMMAND ${CMAKE_COMMAND} --build "${BUILD_FOLDER}" --target start-${start_executable}
RESULT_VARIABLE res
)
else()
message(FATAL_ERROR "Unknown ACTION=${ACTION}")
endif()

View File

@ -485,3 +485,79 @@ 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
================================================================================
SDL's CMake build system can create APK's for the tests.
It can build all tests with a single command without a dependency on gradle or Android Studio.
The APK's are signed with a debug certificate.
The only caveat is that the APK's support a single architecture.
### Requirements
- SDL source tree
- CMake
- ninja or make
- Android Platform SDK
- Android NDK
- Android Build tools
- Java JDK (version should be compatible with Android)
- keytool (usually provided with the Java JDK), used for generating a debug certificate
- zip
### CMake configuration
When configuring the CMake project, you need to use the Android NDK CMake toolchain, and pass the Android home path through `SDL_ANDROID_HOME`.
```
cmake .. -DCMAKE_TOOLCHAIN_FILE=<path/to/android.toolchain.cmake> -DANDROID_ABI=<android-abi> -DSDL_ANDROID_HOME=<path-to-android-sdk-home> -DANDROID_PLATFORM=23 -DSDL_TESTS=ON
```
Remarks:
- `android.toolchain.cmake` can usually be found at `$ANDROID_HOME/ndk/x.y.z/build/cmake/android.toolchain.cmake`
- `ANDROID_ABI` should be one of `arm64-v8a`, `armeabi-v7a`, `x86` or `x86_64`.
- When CMake is unable to find required paths, use `cmake-gui` to override required `SDL_ANDROID_` CMake cache variables.
### Building the APK's
For the `testsprite` executable, the `testsprite-apk` target will build the associated APK:
```
cmake --build . --target testsprite-apk
```
APK's of all tests can be built with the `sdl-test-apks` target:
```
cmake --build . --target sdl-test-apks
```
### Installation/removal of the tests
`testsprite.apk` APK can be installed on your Android machine using the `install-testsprite` target:
```
cmake --build . --target install-testsprite
```
APK's of all tests can be installed with the `install-sdl-test-apks` target:
```
cmake --build . --target install-sdl-test-apks
```
All SDL tests can be uninstalled with the `uninstall-sdl-test-apks` target:
```
cmake --build . --target uninstall-sdl-test-apks
```
### Starting the tests
After installation, the tests can be started using the Android Launcher GUI.
Alternatively, they can also be started using CMake targets.
This command will start the testsprite executable:
```
cmake --build . --target start-testsprite
```
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.

View File

@ -460,3 +460,138 @@ if(SDL_INSTALL_TESTS)
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/installed-tests/SDL3
)
endif()
if(ANDROID AND TARGET SDL3-jar)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../cmake/android")
find_package(SdlAndroid MODULE)
if(SdlAndroid_FOUND)
set(apks "")
set(packages "")
include(SdlAndroidFunctions)
sdl_create_android_debug_keystore(SDL_test-debug-keystore)
sdl_android_compile_resources(SDL_test-resources RESFOLDER android/res)
add_custom_target(sdl-test-apks)
foreach(TEST ${SDL_TEST_EXECUTABLES})
set(ANDROID_MANIFEST_APP_NAME "${TEST}")
set(ANDROID_MANIFEST_LABEL "${TEST}")
set(ANDROID_MANIFEST_LIB_NAME "$<TARGET_FILE_BASE_NAME:${TEST}>")
set(ANDROID_MANIFEST_PACKAGE "org.libsdl.sdl.test.${TEST}")
set(generated_manifest_path "${CMAKE_CURRENT_BINARY_DIR}/android/${TEST}-src/AndroidManifest.xml")
string(REPLACE "." "/" JAVA_PACKAGE_DIR "${ANDROID_MANIFEST_PACKAGE}")
set(GENERATED_SRC_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/android/${TEST}-src")
set(GENERATED_RES_FOLDER "${GENERATED_SRC_FOLDER}/res")
set(JAVA_PACKAGE_DIR "${GENERATED_SRC_FOLDER}/${JAVA_PACKAGE_DIR}")
configure_file(android/cmake/SDLEntryTestActivity.java.cmake "${JAVA_PACKAGE_DIR}/SDLEntryTestActivity.java" @ONLY)
configure_file(android/cmake/SDLTestActivity.java.cmake "${JAVA_PACKAGE_DIR}/SDLTestActivity.java" @ONLY)
configure_file(android/cmake/res/values/strings.xml.cmake android/res/values/strings-${TEST}.xml @ONLY)
configure_file(android/cmake/res/xml/shortcuts.xml.cmake "${GENERATED_RES_FOLDER}/xml/shortcuts.xml" @ONLY)
configure_file(android/cmake/AndroidManifest.xml.cmake "${generated_manifest_path}" @ONLY)
file(GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/android/${TEST}-$<CONFIG>/res/values/strings.xml"
INPUT "${CMAKE_CURRENT_BINARY_DIR}/android/res/values/strings-${TEST}.xml"
)
sdl_android_compile_resources(${TEST}-resources
RESOURCES
"${CMAKE_CURRENT_BINARY_DIR}/android/${TEST}-$<CONFIG>/res/values/strings.xml"
"${GENERATED_RES_FOLDER}/xml/shortcuts.xml"
)
sdl_android_link_resources(${TEST}-apk-linked
MANIFEST "${generated_manifest_path}"
PACKAGE ${ANDROID_MANIFEST_PACKAGE}
RES_TARGETS SDL_test-resources ${TEST}-resources
TARGET_SDK_VERSION 31
)
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding;utf-8")
set(classes_path "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TEST}-java.dir/classes")
# Some CMake versions have a slow `cmake -E make_directory` implementation
if(NOT IS_DIRECTORY "${classes_path}")
execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${classes_path}")
endif()
set(OUT_JAR "${CMAKE_CURRENT_BINARY_DIR}/${TEST}.jar")
add_custom_command(
OUTPUT "${OUT_JAR}"
COMMAND ${CMAKE_COMMAND} -E rm -rf "${classes_path}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${classes_path}"
COMMAND ${Java_JAVAC_EXECUTABLE}
-source 1.8 -target 1.8
-bootclasspath "$<TARGET_PROPERTY:SDL3-jar,OUTPUT>"
"${JAVA_PACKAGE_DIR}/SDLEntryTestActivity.java"
"${JAVA_PACKAGE_DIR}/SDLTestActivity.java"
$<TARGET_PROPERTY:${TEST}-apk-linked,JAVA_R>
-cp "$<TARGET_PROPERTY:SDL3-jar,OUTPUT>:${path_android_jar}"
-d "${classes_path}"
COMMAND ${Java_JAR_EXECUTABLE} cf "${OUT_JAR}" -C "${classes_path}" .
DEPENDS $<TARGET_PROPERTY:${TEST}-apk-linked,OUTPUTS> "$<TARGET_PROPERTY:SDL3-jar,OUTPUT>" "${JAVA_PACKAGE_DIR}/SDLTestActivity.java" "${JAVA_PACKAGE_DIR}/SDLEntryTestActivity.java"
)
add_custom_target(${TEST}-jar DEPENDS "${OUT_JAR}")
set_property(TARGET ${TEST}-jar PROPERTY OUTPUT "${OUT_JAR}")
set(dexworkdir "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${TEST}-dex.dir")
# Some CMake versions have a slow `cmake -E make_directory` implementation
if(NOT IS_DIRECTORY "${dexworkdir}")
execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${dexworkdir}")
endif()
set(classes_dex_base_name "classes.dex")
set(classes_dex "${dexworkdir}/${classes_dex_base_name}")
add_custom_command(
OUTPUT "${classes_dex}"
COMMAND SdlAndroid::d8
$<TARGET_PROPERTY:${TEST}-jar,OUTPUT>
$<TARGET_PROPERTY:SDL3-jar,OUTPUT>
--lib "${path_android_jar}"
--output "${dexworkdir}"
DEPENDS $<TARGET_PROPERTY:${TEST}-jar,OUTPUT> $<TARGET_PROPERTY:SDL3-jar,OUTPUT>
)
add_custom_target(${TEST}-dex DEPENDS "${classes_dex}")
set_property(TARGET ${TEST}-dex PROPERTY OUTPUT "${classes_dex}")
set_property(TARGET ${TEST}-dex PROPERTY OUTPUT_BASE_NAME "${classes_dex_base_name}")
sdl_add_to_apk_unaligned(${TEST}-unaligned-apk
APK_IN ${TEST}-apk-linked
OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/intermediates"
ASSETS ${RESOURCE_FILES}
NATIVE_LIBS SDL3::SDL3-shared ${TEST}
DEX ${TEST}-dex
)
sdl_apk_align(${TEST}-aligned-apk ${TEST}-unaligned-apk
OUTDIR "${CMAKE_CURRENT_BINARY_DIR}/intermediates"
)
sdl_apk_sign(${TEST}-apk ${TEST}-aligned-apk
KEYSTORE SDL_test-debug-keystore
)
add_dependencies(sdl-test-apks ${TEST}-apk)
if(TARGET SdlAndroid::adb)
add_custom_target(install-${TEST}
COMMAND "${CMAKE_COMMAND}" -DACTION=install "-DAPKS=$<TARGET_PROPERTY:${TEST}-apk,OUTPUT>" -P "${SDL3_SOURCE_DIR}/cmake/android/SdlAndroidScript.cmake"
DEPENDS "${TEST}-apk"
)
add_custom_target(start-${TEST}
COMMAND "${ADB_BIN}" shell am start-activity -S "${ANDROID_MANIFEST_PACKAGE}/.SDLTestActivity"
)
add_custom_target(build-install-start-${TEST}
COMMAND "${CMAKE_COMMAND}" -DACTION=build-install-run "-DEXECUTABLES=${TEST}" "-DBUILD_FOLDER=${CMAKE_BINARY_DIR}" -P "${SDL3_SOURCE_DIR}/cmake/android/SdlAndroidScript.cmake"
)
endif()
list(APPEND packages "${ANDROID_MANIFEST_PACKAGE}")
list(APPEND install_targets install-${TEST})
endforeach()
if(TARGET SdlAndroid::adb)
add_custom_target(install-sdl-test-apks
DEPENDS ${install_targets}
VERBATIM
)
add_custom_target(uninstall-sdl-test-apks
COMMAND "${CMAKE_COMMAND}" "-DADB=$<TARGET_FILE:SdlAndroid::adb>" -DACTION=uninstall "-DPACKAGES=${packages}" -P "${SDL3_SOURCE_DIR}/cmake/android/SdlAndroidScript.cmake"
VERBATIM
)
endif()
endif()
endif()

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="@ANDROID_MANIFEST_PACKAGE@">
<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" />
<!-- Touchscreen support -->
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<!-- Game controller support -->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-feature
android:name="android.hardware.gamepad"
android:required="false" />
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
<!-- External mouse input events -->
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
<!-- Allow access to the vibrator -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Allow access to the microphone -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:icon="@mipmap/sdl-test"
android:roundIcon="@mipmap/sdl-test_round"
android:label="@string/label"
android:supportsRtl="true"
android:hardwareAccelerated="true"
tools:targetApi="31">
<activity
android:name="@ANDROID_MANIFEST_PACKAGE@.SDLTestActivity"
android:exported="true"
android:label="@string/label"
android:alwaysRetainTaskState="true"
android:launchMode="singleInstance"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:screenOrientation="fullSensor">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
<activity
android:name="@ANDROID_MANIFEST_PACKAGE@.SDLEntryTestActivity"
android:exported="false"
android:label="@string/label">
</activity>
</application>
</manifest>

View File

@ -0,0 +1,121 @@
package @ANDROID_MANIFEST_PACKAGE@;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import org.libsdl.app.SDL;
import org.libsdl.app.SDLActivity;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;
public class SDLEntryTestActivity extends Activity {
public String MODIFY_ARGUMENTS = "@ANDROID_MANIFEST_PACKAGE@.MODIFY_ARGUMENTS";
boolean isModifyingArguments;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.v("SDL", "SDLEntryTestActivity onCreate");
super.onCreate(savedInstanceState);
String intent_action = getIntent().getAction();
Log.v("SDL", "SDLEntryTestActivity intent.action = " + intent_action);
if (intent_action == MODIFY_ARGUMENTS) {
isModifyingArguments = true;
createArgumentLayout();
} else {
startChildActivityAndFinish();
}
}
protected void createArgumentLayout() {
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.arguments_layout, null);
setContentView(view);
Button button = (Button)requireViewById(R.id.arguments_start_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
startChildActivityAndFinish();
}
});
}
protected String[] getArguments() {
if (!isModifyingArguments) {
return new String[0];
}
EditText editText = (EditText)findViewById(R.id.arguments_edit);
String text = editText.getText().toString();
String new_text = text.replace("[ \t]*[ \t\n]+[ \t]+", "\n").strip();
Log.v("SDL", "text = " + text + "\n becomes \n" + new_text);
return new_text.split("\n", 0);
}
@Override
protected void onStart() {
Log.v("SDL", "SDLEntryTestActivity onStart");
super.onStart();
}
@Override
protected void onResume() {
Log.v("SDL", "SDLEntryTestActivity onResume");
super.onResume();
}
@Override
protected void onPause() {
Log.v("SDL", "SDLEntryTestActivity onPause");
super.onPause();
}
@Override
protected void onStop() {
Log.v("SDL", "SDLEntryTestActivity onStop");
super.onStop();
}
@Override
protected void onDestroy() {
Log.v("SDL", "SDLEntryTestActivity onDestroy");
super.onDestroy();
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Log.v("SDL", "SDLEntryTestActivity onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
EditText editText = (EditText)findViewById(R.id.arguments_edit);
editText.setText(savedInstanceState.getCharSequence("args", ""), TextView.BufferType.EDITABLE);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
Log.v("SDL", "SDLEntryTestActivity onSaveInstanceState");
EditText editText = (EditText)findViewById(R.id.arguments_edit);
outState.putCharSequence("args", editText.getText());
super.onSaveInstanceState(outState);
}
private void startChildActivityAndFinish() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName("@ANDROID_MANIFEST_PACKAGE@", "@ANDROID_MANIFEST_PACKAGE@.SDLTestActivity");
intent.putExtra("arguments", getArguments());
startActivity(intent);
finish();
}
}

View File

@ -0,0 +1,33 @@
package @ANDROID_MANIFEST_PACKAGE@;
import org.libsdl.app.SDLActivity;
import android.os.Bundle;
import android.util.Log;
public class SDLTestActivity extends SDLActivity {
private String[] m_arguments;
@Override
protected void onCreate(Bundle savedInstanceState) {
m_arguments = getIntent().getStringArrayExtra("arguments");
if (m_arguments == null) {
m_arguments = new String[0];
}
super.onCreate(savedInstanceState);
}
@Override
protected String[] getLibraries() {
return new String[] { getString(R.string.lib_name) };
}
@Override
protected String[] getArguments() {
Log.v("SDLTest", "#arguments = " + m_arguments.length);
for(int i = 0; i < m_arguments.length; i++) {
Log.v("SDLTest", "argument[" + i + "] = " + m_arguments[i]);
}
return m_arguments;
}
}

View File

@ -0,0 +1,5 @@
<resources>
<string name="app_name">@ANDROID_MANIFEST_APP_NAME@</string>
<string name="lib_name">@ANDROID_MANIFEST_LIB_NAME@</string>
<string name="label">@ANDROID_MANIFEST_LABEL@</string>
</resources>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="modifyArguments"
android:enabled="true"
android:icon="@drawable/sdl-test_foreground"
android:shortcutShortLabel="@string/shortcutModifyArgumentsShortLabel">
<intent
android:action="@ANDROID_MANIFEST_PACKAGE@.MODIFY_ARGUMENTS"
android:targetPackage="@ANDROID_MANIFEST_PACKAGE@"
android:targetClass="@ANDROID_MANIFEST_PACKAGE@.SDLEntryTestActivity" />
</shortcut>
<shortcut
android:shortcutId="intermediateActivity"
android:enabled="true"
android:icon="@drawable/sdl-test_foreground"
android:shortcutShortLabel="@string/shortcutIntermediateActivityShortLabel">
<intent
android:action="android.intent.action.MAIN"
android:targetPackage="@ANDROID_MANIFEST_PACKAGE@"
android:targetClass="@ANDROID_MANIFEST_PACKAGE@.SDLEntryTestActivity" />
</shortcut>
<!-- Specify more shortcuts here. -->
</shortcuts>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:inputType="textImeMultiLine|textNoSuggestions"
android:text="@string/label_enter_arguments" />
<EditText
android:id="@+id/arguments_edit"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:hint="@string/hint_enter_arguments_here" />
<Button
android:id="@+id/arguments_start_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="@string/button_start_app" />
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/sdl-test_background"/>
<foreground android:drawable="@drawable/sdl-test_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/sdl-test_background"/>
<foreground android:drawable="@drawable/sdl-test_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,7 @@
<resources>
<string name="label_enter_arguments">Arguments</string>
<string name="hint_enter_arguments_here">One argument per line.\ne.g.\n--track-mem\n--windows\n3</string>
<string name="button_start_app">Start</string>
<string name="shortcutModifyArgumentsShortLabel">Modify arguments</string>
<string name="shortcutIntermediateActivityShortLabel">Pass through activity</string>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="sdl-test_background">#FFFFFF</color>
</resources>