diff --git a/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin b/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin new file mode 100644 index 0000000..e6388e1 Binary files /dev/null and b/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin differ diff --git a/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin b/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin new file mode 100644 index 0000000..f43ff91 Binary files /dev/null and b/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin differ diff --git a/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock b/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock new file mode 100644 index 0000000..b269de6 Binary files /dev/null and b/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock differ diff --git a/CMakeLists.txt b/CMakeLists.txt index fbd64b6..739c6ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories (${CMAKE_BINARY_DIR}/include) link_directories (${CMAKE_BINARY_DIR}/lib) option (STATIC_BUILD "Build Planet Blupi statically" ON) +option (ANDROID "Enable when building for Android" OFF) # It's an hack in order to be able to link statically planetblupi on darwin. if (APPLE) @@ -23,6 +24,35 @@ if (APPLE) set (CMD_CPPFLAGS "-I${CMAKE_BINARY_DIR}/include") endif () +if (ANDROID) + # It's really hard to get non-CMake projects build with Android NDK directly, so we'll start by + # generating a standalone toolchain (at configure time) + execute_process(COMMAND ${ANDROID_NDK}/build/tools/make-standalone-toolchain.sh + --platform=${ANDROID_NATIVE_API_LEVEL} + --toolchain=${ANDROID_TOOLCHAIN_NAME} + --install-dir=${CMAKE_BINARY_DIR}/toolchain + --arch=${ANDROID_SYSROOT_ABI} + --stl=libc++ ) # TODO: Should probably use ANDROID_STL instead of hardcoding, but the names are different (libc++ vs c++_static) + + # Prepare all cross-compilation options that need to be passed to child CMake projects + set (ADDITIONAL_CMAKE_OPTIONS + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -DANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN} + -DANDROID_ABI=${ANDROID_ABI} + -DANDROID_STL=${ANDROID_STL}) + + # Prepare all cross-compilation options needed for configure-based projects + set (ADDITIONAL_CONFIGURE_OPTIONS + --host=${ANDROID_HEADER_TRIPLE} + ) + set (ADDITIONAL_TOOL_OPTIONS + CC=clang + CXX=clang++ + ) + set (CMD_PATH "${CMAKE_BINARY_DIR}/toolchain/bin") + set (CMD_CHOST "${ANDROID_HEADER_TRIPLE}") +endif() + configure_file (cmd.sh.in cmd.sh @ONLY) set (CMD ${CMAKE_BINARY_DIR}/cmd.sh) @@ -73,7 +103,7 @@ else () ExternalProject_Add (zlib_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/zlib.tar.gz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --static BUILD_COMMAND ${CMD} make @@ -90,7 +120,7 @@ endif () ExternalProject_Add (argagg_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/argagg.tar.gz PREFIX ${CMAKE_BINARY_DIR} - CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR} ${ADDITIONAL_CMAKE_OPTIONS} ) ########## @@ -100,7 +130,7 @@ ExternalProject_Add (argagg_Project ExternalProject_Add (libcurl_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/curl.tar.xz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static @@ -139,6 +169,7 @@ ExternalProject_Add (libcurl_Project --without-librtmp --without-nghttp2 --without-libidn2 + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -154,10 +185,11 @@ if (NOT APPLE) ExternalProject_Add (libiconv_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/libiconv.tar.gz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -177,10 +209,11 @@ endif () ExternalProject_Add (gettext_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/gettext.tar.xz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND cd gettext-runtime && ${CMD} ./configure + CONFIGURE_COMMAND cd gettext-runtime && ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make -C gettext-runtime INSTALL_COMMAND ${CMD} make -C gettext-runtime install BUILD_IN_SOURCE 1 @@ -195,10 +228,11 @@ ExternalProject_Add (gettext_Project ExternalProject_Add (libpng_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/libpng.tar.xz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -210,6 +244,18 @@ ExternalProject_Add (libpng_Project ## FFmpeg ######### +if (ANDROID) + set (ADDITIONAL_FFMPEG_CONFIGURE_OPTIONS + --enable-cross-compile + --target-os=android + --arch=${ANDROID_SYSROOT_ABI} + --cross-prefix=${CMAKE_BINARY_DIR}/toolchain/bin/${ANDROID_HEADER_TRIPLE}-) + # TODO: We should really be using clang (gcc is deprecated in android NDK) but it doesn't work :( + # Try building with: + #--toolchain=clang-usan + #--as=${CMAKE_BINARY_DIR}/toolchain/bin/${ANDROID_HEADER_TRIPLE}-gcc # Workaround for missing as in clang, looks quite stupid but it works +endif () + ExternalProject_Add (FFmpeg_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/ffmpeg.tar.xz PREFIX ${CMAKE_BINARY_DIR} @@ -247,8 +293,12 @@ ExternalProject_Add (FFmpeg_Project --disable-libxcb-shm --disable-libxcb-xfixes --disable-libxcb-shape +<<<<<<< HEAD --disable-jack --disable-sndio +======= + ${ADDITIONAL_FFMPEG_CONFIGURE_OPTIONS} +>>>>>>> a1e010aedc6ba20f1c5af0592d4576669fe2e2ab BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -259,16 +309,17 @@ ExternalProject_Add (FFmpeg_Project ## libasound ############ -if (UNIX AND NOT APPLE) +if (UNIX AND NOT APPLE AND NOT ANDROID) ExternalProject_Add (libasound_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/alsa-lib.tar.bz2 PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static --disable-old-symbols --disable-python + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -339,11 +390,15 @@ endif () ## libpulse ########### -if (UNIX AND NOT APPLE) +if (UNIX AND NOT APPLE AND NOT ANDROID) ExternalProject_Add (libpulse_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/pulseaudio.tar.xz PREFIX ${CMAKE_BINARY_DIR} +<<<<<<< HEAD CONFIGURE_COMMAND patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/externals/pulseaudio.patch && ${CMD} ./configure +======= + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure +>>>>>>> a1e010aedc6ba20f1c5af0592d4576669fe2e2ab --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static @@ -381,6 +436,7 @@ if (UNIX AND NOT APPLE) --without-speex --without-soxr --with-database=simple + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install INSTALLDIR=${CMAKE_BINARY_DIR} BUILD_IN_SOURCE 1 @@ -393,7 +449,7 @@ endif () ## SDL2 ####### -if (UNIX AND NOT APPLE) +if (UNIX AND NOT APPLE AND NOT ANDROID) set (SDL2_CONFIGURE --enable-video-x11 --enable-x11-shared --enable-video-wayland @@ -415,23 +471,27 @@ elseif (MINGW) elseif (APPLE) set (SDL2_CONFIGURE --enable-video-opengl --enable-video-cocoa) +elseif (ANDROID) + set (SDL2_CONFIGURE --disable-pulseaudio) endif () set (SDL2_DEPENDS zlib_Project) -if (UNIX AND NOT APPLE) +if (UNIX AND NOT APPLE AND NOT ANDROID) set (SDL2_DEPENDS ${SDL2_DEPENDS} libasound_Project libpulse_Project) endif () ExternalProject_Add (SDL2_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/SDL2.tar.bz2 PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static - --disable-joystick + #--disable-joystick + --enable-joystick # TODO: Default SDL2 android skeleton requires joystick to build, could be probably fixed by commenting out some things --disable-haptic ${SDL2_CONFIGURE} + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -446,7 +506,9 @@ ExternalProject_Add (SDL2_Project ExternalProject_Add (SDL2_image_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/SDL2_image.tar.gz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + # SDL_MAIN_HANDLED fixes test program linking on Android + # TODO: Is there a better way to handle this? + CONFIGURE_COMMAND CFLAGS=-DSDL_MAIN_HANDLED ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static @@ -468,6 +530,7 @@ ExternalProject_Add (SDL2_image_Project --disable-xv --disable-webp --disable-webp-shared + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -487,7 +550,9 @@ endif () ExternalProject_Add (SDL2_mixer_Project URL ${CMAKE_CURRENT_SOURCE_DIR}/externals/SDL2_mixer.tar.gz PREFIX ${CMAKE_BINARY_DIR} - CONFIGURE_COMMAND ${CMD} ./configure + # SDL_MAIN_HANDLED fixes test program linking on Android + # TODO: Is there a better way to handle this? + CONFIGURE_COMMAND CFLAGS=-DSDL_MAIN_HANDLED ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure --prefix=${CMAKE_BINARY_DIR} --disable-shared --enable-static @@ -514,6 +579,7 @@ ExternalProject_Add (SDL2_mixer_Project --disable-music-mp3-smpeg-shared --disable-smpegtest --disable-music-mp3-mad-gpl + ${ADDITIONAL_CONFIGURE_OPTIONS} BUILD_COMMAND ${CMD} make INSTALL_COMMAND ${CMD} make install BUILD_IN_SOURCE 1 @@ -530,9 +596,10 @@ ExternalProject_Add (SDL_kitchensink_Project DOWNLOAD_COMMAND "" SOURCE_DIR ${CMAKE_SOURCE_DIR}/SDL_kitchensink PREFIX ${CMAKE_BINARY_DIR} - CMAKE_COMMAND ${CMD} cmake + CMAKE_COMMAND ${CMD} ${CMAKE_COMMAND} CMAKE_ARGS -DDISABLE_SHARED=true -DCMAKE_INSTALL_PREFIX:PATH= + ${ADDITIONAL_CMAKE_OPTIONS} INSTALL_DIR ${CMAKE_BINARY_DIR} BUILD_ALWAYS 1 DEPENDS SDL2_Project FFmpeg_Project @@ -574,11 +641,16 @@ set (planetblupi_DEPS gettext_Project libvorbis_Project ) +<<<<<<< HEAD if (UNIX AND NOT APPLE) list (APPEND planetblupi_DEPS libasound_Project libpulse_Project ) +======= +if (UNIX AND NOT APPLE AND NOT ANDROID) + list (APPEND planetblupi_DEPS libasound_Project libpulse_Project) +>>>>>>> a1e010aedc6ba20f1c5af0592d4576669fe2e2ab endif () ExternalProject_Add (planetblupi_Project @@ -586,7 +658,7 @@ ExternalProject_Add (planetblupi_Project DOWNLOAD_COMMAND "" SOURCE_DIR ${CMAKE_SOURCE_DIR}/planetblupi PREFIX ${CMAKE_BINARY_DIR} - CMAKE_COMMAND ${CMD} cmake + CMAKE_COMMAND ${CMD} ${CMAKE_COMMAND} CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DAPPIMAGE_APPRUN_PROGRAM=${APPIMAGE_APPRUN_PROGRAM} -DAPPIMAGE_ASSISTANT_PROGRAM=${APPIMAGE_TOOL_PROGRAM} @@ -594,11 +666,25 @@ ExternalProject_Add (planetblupi_Project -DPB_HTTP_VERSION_CHECK=yes -DSTATIC_BUILD=${STATIC_BUILD} -DSIGN_APP=${SIGN_APP} + -DANDROID=${ANDROID} + ${ADDITIONAL_CMAKE_OPTIONS} INSTALL_DIR ${CMAKE_BINARY_DIR} BUILD_ALWAYS 1 DEPENDS ${planetblupi_DEPS} ) +if (ANDROID) + #find_package (PkgConfig REQUIRED) + #pkg_search_module (SDL2 REQUIRED sdl2) + + add_library(main SHARED android/SDL_android_main.c) + add_dependencies (main planetblupi_Project) + target_link_libraries (main PUBLIC planetblupi) + + #add_dependencies (main SDL2_Project) + target_link_libraries (main PUBLIC -lintl -liconv -lSDL2 -lSDL2_image -lSDL2_mixer -lcurl -lSDL_kitchensink_static -lpng -lavformat -lavcodec -lavutil -lswscale -lswresample -lz -lGLESv1_CM -lGLESv2 -llog -landroid ${CMAKE_CXX_STANDARD_LIBRARIES_INIT}) +endif () + add_custom_target (dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) set (CPACK_SOURCE_GENERATOR "TXZ") diff --git a/CMakeLists.txt.bkp b/CMakeLists.txt.bkp new file mode 100644 index 0000000..d4f49f6 --- /dev/null +++ b/CMakeLists.txt.bkp @@ -0,0 +1,565 @@ + +cmake_minimum_required (VERSION 3.2) + +include (${CMAKE_ROOT}/Modules/ExternalProject.cmake) + +include_directories (${CMAKE_BINARY_DIR}/include) +link_directories (${CMAKE_BINARY_DIR}/lib) + +option (STATIC_BUILD "Build Planet Blupi statically" ON) +option (ANDROID "Enable when building for Android" OFF) + +# It's an hack in order to be able to link statically planetblupi on darwin. +if (APPLE) + set (ISAPPLE 1) + set (CMD_LDFLAGS "-L${CMAKE_BINARY_DIR}/lib -framework AudioToolBox -framework AudioUnit -framework CoreAudio -framework CoreFoundation -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo -framework Carbon") + + if (OLD_SDK) + set (OSX_SDK_VERSION 10.9) + set (CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX${OSX_SDK_VERSION}.sdk/") + set (CMAKE_OSX_DEPLOYMENT_TARGET ${OSX_SDK_VERSION}) + set (CMD_CXXFLAGS "--sysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${OSX_SDK_VERSION} ${CMAKE_CXX_FLAGS}") + set (CMD_CFLAGS "--sysroot ${CMAKE_OSX_SYSROOT} -mmacosx-version-min=${OSX_SDK_VERSION} ${CMAKE_C_FLAGS}") + endif () + set (CMD_CPPFLAGS "-I${CMAKE_BINARY_DIR}/include") +endif () + +if (ANDROID) + set (ADDITIONAL_CONFIGURE_OPTIONS + --host=${ANDROID_HEADER_TRIPLE} + ) + set (ADDITIONAL_CMAKE_OPTIONS + -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + -DANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN} + -DANDROID_ABI=${ANDROID_ABI} + -DANDROID_STL=${ANDROID_STL} + ) + set (ADDITIONAL_TOOL_OPTIONS + CC=${CMAKE_C_COMPILER} + CPP=${CMAKE_CXX_COMPILER} + ) + #set(CMD_CFLAGS "--target=${ANDROID_HEADER_TRIPLE} ${ANDROID_COMPILER_FLAGS}") + #set(CMD_CPPFLAGS "--target=${ANDROID_HEADER_TRIPLE} ${ANDROID_COMPILER_FLAGS}") + #set(CMD_CXXFLAGS "--target=${ANDROID_HEADER_TRIPLE} ${ANDROID_COMPILER_FLAGS}") + #set(CMD_LDFLAGS "--target=${ANDROID_HEADER_TRIPLE} ${ANDROID_LINKER_FLAGS}") + set(CMD_CFLAGS "--target=armv5te-none-linux-androideabi --gcc-toolchain=/opt/android-sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 --sysroot=/opt/android-sdk/ndk-bundle/sysroot -Dnative_lib_EXPORTS -isystem /opt/android-sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/include -isystem /opt/android-sdk/ndk-bundle/sources/android/support/include -isystem /opt/android-sdk/ndk-bundle/sources/cxx-stl/llvm-libc++abi/include -isystem /opt/android-sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=19 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security") + set(CMD_CPPFLAGS "${CMD_CFLAGS}") + set(CMD_CXXFLAGS "${CMD_CXXFLAGS}") + set(CMD_LDFLAGS "--target=armv5te-none-linux-androideabi --gcc-toolchain=/opt/android-sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64 --sysroot=/opt/android-sdk/ndk-bundle/sysroot -fPIC -isystem /opt/android-sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=19 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv5te -mtune=xscale -msoft-float -fno-integrated-as -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -Os -DNDEBUG -Wl,--exclude-libs,libgcc.a --sysroot /opt/android-sdk/ndk-bundle/platforms/android-19/arch-arm -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -L/opt/android-sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now") + set(CMD_CHOST "${ANDROID_HEADER_TRIPLE}") +endif() + +configure_file (cmd.sh.in cmd.sh @ONLY) +set (CMD ${CMAKE_BINARY_DIR}/cmd.sh) + +######### +## zlib +######### + +if (WIN32) + ExternalProject_Add (zlib_Project + URL http://www.zlib.net/zlib-1.2.11.tar.gz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND + BUILD_COMMAND ${CMD} make -fwin32/Makefile.gcc + INSTALL_COMMAND ${CMD} make install -fwin32/Makefile.gcc + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + ) +else () + ExternalProject_Add (zlib_Project + URL http://www.zlib.net/zlib-1.2.11.tar.gz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --static + BUILD_COMMAND ${CMD} make libz.a # don't make test programs + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + ) +endif () + +######### +## argagg +######### + +ExternalProject_Add (argagg_Project + URL https://github.com/vietjtnguyen/argagg/archive/0.4.6.tar.gz + PREFIX ${CMAKE_BINARY_DIR} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR} ${ADDITIONAL_CMAKE_OPTIONS} +) + +########## +## libcurl +########## + +ExternalProject_Add (libcurl_Project + URL https://curl.haxx.se/download/curl-7.55.0.tar.xz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --enable-http + --disable-ftp + --disable-file + --disable-ldap + --disable-ldaps + --disable-rtsp + --disable-proxy + --disable-dict + --disable-telnet + --disable-tftp + --disable-pop3 + --disable-imap + --disable-smb + --disable-smtp + --disable-gopher + --disable-manual + --disable-libcurl-option + --enable-ipv6 + --disable-sspi + --disable-ntlm-wb + --disable-unix-socket + --without-winssl + --without-darwinssl + --without-ssl + --without-gnutls + --without-polarssl + --without-mbedtls + --without-cyassl + --without-axtls + --without-libpsl + --without-libmetalink + --without-libssh2 + --without-librtmp + --without-nghttp2 + --without-libidn2 + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS zlib_Project +) + +########### +## libiconv +########### + +if (NOT APPLE) + ExternalProject_Add (libiconv_Project + URL https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + ) +endif () + +########## +## gettext +########## + +set (gettext_DEPENDS) +if (NOT APPLE) + set (gettext_DEPENDS ${gettext_DEPENDS} libiconv_Project) +endif () + +ExternalProject_Add (gettext_Project + URL http://mirror.switch.ch/ftp/mirror/gnu/gettext/gettext-0.19.8.1.tar.xz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND cd gettext-runtime && ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make -C gettext-runtime + INSTALL_COMMAND ${CMD} make -C gettext-runtime install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS ${gettext_DEPENDS} +) + +######### +## libpng +######### + +ExternalProject_Add (libpng_Project + URL http://prdownloads.sourceforge.net/libpng/libpng-1.6.28.tar.xz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS zlib_Project +) + +######### +## FFmpeg +######### + +ExternalProject_Add (FFmpeg_Project + URL http://www.ffmpeg.org/releases/ffmpeg-3.2.4.tar.xz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --disable-iconv + --disable-programs + --disable-doc + --disable-yasm + --disable-avdevice + --disable-avfilter + --disable-network + --disable-everything + --enable-decoder=cinepak,msvideo1,vorbis + --enable-demuxer=matroska + --enable-protocol=file + --disable-crystalhd + --disable-xvmc + --disable-vaapi + --disable-videotoolbox + --disable-vdpau + --disable-vda + --disable-nvenc + --disable-dxva2 + --disable-d3d11va + --disable-audiotoolbox + --disable-zlib + --disable-bzlib + --disable-lzma + --disable-xlib + --disable-sdl2 + --disable-libxcb + --disable-libxcb-shm + --disable-libxcb-xfixes + --disable-libxcb-shape + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} +) + +############ +## libasound +############ + +if (UNIX AND NOT APPLE AND NOT ANDROID) + ExternalProject_Add (libasound_Project + URL ftp://ftp.alsa-project.org/pub/lib/alsa-lib-1.1.4.1.tar.bz2 + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --disable-old-symbols + --disable-python + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + ) +endif () + +########### +## libpulse +########### + +if (UNIX AND NOT APPLE AND NOT ANDROID) + ExternalProject_Add (libpulse_Project + URL https://freedesktop.org/software/pulseaudio/releases/pulseaudio-11.0.tar.xz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --enable-alsa + --disable-nls + --disable-x11 + --disable-tests + --disable-esound + --disable-waveout + --disable-gconf + --disable-glib2 + --disable-gtk3 + --disable-jack + --disable-asyncns + --disable-avahi + --disable-openssl + --disable-tcpwrap + --disable-lirc + --disable-dbus + --disable-udev + --disable-bluez4 + --disable-bluez5 + --disable-hal-compat + --disable-ipv6 + --disable-webrtc-aec + --disable-systemd-daemon + --disable-systemd-login + --disable-systemd-journal + --disable-manpages + --disable-default-build-tests + --disable-legacy-database-entry-format + --enable-static-bins + --without-caps + --without-fftw + --without-speex + --without-soxr + --with-database=simple + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install INSTALLDIR=${CMAKE_BINARY_DIR} + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS libasound_Project + ) +endif () + +####### +## SDL2 +####### + +if (UNIX AND NOT APPLE AND NOT ANDROID) + set (SDL2_CONFIGURE --enable-video-x11 + --enable-x11-shared + --enable-video-wayland + --enable-wayland-shared + --enable-video-opengl + --enable-oss + --enable-alsa + --disable-alsa-shared + --disable-sndio + --disable-sndio-shared + --enable-pulseaudio + --disable-pulseaudio-shared) +elseif (MINGW) + set (SDL2_CONFIGURE --enable-directx + --enable-render-d3d + --enable-video-opengl) +elseif (APPLE) + set (SDL2_CONFIGURE --enable-video-opengl + --enable-video-cocoa) +elseif (ANDROID) + set (SDL2_CONFIGURE --disable-video-x11 + --disable-video-wayland + --disable-video-mir + --disable-oss + --disable-alsa + --disable-sndio + --disable-pulseaudio) +endif () + +set (SDL2_DEPENDS zlib_Project) +if (UNIX AND NOT APPLE AND NOT ANDROID) + set (SDL2_DEPENDS ${SDL2_DEPENDS} libasound_Project libpulse_Project) +endif () + +ExternalProject_Add (SDL2_Project + URL http://hg.libsdl.org/SDL/archive/3d0bbfe683a8.tar.bz2 + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${ADDITIONAL_TOOL_OPTIONS} ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --disable-joystick + --disable-haptic + ${SDL2_CONFIGURE} + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS ${SDL2_DEPENDS} +) + +############# +## SDL2_image +############# + +ExternalProject_Add (SDL2_image_Project + URL https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.1.tar.gz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --disable-sdl-test + --disable-bmp + --disable-gif + --disable-jpg + --disable-jpg-shared + --disable-lbm + --disable-pcx + --enable-png + --disable-png-shared + --disable-pnm + --disable-tga + --disable-tif + --disable-tif-shared + --disable-xcf + --disable-xpm + --disable-xv + --disable-webp + --disable-webp-shared + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS SDL2_Project libpng_Project +) + +############# +## SDL2_mixer +############# + +set (SDL2_mixer_DEPENDS SDL2_Project) +if (NOT APPLE) + set (SDL2_mixer_DEPENDS ${SDL2_mixer_DEPENDS} libiconv_Project) +endif () + +ExternalProject_Add (SDL2_mixer_Project + URL https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.1.tar.gz + PREFIX ${CMAKE_BINARY_DIR} + CONFIGURE_COMMAND ${CMD} ./configure + --prefix=${CMAKE_BINARY_DIR} + --disable-shared + --enable-static + --disable-sdltest + --disable-music-cmd + --enable-music-wave + --disable-music-mod + --disable-music-mod-modplug + --disable-music-mod-modplug-shared + --disable-music-mod-mikmod + --disable-music-mod-mikmod-shared + --enable-music-midi + --enable-music-midi-timidity + --enable-music-midi-native + --disable-music-midi-fluidsynth + --disable-music-midi-fluidsynth-shared + --disable-music-ogg + --disable-music-ogg-tremor + --disable-music-ogg-shared + --disable-music-flac + --disable-music-flac-shared + --disable-music-mp3 + --disable-music-mp3-smpeg + --disable-music-mp3-smpeg-shared + --disable-smpegtest + --disable-music-mp3-mad-gpl + ${ADDITIONAL_CONFIGURE_OPTIONS} + BUILD_COMMAND ${CMD} make + INSTALL_COMMAND ${CMD} make install + BUILD_IN_SOURCE 1 + INSTALL_DIR ${CMAKE_BINARY_DIR} + DEPENDS ${SDL2_mixer_DEPENDS} +) + +################## +## SDL_kitchensink +################## + +ExternalProject_Add (SDL_kitchensink_Project + URL ${CMAKE_SOURCE_DIR}/SDL_kitchensink + DOWNLOAD_COMMAND "" + SOURCE_DIR ${CMAKE_SOURCE_DIR}/SDL_kitchensink + PREFIX ${CMAKE_BINARY_DIR} + CMAKE_COMMAND ${CMD} cmake + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= ${ADDITIONAL_CMAKE_OPTIONS} + INSTALL_DIR ${CMAKE_BINARY_DIR} + BUILD_ALWAYS 1 + DEPENDS SDL2_Project FFmpeg_Project +) + +############## +## planetblupi +############## + +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + set (APPIMAGE_APPRUN_BIN "AppRun-x86_64") + set (APPIMAGE_APPRUN_URL "https://github.com/probonopd/AppImageKit/releases/download/continuous/${APPIMAGE_APPRUN_BIN}") + set (APPIMAGE_APPRUN_PROGRAM "${CMAKE_BINARY_DIR}/bin/${APPIMAGE_APPRUN_BIN}") + + set (APPIMAGE_TOOL_BIN "appimagetool-x86_64.AppImage") + set (APPIMAGE_TOOL_URL "https://github.com/probonopd/AppImageKit/releases/download/continuous/${APPIMAGE_TOOL_BIN}") + set (APPIMAGE_TOOL_PROGRAM "${CMAKE_BINARY_DIR}/bin/${APPIMAGE_TOOL_BIN}") + + if (NOT EXISTS "${APPIMAGE_APPRUN_PROGRAM}") + file (DOWNLOAD "${APPIMAGE_APPRUN_URL}" "${APPIMAGE_APPRUN_PROGRAM}") + endif () + + if (NOT EXISTS "${APPIMAGE_TOOL_PROGRAM}") + file (DOWNLOAD "${APPIMAGE_TOOL_URL}" "${APPIMAGE_TOOL_PROGRAM}") + endif () + + execute_process (COMMAND /bin/chmod 0755 "${APPIMAGE_APPRUN_PROGRAM}") + execute_process (COMMAND /bin/chmod 0755 "${APPIMAGE_TOOL_PROGRAM}") +endif () + +set (planetblupi_DEPS + argagg_Project + libcurl_Project + SDL2_Project + SDL2_image_Project + SDL2_mixer_Project + SDL_kitchensink_Project + libpng_Project + gettext_Project +) +if (UNIX AND NOT APPLE AND NOT ANDROID) + list (APPEND planetblupi_DEPS libasound_Project libpulse_Project) +endif () + +ExternalProject_Add (planetblupi_Project + URL ${CMAKE_SOURCE_DIR}/planetblupi + DOWNLOAD_COMMAND "" + SOURCE_DIR ${CMAKE_SOURCE_DIR}/planetblupi + PREFIX ${CMAKE_BINARY_DIR} + CMAKE_COMMAND ${CMD} cmake + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DAPPIMAGE_APPRUN_PROGRAM=${APPIMAGE_APPRUN_PROGRAM} + -DAPPIMAGE_ASSISTANT_PROGRAM=${APPIMAGE_TOOL_PROGRAM} + -DCMAKE_INSTALL_PREFIX:PATH= + -DSTATIC_BUILD=${STATIC_BUILD} + -DSIGN_APP=${SIGN_APP} + -DANDROID=${ANDROID} + ${ADDITIONAL_CMAKE_OPTIONS} + INSTALL_DIR ${CMAKE_BINARY_DIR} + BUILD_ALWAYS 1 + DEPENDS ${planetblupi_DEPS} +) + +if (ANDROID) + find_package (PkgConfig REQUIRED) + pkg_search_module (SDL2 REQUIRED sdl2) + add_library(main SHARED android/SDL_android_main.c) + #add_dependencies(main planetblupi_Project SDL2_Project) + add_dependencies(main SDL2_Project) + #target_link_libraries (main PUBLIC ${CMAKE_BINARY_DIR}/bin/libplanetblupi.a) + target_link_libraries(main PUBLIC ${SDL2_STATIC_LIBRARIES}) +endif () + +add_custom_target (dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) + +set (CPACK_SOURCE_GENERATOR "TBZ2") +set (CPACK_SOURCE_PACKAGE_FILE_NAME "planetblupi-dev") +set (CPACK_SOURCE_IGNORE_FILES "/build/;/Debug/;/Release/;/.git/;~$;${CPACK_SOURCE_IGNORE_FILES}") +include (CPack) \ No newline at end of file diff --git a/MyApplication/.gitignore b/MyApplication/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/MyApplication/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/MyApplication/.idea/compiler.xml b/MyApplication/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/MyApplication/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyApplication/.idea/copyright/profiles_settings.xml b/MyApplication/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/MyApplication/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/MyApplication/.idea/gradle.xml b/MyApplication/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/MyApplication/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/MyApplication/.idea/misc.xml b/MyApplication/.idea/misc.xml new file mode 100644 index 0000000..7158618 --- /dev/null +++ b/MyApplication/.idea/misc.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.8 + + + + + + + + \ No newline at end of file diff --git a/MyApplication/.idea/modules.xml b/MyApplication/.idea/modules.xml new file mode 100644 index 0000000..54b7b3f --- /dev/null +++ b/MyApplication/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/MyApplication/.idea/runConfigurations.xml b/MyApplication/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/MyApplication/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/MyApplication/app/.gitignore b/MyApplication/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/MyApplication/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/MyApplication/app/CMakeLists.txt b/MyApplication/app/CMakeLists.txt new file mode 100644 index 0000000..ea96606 --- /dev/null +++ b/MyApplication/app/CMakeLists.txt @@ -0,0 +1,45 @@ +# Sets the minimum version of CMake required to build the native +# library. You should either keep the default value or only pass a +# value of 3.4.0 or lower. + +cmake_minimum_required(VERSION 3.4.1) + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds it for you. +# Gradle automatically packages shared libraries with your APK. + +add_library( # Sets the name of the library. + native-lib + + # Sets the library as a shared library. + SHARED + + # Provides a relative path to your source file(s). + # Associated headers in the same location as their source + # file are automatically included. + src/main/cpp/native-lib.cpp ) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because system libraries are included in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +find_library( # Sets the name of the path variable. + log-lib + + # Specifies the name of the NDK library that + # you want CMake to locate. + log ) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in the +# build script, prebuilt third-party libraries, or system libraries. + +target_link_libraries( # Specifies the target library. + native-lib + + # Links the target library to the log library + # included in the NDK. + ${log-lib} ) diff --git a/MyApplication/app/build.gradle b/MyApplication/app/build.gradle new file mode 100644 index 0000000..f246b37 --- /dev/null +++ b/MyApplication/app/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "25.0.0" + defaultConfig { + applicationId "pl.krzysh.myapplication" + minSdkVersion 19 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + cppFlags "" + arguments "-DANDROID_STL=c++_static" + } + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:23.4.0' + testCompile 'junit:junit:4.12' +} diff --git a/MyApplication/app/proguard-rules.pro b/MyApplication/app/proguard-rules.pro new file mode 100644 index 0000000..45dc58a --- /dev/null +++ b/MyApplication/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /opt/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/MyApplication/app/src/androidTest/java/pl/krzysh/myapplication/ExampleInstrumentedTest.java b/MyApplication/app/src/androidTest/java/pl/krzysh/myapplication/ExampleInstrumentedTest.java new file mode 100644 index 0000000..878597a --- /dev/null +++ b/MyApplication/app/src/androidTest/java/pl/krzysh/myapplication/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package pl.krzysh.myapplication; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("pl.krzysh.myapplication", appContext.getPackageName()); + } +} diff --git a/MyApplication/app/src/main/AndroidManifest.xml b/MyApplication/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b40027e --- /dev/null +++ b/MyApplication/app/src/main/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyApplication/app/src/main/cpp/native-lib.cpp b/MyApplication/app/src/main/cpp/native-lib.cpp new file mode 100644 index 0000000..2373412 --- /dev/null +++ b/MyApplication/app/src/main/cpp/native-lib.cpp @@ -0,0 +1,11 @@ +#include +#include + +extern "C" +jstring +Java_pl_krzysh_myapplication_MainActivity_stringFromJNI( + JNIEnv *env, + jobject /* this */) { + std::string hello = "Hello from C++"; + return env->NewStringUTF(hello.c_str()); +} diff --git a/MyApplication/app/src/main/java/pl/krzysh/myapplication/MainActivity.java b/MyApplication/app/src/main/java/pl/krzysh/myapplication/MainActivity.java new file mode 100644 index 0000000..aa1f152 --- /dev/null +++ b/MyApplication/app/src/main/java/pl/krzysh/myapplication/MainActivity.java @@ -0,0 +1,29 @@ +package pl.krzysh.myapplication; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.widget.TextView; + +public class MainActivity extends AppCompatActivity { + + // Used to load the 'native-lib' library on application startup. + static { + System.loadLibrary("native-lib"); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Example of a call to a native method + TextView tv = (TextView) findViewById(R.id.sample_text); + tv.setText(stringFromJNI()); + } + + /** + * A native method that is implemented by the 'native-lib' native library, + * which is packaged with this application. + */ + public native String stringFromJNI(); +} diff --git a/MyApplication/app/src/main/res/layout/activity_main.xml b/MyApplication/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..250de37 --- /dev/null +++ b/MyApplication/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/MyApplication/app/src/main/res/mipmap-hdpi/ic_launcher.png b/MyApplication/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..cde69bc Binary files /dev/null and b/MyApplication/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/MyApplication/app/src/main/res/mipmap-mdpi/ic_launcher.png b/MyApplication/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..c133a0c Binary files /dev/null and b/MyApplication/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/MyApplication/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/MyApplication/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..bfa42f0 Binary files /dev/null and b/MyApplication/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/MyApplication/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/MyApplication/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..324e72c Binary files /dev/null and b/MyApplication/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/MyApplication/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/MyApplication/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..aee44e1 Binary files /dev/null and b/MyApplication/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/MyApplication/app/src/main/res/values-w820dp/dimens.xml b/MyApplication/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/MyApplication/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/MyApplication/app/src/main/res/values/colors.xml b/MyApplication/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..3ab3e9c --- /dev/null +++ b/MyApplication/app/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/MyApplication/app/src/main/res/values/dimens.xml b/MyApplication/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..47c8224 --- /dev/null +++ b/MyApplication/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/MyApplication/app/src/main/res/values/strings.xml b/MyApplication/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..efd3073 --- /dev/null +++ b/MyApplication/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + My Application + diff --git a/MyApplication/app/src/main/res/values/styles.xml b/MyApplication/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..5885930 --- /dev/null +++ b/MyApplication/app/src/main/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/MyApplication/app/src/test/java/pl/krzysh/myapplication/ExampleUnitTest.java b/MyApplication/app/src/test/java/pl/krzysh/myapplication/ExampleUnitTest.java new file mode 100644 index 0000000..4647c1d --- /dev/null +++ b/MyApplication/app/src/test/java/pl/krzysh/myapplication/ExampleUnitTest.java @@ -0,0 +1,17 @@ +package pl.krzysh.myapplication; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test + public void addition_isCorrect() throws Exception { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/MyApplication/build.gradle b/MyApplication/build.gradle new file mode 100644 index 0000000..c20bca1 --- /dev/null +++ b/MyApplication/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:2.2.2' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/MyApplication/gradle.properties b/MyApplication/gradle.properties new file mode 100644 index 0000000..aac7c9b --- /dev/null +++ b/MyApplication/gradle.properties @@ -0,0 +1,17 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true diff --git a/MyApplication/gradle/wrapper/gradle-wrapper.jar b/MyApplication/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..13372ae Binary files /dev/null and b/MyApplication/gradle/wrapper/gradle-wrapper.jar differ diff --git a/MyApplication/gradle/wrapper/gradle-wrapper.properties b/MyApplication/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..04e285f --- /dev/null +++ b/MyApplication/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Dec 28 10:00:20 PST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip diff --git a/MyApplication/gradlew b/MyApplication/gradlew new file mode 100755 index 0000000..9d82f78 --- /dev/null +++ b/MyApplication/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/MyApplication/gradlew.bat b/MyApplication/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/MyApplication/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/MyApplication/settings.gradle b/MyApplication/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/MyApplication/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/android/.idea/compiler.xml b/android/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/android/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/copyright/profiles_settings.xml b/android/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/android/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/android/.idea/gradle.xml b/android/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/android/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/android/.idea/misc.xml b/android/.idea/misc.xml new file mode 100644 index 0000000..7158618 --- /dev/null +++ b/android/.idea/misc.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.8 + + + + + + + + \ No newline at end of file diff --git a/android/.idea/modules.xml b/android/.idea/modules.xml new file mode 100644 index 0000000..abc31fc --- /dev/null +++ b/android/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/.idea/runConfigurations.xml b/android/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/android/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/android/SDL_android_main.c b/android/SDL_android_main.c new file mode 100644 index 0000000..7674206 --- /dev/null +++ b/android/SDL_android_main.c @@ -0,0 +1,84 @@ +/* + SDL_android_main.c, placed in the public domain by Sam Lantinga 3/13/14 +*/ +//#include "../../SDL_internal.h" + +#ifdef __ANDROID__ + +/* Include the SDL main definition header */ +//#include "SDL_main.h" +#include + +/******************************************************************************* + Functions called by JNI +*******************************************************************************/ +#include + +/* Called before SDL_main() to initialize JNI bindings in SDL library */ +extern void SDL_Android_Init(JNIEnv* env, jclass cls); + +/* This prototype is needed to prevent a warning about the missing prototype for global function below */ +JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array); + +/* Start up the SDL app */ +JNIEXPORT int JNICALL Java_org_libsdl_app_SDLActivity_nativeInit(JNIEnv* env, jclass cls, jobject array) +{ + int i; + int argc; + int status; + int len; + char** argv; + + /* This interface could expand with ABI negotiation, callbacks, etc. */ + SDL_Android_Init(env, cls); + + SDL_SetMainReady(); + + /* Prepare the arguments. */ + + len = (*env)->GetArrayLength(env, array); + argv = SDL_stack_alloc(char*, 1 + len + 1); + argc = 0; + /* Use the name "app_process" so PHYSFS_platformCalcBaseDir() works. + https://bitbucket.org/MartinFelis/love-android-sdl2/issue/23/release-build-crash-on-start + */ + argv[argc++] = SDL_strdup("app_process"); + for (i = 0; i < len; ++i) { + const char* utf; + char* arg = NULL; + jstring string = (*env)->GetObjectArrayElement(env, array, i); + if (string) { + utf = (*env)->GetStringUTFChars(env, string, 0); + if (utf) { + arg = SDL_strdup(utf); + (*env)->ReleaseStringUTFChars(env, string, utf); + } + (*env)->DeleteLocalRef(env, string); + } + if (!arg) { + arg = SDL_strdup(""); + } + argv[argc++] = arg; + } + argv[argc] = NULL; + + + /* Run the application. */ + + status = SDL_main(argc, argv); + + /* Release the arguments. */ + + for (i = 0; i < argc; ++i) { + SDL_free(argv[i]); + } + SDL_stack_free(argv); + /* Do not issue an exit or the whole application will terminate instead of just the SDL thread */ + /* exit(status); */ + + return status; +} + +#endif /* __ANDROID__ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/android/app/.gitignore b/android/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/android/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt new file mode 100644 index 0000000..a826843 --- /dev/null +++ b/android/app/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.4.1) +add_library(main SHARED src/main/cpp/SDL_android_main.c) +target_link_libraries(main libplanetblupi.a`) diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..8f59af0 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 23 + buildToolsVersion "25.0.0" + defaultConfig { + applicationId "org.libsdl.app" + minSdkVersion 19 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + externalNativeBuild { + cmake { + //cppFlags "-std=c++11 -frtti -fexceptions" + arguments "-DANDROID=TRUE", "-DANDROID_STL=c++_static" + } + } + ndk { + abiFilters 'armeabi' + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + externalNativeBuild { + cmake { + path "../../CMakeLists.txt" + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:23.4.0' + testCompile 'junit:junit:4.12' +} diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..45dc58a --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /opt/android-sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/android/app/src/androidTest/java/org/libsdl/app/ExampleInstrumentedTest.java b/android/app/src/androidTest/java/org/libsdl/app/ExampleInstrumentedTest.java new file mode 100644 index 0000000..4cab5e1 --- /dev/null +++ b/android/app/src/androidTest/java/org/libsdl/app/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package org.libsdl.app; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("org.libsdl.app", appContext.getPackageName()); + } +} diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..8557a4b --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/AndroidManifest.xml.bkp b/android/app/src/main/AndroidManifest.xml.bkp new file mode 100644 index 0000000..6c297a4 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml.bkp @@ -0,0 +1,12 @@ + + + + + + + diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java new file mode 100644 index 0000000..d23d740 --- /dev/null +++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -0,0 +1,1742 @@ +package org.libsdl.app; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.lang.reflect.Method; + +import android.app.*; +import android.content.*; +import android.text.InputType; +import android.view.*; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InputMethodManager; +import android.widget.RelativeLayout; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.os.*; +import android.util.Log; +import android.util.SparseArray; +import android.graphics.*; +import android.graphics.drawable.Drawable; +import android.media.*; +import android.hardware.*; +import android.content.pm.ActivityInfo; + +/** + SDL Activity +*/ +public class SDLActivity extends Activity { + private static final String TAG = "SDL"; + + // Keep track of the paused state + public static boolean mIsPaused, mIsSurfaceReady, mHasFocus; + public static boolean mExitCalledFromJava; + + /** If shared libraries (e.g. SDL or the native application) could not be loaded. */ + public static boolean mBrokenLibraries; + + // If we want to separate mouse and touch events. + // This is only toggled in native code when a hint is set! + public static boolean mSeparateMouseAndTouch; + + // Main components + protected static SDLActivity mSingleton; + protected static SDLSurface mSurface; + protected static View mTextEdit; + protected static ViewGroup mLayout; + protected static SDLJoystickHandler mJoystickHandler; + + // This is what SDL runs in. It invokes SDL_main(), eventually + protected static Thread mSDLThread; + + // Audio + protected static AudioTrack mAudioTrack; + protected static AudioRecord mAudioRecord; + + /** + * This method is called by SDL before loading the native shared libraries. + * It can be overridden to provide names of shared libraries to be loaded. + * The default implementation returns the defaults. It never returns null. + * An array returned by a new implementation must at least contain "SDL2". + * Also keep in mind that the order the libraries are loaded may matter. + * @return names of shared libraries to be loaded (e.g. "SDL2", "main"). + */ + protected String[] getLibraries() { + return new String[] { + // "SDL2", + // "SDL2_image", + // "SDL2_mixer", + // "SDL2_net", + // "SDL2_ttf", + "main" + }; + } + + // Load the .so + public void loadLibraries() { + for (String lib : getLibraries()) { + System.loadLibrary(lib); + } + } + + /** + * This method is called by SDL before starting the native application thread. + * It can be overridden to provide the arguments after the application name. + * The default implementation returns an empty array. It never returns null. + * @return arguments for the native application. + */ + protected String[] getArguments() { + return new String[0]; + } + + public static void initialize() { + // The static nature of the singleton and Android quirkyness force us to initialize everything here + // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values + mSingleton = null; + mSurface = null; + mTextEdit = null; + mLayout = null; + mJoystickHandler = null; + mSDLThread = null; + mAudioTrack = null; + mAudioRecord = null; + mExitCalledFromJava = false; + mBrokenLibraries = false; + mIsPaused = false; + mIsSurfaceReady = false; + mHasFocus = true; + } + + // Setup + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.v(TAG, "Device: " + android.os.Build.DEVICE); + Log.v(TAG, "Model: " + android.os.Build.MODEL); + Log.v(TAG, "onCreate(): " + mSingleton); + super.onCreate(savedInstanceState); + + SDLActivity.initialize(); + // So we can call stuff from static callbacks + mSingleton = this; + + // Load shared libraries + String errorMsgBrokenLib = ""; + try { + loadLibraries(); + } catch(UnsatisfiedLinkError e) { + System.err.println(e.getMessage()); + mBrokenLibraries = true; + errorMsgBrokenLib = e.getMessage(); + } catch(Exception e) { + System.err.println(e.getMessage()); + mBrokenLibraries = true; + errorMsgBrokenLib = e.getMessage(); + } + + if (mBrokenLibraries) + { + AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this); + dlgAlert.setMessage("An error occurred while trying to start the application. Please try again and/or reinstall." + + System.getProperty("line.separator") + + System.getProperty("line.separator") + + "Error: " + errorMsgBrokenLib); + dlgAlert.setTitle("SDL Error"); + dlgAlert.setPositiveButton("Exit", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog,int id) { + // if this button is clicked, close current activity + SDLActivity.mSingleton.finish(); + } + }); + dlgAlert.setCancelable(false); + dlgAlert.create().show(); + + return; + } + + // Set up the surface + mSurface = new SDLSurface(getApplication()); + + if(Build.VERSION.SDK_INT >= 12) { + mJoystickHandler = new SDLJoystickHandler_API12(); + } + else { + mJoystickHandler = new SDLJoystickHandler(); + } + + mLayout = new RelativeLayout(this); + mLayout.addView(mSurface); + + setContentView(mLayout); + + // Get filename from "Open with" of another application + Intent intent = getIntent(); + + if (intent != null && intent.getData() != null) { + String filename = intent.getData().getPath(); + if (filename != null) { + Log.v(TAG, "Got filename: " + filename); + SDLActivity.onNativeDropFile(filename); + } + } + } + + // Events + @Override + protected void onPause() { + Log.v(TAG, "onPause()"); + super.onPause(); + + if (SDLActivity.mBrokenLibraries) { + return; + } + + SDLActivity.handlePause(); + } + + @Override + protected void onResume() { + Log.v(TAG, "onResume()"); + super.onResume(); + + if (SDLActivity.mBrokenLibraries) { + return; + } + + SDLActivity.handleResume(); + } + + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + Log.v(TAG, "onWindowFocusChanged(): " + hasFocus); + + if (SDLActivity.mBrokenLibraries) { + return; + } + + SDLActivity.mHasFocus = hasFocus; + if (hasFocus) { + SDLActivity.handleResume(); + } + } + + @Override + public void onLowMemory() { + Log.v(TAG, "onLowMemory()"); + super.onLowMemory(); + + if (SDLActivity.mBrokenLibraries) { + return; + } + + SDLActivity.nativeLowMemory(); + } + + @Override + protected void onDestroy() { + Log.v(TAG, "onDestroy()"); + + if (SDLActivity.mBrokenLibraries) { + super.onDestroy(); + // Reset everything in case the user re opens the app + SDLActivity.initialize(); + return; + } + + // Send a quit message to the application + SDLActivity.mExitCalledFromJava = true; + SDLActivity.nativeQuit(); + + // Now wait for the SDL thread to quit + if (SDLActivity.mSDLThread != null) { + try { + SDLActivity.mSDLThread.join(); + } catch(Exception e) { + Log.v(TAG, "Problem stopping thread: " + e); + } + SDLActivity.mSDLThread = null; + + //Log.v(TAG, "Finished waiting for SDL thread"); + } + + super.onDestroy(); + // Reset everything in case the user re opens the app + SDLActivity.initialize(); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + + if (SDLActivity.mBrokenLibraries) { + return false; + } + + int keyCode = event.getKeyCode(); + // Ignore certain special keys so they're handled by Android + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || + keyCode == KeyEvent.KEYCODE_VOLUME_UP || + keyCode == KeyEvent.KEYCODE_CAMERA || + keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */ + keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */ + ) { + return false; + } + return super.dispatchKeyEvent(event); + } + + /** Called by onPause or surfaceDestroyed. Even if surfaceDestroyed + * is the first to be called, mIsSurfaceReady should still be set + * to 'true' during the call to onPause (in a usual scenario). + */ + public static void handlePause() { + if (!SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) { + SDLActivity.mIsPaused = true; + SDLActivity.nativePause(); + mSurface.handlePause(); + } + } + + /** Called by onResume or surfaceCreated. An actual resume should be done only when the surface is ready. + * Note: Some Android variants may send multiple surfaceChanged events, so we don't need to resume + * every time we get one of those events, only if it comes after surfaceDestroyed + */ + public static void handleResume() { + if (SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady && SDLActivity.mHasFocus) { + SDLActivity.mIsPaused = false; + SDLActivity.nativeResume(); + mSurface.handleResume(); + } + } + + /* The native thread has finished */ + public static void handleNativeExit() { + SDLActivity.mSDLThread = null; + mSingleton.finish(); + } + + + // Messages from the SDLMain thread + static final int COMMAND_CHANGE_TITLE = 1; + static final int COMMAND_UNUSED = 2; + static final int COMMAND_TEXTEDIT_HIDE = 3; + static final int COMMAND_SET_KEEP_SCREEN_ON = 5; + + protected static final int COMMAND_USER = 0x8000; + + /** + * This method is called by SDL if SDL did not handle a message itself. + * This happens if a received message contains an unsupported command. + * Method can be overwritten to handle Messages in a different class. + * @param command the command of the message. + * @param param the parameter of the message. May be null. + * @return if the message was handled in overridden method. + */ + protected boolean onUnhandledMessage(int command, Object param) { + return false; + } + + /** + * A Handler class for Messages from native SDL applications. + * It uses current Activities as target (e.g. for the title). + * static to prevent implicit references to enclosing object. + */ + protected static class SDLCommandHandler extends Handler { + @Override + public void handleMessage(Message msg) { + Context context = getContext(); + if (context == null) { + Log.e(TAG, "error handling message, getContext() returned null"); + return; + } + switch (msg.arg1) { + case COMMAND_CHANGE_TITLE: + if (context instanceof Activity) { + ((Activity) context).setTitle((String)msg.obj); + } else { + Log.e(TAG, "error handling message, getContext() returned no Activity"); + } + break; + case COMMAND_TEXTEDIT_HIDE: + if (mTextEdit != null) { + // Note: On some devices setting view to GONE creates a flicker in landscape. + // Setting the View's sizes to 0 is similar to GONE but without the flicker. + // The sizes will be set to useful values when the keyboard is shown again. + mTextEdit.setLayoutParams(new RelativeLayout.LayoutParams(0, 0)); + + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0); + } + break; + case COMMAND_SET_KEEP_SCREEN_ON: + { + Window window = ((Activity) context).getWindow(); + if (window != null) { + if ((msg.obj instanceof Integer) && (((Integer) msg.obj).intValue() != 0)) { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + } + break; + } + default: + if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) { + Log.e(TAG, "error handling message, command is " + msg.arg1); + } + } + } + } + + // Handler for the messages + Handler commandHandler = new SDLCommandHandler(); + + // Send a message from the SDLMain thread + boolean sendCommand(int command, Object data) { + Message msg = commandHandler.obtainMessage(); + msg.arg1 = command; + msg.obj = data; + return commandHandler.sendMessage(msg); + } + + // C functions we call + public static native int nativeInit(Object arguments); + public static native void nativeLowMemory(); + public static native void nativeQuit(); + public static native void nativePause(); + public static native void nativeResume(); + public static native void onNativeDropFile(String filename); + public static native void onNativeResize(int x, int y, int format, float rate); + public static native int onNativePadDown(int device_id, int keycode); + public static native int onNativePadUp(int device_id, int keycode); + public static native void onNativeJoy(int device_id, int axis, + float value); + public static native void onNativeHat(int device_id, int hat_id, + int x, int y); + public static native void onNativeKeyDown(int keycode); + public static native void onNativeKeyUp(int keycode); + public static native void onNativeKeyboardFocusLost(); + public static native void onNativeMouse(int button, int action, float x, float y); + public static native void onNativeTouch(int touchDevId, int pointerFingerId, + int action, float x, + float y, float p); + public static native void onNativeAccel(float x, float y, float z); + public static native void onNativeSurfaceChanged(); + public static native void onNativeSurfaceDestroyed(); + public static native int nativeAddJoystick(int device_id, String name, + int is_accelerometer, int nbuttons, + int naxes, int nhats, int nballs); + public static native int nativeRemoveJoystick(int device_id); + public static native String nativeGetHint(String name); + + /** + * This method is called by SDL using JNI. + */ + public static boolean setActivityTitle(String title) { + // Called from SDLMain() thread and can't directly affect the view + return mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title); + } + + /** + * This method is called by SDL using JNI. + */ + public static boolean sendMessage(int command, int param) { + return mSingleton.sendCommand(command, Integer.valueOf(param)); + } + + /** + * This method is called by SDL using JNI. + */ + public static Context getContext() { + return mSingleton; + } + + /** + * This method is called by SDL using JNI. + * @return result of getSystemService(name) but executed on UI thread. + */ + public Object getSystemServiceFromUiThread(final String name) { + final Object lock = new Object(); + final Object[] results = new Object[2]; // array for writable variables + synchronized (lock) { + runOnUiThread(new Runnable() { + @Override + public void run() { + synchronized (lock) { + results[0] = getSystemService(name); + results[1] = Boolean.TRUE; + lock.notify(); + } + } + }); + if (results[1] == null) { + try { + lock.wait(); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + } + return results[0]; + } + + static class ShowTextInputTask implements Runnable { + /* + * This is used to regulate the pan&scan method to have some offset from + * the bottom edge of the input region and the top edge of an input + * method (soft keyboard) + */ + static final int HEIGHT_PADDING = 15; + + public int x, y, w, h; + + public ShowTextInputTask(int x, int y, int w, int h) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + + @Override + public void run() { + RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w, h + HEIGHT_PADDING); + params.leftMargin = x; + params.topMargin = y; + + if (mTextEdit == null) { + mTextEdit = new DummyEdit(getContext()); + + mLayout.addView(mTextEdit, params); + } else { + mTextEdit.setLayoutParams(params); + } + + mTextEdit.setVisibility(View.VISIBLE); + mTextEdit.requestFocus(); + + InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(mTextEdit, 0); + } + } + + /** + * This method is called by SDL using JNI. + */ + public static boolean showTextInput(int x, int y, int w, int h) { + // Transfer the task to the main thread as a Runnable + return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h)); + } + + /** + * This method is called by SDL using JNI. + */ + public static Surface getNativeSurface() { + return SDLActivity.mSurface.getNativeSurface(); + } + + // Audio + + /** + * This method is called by SDL using JNI. + */ + public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { + int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; + int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; + int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); + + Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); + + // Let the user pick a larger buffer if they really want -- but ye + // gods they probably shouldn't, the minimums are horrifyingly high + // latency already + desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); + + if (mAudioTrack == null) { + mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, + channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); + + // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid + // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java + // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState() + + if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) { + Log.e(TAG, "Failed during initialization of Audio Track"); + mAudioTrack = null; + return -1; + } + + mAudioTrack.play(); + } + + Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); + + return 0; + } + + /** + * This method is called by SDL using JNI. + */ + public static void audioWriteShortBuffer(short[] buffer) { + for (int i = 0; i < buffer.length; ) { + int result = mAudioTrack.write(buffer, i, buffer.length - i); + if (result > 0) { + i += result; + } else if (result == 0) { + try { + Thread.sleep(1); + } catch(InterruptedException e) { + // Nom nom + } + } else { + Log.w(TAG, "SDL audio: error return from write(short)"); + return; + } + } + } + + /** + * This method is called by SDL using JNI. + */ + public static void audioWriteByteBuffer(byte[] buffer) { + for (int i = 0; i < buffer.length; ) { + int result = mAudioTrack.write(buffer, i, buffer.length - i); + if (result > 0) { + i += result; + } else if (result == 0) { + try { + Thread.sleep(1); + } catch(InterruptedException e) { + // Nom nom + } + } else { + Log.w(TAG, "SDL audio: error return from write(byte)"); + return; + } + } + } + + /** + * This method is called by SDL using JNI. + */ + public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) { + int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO; + int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT; + int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1); + + Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); + + // Let the user pick a larger buffer if they really want -- but ye + // gods they probably shouldn't, the minimums are horrifyingly high + // latency already + desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); + + if (mAudioRecord == null) { + mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate, + channelConfig, audioFormat, desiredFrames * frameSize); + + // see notes about AudioTrack state in audioOpen(), above. Probably also applies here. + if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) { + Log.e(TAG, "Failed during initialization of AudioRecord"); + mAudioRecord.release(); + mAudioRecord = null; + return -1; + } + + mAudioRecord.startRecording(); + } + + Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); + + return 0; + } + + /** This method is called by SDL using JNI. */ + public static int captureReadShortBuffer(short[] buffer, boolean blocking) { + // !!! FIXME: this is available in API Level 23. Until then, we always block. :( + //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING); + return mAudioRecord.read(buffer, 0, buffer.length); + } + + /** This method is called by SDL using JNI. */ + public static int captureReadByteBuffer(byte[] buffer, boolean blocking) { + // !!! FIXME: this is available in API Level 23. Until then, we always block. :( + //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING); + return mAudioRecord.read(buffer, 0, buffer.length); + } + + + /** This method is called by SDL using JNI. */ + public static void audioClose() { + if (mAudioTrack != null) { + mAudioTrack.stop(); + mAudioTrack.release(); + mAudioTrack = null; + } + } + + /** This method is called by SDL using JNI. */ + public static void captureClose() { + if (mAudioRecord != null) { + mAudioRecord.stop(); + mAudioRecord.release(); + mAudioRecord = null; + } + } + + + // Input + + /** + * This method is called by SDL using JNI. + * @return an array which may be empty but is never null. + */ + public static int[] inputGetInputDeviceIds(int sources) { + int[] ids = InputDevice.getDeviceIds(); + int[] filtered = new int[ids.length]; + int used = 0; + for (int i = 0; i < ids.length; ++i) { + InputDevice device = InputDevice.getDevice(ids[i]); + if ((device != null) && ((device.getSources() & sources) != 0)) { + filtered[used++] = device.getId(); + } + } + return Arrays.copyOf(filtered, used); + } + + // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance + public static boolean handleJoystickMotionEvent(MotionEvent event) { + return mJoystickHandler.handleMotionEvent(event); + } + + /** + * This method is called by SDL using JNI. + */ + public static void pollInputDevices() { + if (SDLActivity.mSDLThread != null) { + mJoystickHandler.pollInputDevices(); + } + } + + // Check if a given device is considered a possible SDL joystick + public static boolean isDeviceSDLJoystick(int deviceId) { + InputDevice device = InputDevice.getDevice(deviceId); + // We cannot use InputDevice.isVirtual before API 16, so let's accept + // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1) + if ((device == null) || (deviceId < 0)) { + return false; + } + int sources = device.getSources(); + return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) || + ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) || + ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) + ); + } + + // APK expansion files support + + /** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */ + private Object expansionFile; + + /** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */ + private Method expansionFileMethod; + + /** + * This method is called by SDL using JNI. + * @return an InputStream on success or null if no expansion file was used. + * @throws IOException on errors. Message is set for the SDL error message. + */ + public InputStream openAPKExpansionInputStream(String fileName) throws IOException { + // Get a ZipResourceFile representing a merger of both the main and patch files + if (expansionFile == null) { + String mainHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION"); + if (mainHint == null) { + return null; // no expansion use if no main version was set + } + String patchHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION"); + if (patchHint == null) { + return null; // no expansion use if no patch version was set + } + + Integer mainVersion; + Integer patchVersion; + try { + mainVersion = Integer.valueOf(mainHint); + patchVersion = Integer.valueOf(patchHint); + } catch (NumberFormatException ex) { + ex.printStackTrace(); + throw new IOException("No valid file versions set for APK expansion files", ex); + } + + try { + // To avoid direct dependency on Google APK expansion library that is + // not a part of Android SDK we access it using reflection + expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport") + .getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class) + .invoke(null, this, mainVersion, patchVersion); + + expansionFileMethod = expansionFile.getClass() + .getMethod("getInputStream", String.class); + } catch (Exception ex) { + ex.printStackTrace(); + expansionFile = null; + expansionFileMethod = null; + throw new IOException("Could not access APK expansion support library", ex); + } + } + + // Get an input stream for a known file inside the expansion file ZIPs + InputStream fileStream; + try { + fileStream = (InputStream)expansionFileMethod.invoke(expansionFile, fileName); + } catch (Exception ex) { + // calling "getInputStream" failed + ex.printStackTrace(); + throw new IOException("Could not open stream from APK expansion file", ex); + } + + if (fileStream == null) { + // calling "getInputStream" was successful but null was returned + throw new IOException("Could not find path in APK expansion file"); + } + + return fileStream; + } + + // Messagebox + + /** Result of current messagebox. Also used for blocking the calling thread. */ + protected final int[] messageboxSelection = new int[1]; + + /** Id of current dialog. */ + protected int dialogs = 0; + + /** + * This method is called by SDL using JNI. + * Shows the messagebox from UI thread and block calling thread. + * buttonFlags, buttonIds and buttonTexts must have same length. + * @param buttonFlags array containing flags for every button. + * @param buttonIds array containing id for every button. + * @param buttonTexts array containing text for every button. + * @param colors null for default or array of length 5 containing colors. + * @return button id or -1. + */ + public int messageboxShowMessageBox( + final int flags, + final String title, + final String message, + final int[] buttonFlags, + final int[] buttonIds, + final String[] buttonTexts, + final int[] colors) { + + messageboxSelection[0] = -1; + + // sanity checks + + if ((buttonFlags.length != buttonIds.length) && (buttonIds.length != buttonTexts.length)) { + return -1; // implementation broken + } + + // collect arguments for Dialog + + final Bundle args = new Bundle(); + args.putInt("flags", flags); + args.putString("title", title); + args.putString("message", message); + args.putIntArray("buttonFlags", buttonFlags); + args.putIntArray("buttonIds", buttonIds); + args.putStringArray("buttonTexts", buttonTexts); + args.putIntArray("colors", colors); + + // trigger Dialog creation on UI thread + + runOnUiThread(new Runnable() { + @Override + public void run() { + showDialog(dialogs++, args); + } + }); + + // block the calling thread + + synchronized (messageboxSelection) { + try { + messageboxSelection.wait(); + } catch (InterruptedException ex) { + ex.printStackTrace(); + return -1; + } + } + + // return selected value + + return messageboxSelection[0]; + } + + @Override + protected Dialog onCreateDialog(int ignore, Bundle args) { + + // TODO set values from "flags" to messagebox dialog + + // get colors + + int[] colors = args.getIntArray("colors"); + int backgroundColor; + int textColor; + int buttonBorderColor; + int buttonBackgroundColor; + int buttonSelectedColor; + if (colors != null) { + int i = -1; + backgroundColor = colors[++i]; + textColor = colors[++i]; + buttonBorderColor = colors[++i]; + buttonBackgroundColor = colors[++i]; + buttonSelectedColor = colors[++i]; + } else { + backgroundColor = Color.TRANSPARENT; + textColor = Color.TRANSPARENT; + buttonBorderColor = Color.TRANSPARENT; + buttonBackgroundColor = Color.TRANSPARENT; + buttonSelectedColor = Color.TRANSPARENT; + } + + // create dialog with title and a listener to wake up calling thread + + final Dialog dialog = new Dialog(this); + dialog.setTitle(args.getString("title")); + dialog.setCancelable(false); + dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface unused) { + synchronized (messageboxSelection) { + messageboxSelection.notify(); + } + } + }); + + // create text + + TextView message = new TextView(this); + message.setGravity(Gravity.CENTER); + message.setText(args.getString("message")); + if (textColor != Color.TRANSPARENT) { + message.setTextColor(textColor); + } + + // create buttons + + int[] buttonFlags = args.getIntArray("buttonFlags"); + int[] buttonIds = args.getIntArray("buttonIds"); + String[] buttonTexts = args.getStringArray("buttonTexts"); + + final SparseArray