From d5f430cc11d8c8e9a3e6b45068951c7a98fc3f42 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 5 Nov 2018 15:13:57 +0000 Subject: [PATCH 1/3] android: gradle wrapper https://github.com/gradle/gradle/tree/v4.6.0 License: Apache 2.0 --- .../android/gradle-wrapper/gradle.properties | 17 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54334 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + platforms/android/gradle-wrapper/gradlew | 172 ++++++++++++++++++ platforms/android/gradle-wrapper/gradlew.bat | 84 +++++++++ 5 files changed, 278 insertions(+) create mode 100644 platforms/android/gradle-wrapper/gradle.properties create mode 100644 platforms/android/gradle-wrapper/gradle/wrapper/gradle-wrapper.jar create mode 100644 platforms/android/gradle-wrapper/gradle/wrapper/gradle-wrapper.properties create mode 100644 platforms/android/gradle-wrapper/gradlew create mode 100644 platforms/android/gradle-wrapper/gradlew.bat diff --git a/platforms/android/gradle-wrapper/gradle.properties b/platforms/android/gradle-wrapper/gradle.properties new file mode 100644 index 0000000000..aac7c9b461 --- /dev/null +++ b/platforms/android/gradle-wrapper/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/platforms/android/gradle-wrapper/gradle/wrapper/gradle-wrapper.jar b/platforms/android/gradle-wrapper/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..8252d7e25c5b548b131082159ee03249a5d36511 GIT binary patch literal 54334 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

<5G2M1WZP5 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 \(.*\)$'` + 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 + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m"' + +# 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 +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +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" -a "$nonstop" = "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 + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/platforms/android/gradle-wrapper/gradlew.bat b/platforms/android/gradle-wrapper/gradlew.bat new file mode 100644 index 0000000000..9f29d12cd0 --- /dev/null +++ b/platforms/android/gradle-wrapper/gradlew.bat @@ -0,0 +1,84 @@ +@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 + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@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=-Dfile.encoding=UTF-8 "-Xmx64m" + +@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 Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_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=%* + +: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 From 2b35c1708b43e2f9e9173c8ee31808214f6ee3e6 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 5 Nov 2018 17:39:09 +0000 Subject: [PATCH 2/3] android: gradle-based package and samples - drop hello-android sample --- cmake/android/OpenCVDetectAndroidSDK.cmake | 18 ++ cmake/android/android_gradle_projects.cmake | 154 +++++++++++++++++- modules/java/CMakeLists.txt | 6 +- modules/java/android_sdk/CMakeLists.txt | 68 +++++++- .../android_gradle_lib/AndroidManifest.xml | 6 + .../android_gradle_lib/build.gradle | 35 ++++ .../android_gradle_lib/res/values/attrs.xml | 11 ++ modules/java/android_sdk/build.gradle.in | 10 +- modules/java/jni/CMakeLists.txt | 8 +- .../android/build-tests/test_ant_build.py | 77 --------- .../android/build-tests/test_cmake_build.py | 54 +++--- platforms/android/build-tests/test_gradle.sh | 37 +++++ .../android/build-tests/test_ndk_build.py | 148 ----------------- platforms/android/build_sdk.py | 100 +----------- platforms/android/ndk-18.config.py | 6 + platforms/android/service/CMakeLists.txt | 5 + samples/android/15-puzzle/build.gradle.in | 31 ++++ .../15-puzzle/gradle/AndroidManifest.xml | 32 ++++ samples/android/CMakeLists.txt | 9 - samples/android/build.gradle.in | 66 ++++++++ .../camera-calibration/build.gradle.in | 31 ++++ .../gradle/AndroidManifest.xml | 35 ++++ .../color-blob-detection/build.gradle.in | 31 ++++ .../gradle/AndroidManifest.xml | 35 ++++ .../android/face-detection/build.gradle.in | 43 +++++ .../face-detection/gradle/AndroidManifest.xml | 35 ++++ .../android/face-detection/jni/CMakeLists.txt | 19 +++ .../jni/DetectionBasedTracker_jni.cpp | 4 +- samples/android/hello-android/CMakeLists.txt | 66 -------- .../android/hello-android/cmake_android.cmd | 9 - .../android/hello-android/cmake_android.sh | 13 -- samples/android/hello-android/main.cpp | 28 ---- samples/android/hello-android/run.cmd | 49 ------ samples/android/hello-android/run.sh | 15 -- .../image-manipulations/build.gradle.in | 31 ++++ .../gradle/AndroidManifest.xml | 35 ++++ .../mobilenet-objdetect/AndroidManifest.xml | 42 ++--- .../mobilenet-objdetect/build.gradle.in | 31 ++++ .../gradle/AndroidManifest.xml | 29 ++++ .../tutorial-1-camerapreview/build.gradle.in | 31 ++++ .../gradle/AndroidManifest.xml | 35 ++++ .../build.gradle.in | 43 +++++ .../gradle/AndroidManifest.xml | 35 ++++ .../jni/CMakeLists.txt | 19 +++ .../tutorial-3-cameracontrol/build.gradle.in | 31 ++++ .../gradle/AndroidManifest.xml | 36 ++++ .../android/tutorial-4-opencl/build.gradle.in | 43 +++++ .../gradle/AndroidManifest.xml | 32 ++++ .../tutorial-4-opencl/jni/CMakeLists.txt | 19 +++ 49 files changed, 1218 insertions(+), 568 deletions(-) create mode 100644 modules/java/android_sdk/android_gradle_lib/AndroidManifest.xml create mode 100644 modules/java/android_sdk/android_gradle_lib/build.gradle create mode 100644 modules/java/android_sdk/android_gradle_lib/res/values/attrs.xml delete mode 100644 platforms/android/build-tests/test_ant_build.py create mode 100755 platforms/android/build-tests/test_gradle.sh delete mode 100644 platforms/android/build-tests/test_ndk_build.py create mode 100644 platforms/android/ndk-18.config.py create mode 100644 samples/android/15-puzzle/build.gradle.in create mode 100644 samples/android/15-puzzle/gradle/AndroidManifest.xml create mode 100644 samples/android/build.gradle.in create mode 100644 samples/android/camera-calibration/build.gradle.in create mode 100644 samples/android/camera-calibration/gradle/AndroidManifest.xml create mode 100644 samples/android/color-blob-detection/build.gradle.in create mode 100644 samples/android/color-blob-detection/gradle/AndroidManifest.xml create mode 100644 samples/android/face-detection/build.gradle.in create mode 100644 samples/android/face-detection/gradle/AndroidManifest.xml create mode 100644 samples/android/face-detection/jni/CMakeLists.txt delete mode 100644 samples/android/hello-android/CMakeLists.txt delete mode 100644 samples/android/hello-android/cmake_android.cmd delete mode 100755 samples/android/hello-android/cmake_android.sh delete mode 100644 samples/android/hello-android/main.cpp delete mode 100644 samples/android/hello-android/run.cmd delete mode 100755 samples/android/hello-android/run.sh create mode 100644 samples/android/image-manipulations/build.gradle.in create mode 100644 samples/android/image-manipulations/gradle/AndroidManifest.xml create mode 100644 samples/android/mobilenet-objdetect/build.gradle.in create mode 100644 samples/android/mobilenet-objdetect/gradle/AndroidManifest.xml create mode 100644 samples/android/tutorial-1-camerapreview/build.gradle.in create mode 100644 samples/android/tutorial-1-camerapreview/gradle/AndroidManifest.xml create mode 100644 samples/android/tutorial-2-mixedprocessing/build.gradle.in create mode 100644 samples/android/tutorial-2-mixedprocessing/gradle/AndroidManifest.xml create mode 100644 samples/android/tutorial-2-mixedprocessing/jni/CMakeLists.txt create mode 100644 samples/android/tutorial-3-cameracontrol/build.gradle.in create mode 100644 samples/android/tutorial-3-cameracontrol/gradle/AndroidManifest.xml create mode 100644 samples/android/tutorial-4-opencl/build.gradle.in create mode 100644 samples/android/tutorial-4-opencl/gradle/AndroidManifest.xml create mode 100644 samples/android/tutorial-4-opencl/jni/CMakeLists.txt diff --git a/cmake/android/OpenCVDetectAndroidSDK.cmake b/cmake/android/OpenCVDetectAndroidSDK.cmake index f2f21f5f70..3a4ffefa43 100644 --- a/cmake/android/OpenCVDetectAndroidSDK.cmake +++ b/cmake/android/OpenCVDetectAndroidSDK.cmake @@ -8,6 +8,24 @@ if(DEFINED ANDROID_NDK_REVISION AND ANDROID_NDK_REVISION MATCHES "(1[56])([0-9]+ set(ANDROID_NDK_REVISION "${ANDROID_NDK_REVISION}" CACHE INTERNAL "Android NDK revision") endif() +# fixup -g option: https://github.com/opencv/opencv/issues/8460#issuecomment-434249750 +if((INSTALL_CREATE_DISTRIB OR CMAKE_BUILD_TYPE STREQUAL "Release") + AND NOT OPENCV_SKIP_ANDROID_G_OPTION_FIX +) + if(" ${CMAKE_CXX_FLAGS} " MATCHES " -g ") + message(STATUS "Android: fixup -g compiler option from Android toolchain") + endif() + string(REPLACE " -g " " " CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} ") + string(REPLACE " -g " " " CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} ") + string(REPLACE " -g " " " CMAKE_ASM_FLAGS " ${CMAKE_ASM_FLAGS} ") + if(NOT " ${CMAKE_CXX_FLAGS_DEBUG}" MATCHES " -g") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") + endif() + if(NOT " ${CMAKE_C_FLAGS_DEBUG}" MATCHES " -g") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g") + endif() +endif() + # https://developer.android.com/studio/command-line/variables.html ocv_check_environment_variables(ANDROID_SDK_ROOT ANDROID_HOME ANDROID_SDK) diff --git a/cmake/android/android_gradle_projects.cmake b/cmake/android/android_gradle_projects.cmake index 1ca752f8b2..ebad46a403 100644 --- a/cmake/android/android_gradle_projects.cmake +++ b/cmake/android/android_gradle_projects.cmake @@ -1,5 +1,151 @@ -message(FATAL_ERROR " -Android gradle-based build/projects are not supported in this version of OpenCV. -You need to downgrade Android SDK Tools to version 25.2.5. -Details: https://github.com/opencv/opencv/issues/8460 +# https://developer.android.com/studio/releases/gradle-plugin +set(ANDROID_GRADLE_PLUGIN_VERSION "3.2.1" CACHE STRING "Android Gradle Plugin version (3.0+)") +message(STATUS "Android Gradle Plugin version: ${ANDROID_GRADLE_PLUGIN_VERSION}") + +set(ANDROID_COMPILE_SDK_VERSION "26" CACHE STRING "Android compileSdkVersion") +set(ANDROID_MIN_SDK_VERSION "21" CACHE STRING "Android minSdkVersion") +set(ANDROID_TARGET_SDK_VERSION "26" CACHE STRING "Android minSdkVersion") + +set(ANDROID_BUILD_BASE_DIR "${OpenCV_BINARY_DIR}/opencv_android" CACHE INTERNAL "") +set(ANDROID_TMP_INSTALL_BASE_DIR "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/install/opencv_android") + +set(ANDROID_INSTALL_SAMPLES_DIR "samples") + +set(ANDROID_BUILD_ABI_FILTER " +reset() +include '${ANDROID_ABI}' ") + +set(ANDROID_INSTALL_ABI_FILTER " +//reset() +//include 'armeabi-v7a' +//include 'arm64-v8a' +//include 'x86' +//include 'x86_64' +") +if(NOT INSTALL_CREATE_DISTRIB) + set(ANDROID_INSTALL_ABI_FILTER "${ANDROID_BUILD_ABI_FILTER}") +endif() + +# BUG: Ninja generator generates broken targets with ANDROID_ABI_FILTER name (CMake 3.11.2) +#set(__spaces " ") +#string(REPLACE "\n" "\n${__spaces}" ANDROID_ABI_FILTER "${__spaces}${ANDROID_BUILD_ABI_FILTER}") +#string(REPLACE REGEX "[ ]+$" "" ANDROID_ABI_FILTER "${ANDROID_ABI_FILTER}") +set(ANDROID_ABI_FILTER "${ANDROID_BUILD_ABI_FILTER}") +configure_file("${OpenCV_SOURCE_DIR}/samples/android/build.gradle.in" "${ANDROID_BUILD_BASE_DIR}/build.gradle" @ONLY) + +set(ANDROID_ABI_FILTER "${ANDROID_INSTALL_ABI_FILTER}") +configure_file("${OpenCV_SOURCE_DIR}/samples/android/build.gradle.in" "${ANDROID_TMP_INSTALL_BASE_DIR}/${ANDROID_INSTALL_SAMPLES_DIR}/build.gradle" @ONLY) +install(FILES "${ANDROID_TMP_INSTALL_BASE_DIR}/${ANDROID_INSTALL_SAMPLES_DIR}/build.gradle" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}" COMPONENT samples) + +set(GRADLE_WRAPPER_FILES + "gradle/wrapper/gradle-wrapper.jar" + "gradle/wrapper/gradle-wrapper.properties" + "gradlew.bat" + "gradlew" + "gradle.properties" +) +foreach(fname ${GRADLE_WRAPPER_FILES}) + get_filename_component(__dir "${fname}" DIRECTORY) + set(__permissions "") + set(__permissions_prefix "") + if(fname STREQUAL "gradlew") + set(__permissions FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + endif() + file(COPY "${OpenCV_SOURCE_DIR}/platforms/android/gradle-wrapper/${fname}" DESTINATION "${ANDROID_BUILD_BASE_DIR}/${__dir}" ${__permissions}) + string(REPLACE "FILE_PERMISSIONS" "PERMISSIONS" __permissions "${__permissions}") + if("${__dir}" STREQUAL "") + set(__dir ".") + endif() + install(FILES "${OpenCV_SOURCE_DIR}/platforms/android/gradle-wrapper/${fname}" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}/${__dir}" COMPONENT samples ${__permissions}) +endforeach() + +file(WRITE "${ANDROID_BUILD_BASE_DIR}/settings.gradle" " +include ':opencv' +") + +file(WRITE "${ANDROID_TMP_INSTALL_BASE_DIR}/settings.gradle" " +rootProject.name = 'opencv_samples' + +def opencvsdk='../' +//def opencvsdk='/' +//println opencvsdk +include ':opencv' +project(':opencv').projectDir = new File(opencvsdk + '/sdk') +") + + +macro(add_android_project target path) + get_filename_component(__dir "${path}" NAME) + + set(OPENCV_ANDROID_CMAKE_EXTRA_ARGS "") + if(DEFINED ANDROID_TOOLCHAIN) + set(OPENCV_ANDROID_CMAKE_EXTRA_ARGS "${OPENCV_ANDROID_CMAKE_EXTRA_ARGS},\n\"-DANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN}\"") + endif() + if(DEFINED ANDROID_STL) + set(OPENCV_ANDROID_CMAKE_EXTRA_ARGS "${OPENCV_ANDROID_CMAKE_EXTRA_ARGS},\n\"-DANDROID_STL=${ANDROID_STL}\"") + endif() + + # + # Build + # + set(ANDROID_SAMPLE_JNI_PATH "${path}/jni") + set(ANDROID_SAMPLE_JAVA_PATH "${path}/src") + set(ANDROID_SAMPLE_RES_PATH "${path}/res") + set(ANDROID_SAMPLE_MANIFEST_PATH "${path}/gradle/AndroidManifest.xml") + + set(ANDROID_ABI_FILTER "${ANDROID_BUILD_ABI_FILTER}") + set(ANDROID_PROJECT_JNI_PATH "../../") + + string(REPLACE ";" "', '" ANDROID_SAMPLE_JAVA_PATH "['${ANDROID_SAMPLE_JAVA_PATH}']") + string(REPLACE ";" "', '" ANDROID_SAMPLE_RES_PATH "['${ANDROID_SAMPLE_RES_PATH}']") + configure_file("${path}/build.gradle.in" "${ANDROID_BUILD_BASE_DIR}/${__dir}/build.gradle" @ONLY) + + file(APPEND "${ANDROID_BUILD_BASE_DIR}/settings.gradle" " +include ':${__dir}' +") + + # build apk + set(APK_FILE "${ANDROID_BUILD_BASE_DIR}/${__dir}/build/outputs/apk/release/${__dir}-${ANDROID_ABI}-release-unsigned.apk") + ocv_update(OPENCV_GRADLE_VERBOSE_OPTIONS "-i") + add_custom_command( + OUTPUT "${APK_FILE}" "${OPENCV_DEPHELPER}/android_sample_${__dir}" + COMMAND ./gradlew ${OPENCV_GRADLE_VERBOSE_OPTIONS} "${__dir}:assemble" + COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/android_sample_${__dir}" + WORKING_DIRECTORY "${ANDROID_BUILD_BASE_DIR}" + DEPENDS ${depends} opencv_java_android + COMMENT "Building OpenCV Android sample project: ${__dir}" + ) + file(REMOVE "${OPENCV_DEPHELPER}/android_sample_${__dir}") # force rebuild after CMake run + + add_custom_target(android_sample_${__dir} ALL DEPENDS "${OPENCV_DEPHELPER}/android_sample_${__dir}" SOURCES "${ANDROID_SAMPLE_MANIFEST_PATH}") + + # + # Install + # + set(ANDROID_SAMPLE_JNI_PATH "jni") + set(ANDROID_SAMPLE_JAVA_PATH "src") + set(ANDROID_SAMPLE_RES_PATH "res") + set(ANDROID_SAMPLE_MANIFEST_PATH "AndroidManifest.xml") + + install(DIRECTORY "${path}/res" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}/${__dir}" COMPONENT samples OPTIONAL) + install(DIRECTORY "${path}/src" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}/${__dir}" COMPONENT samples) + install(DIRECTORY "${path}/jni" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}/${__dir}" COMPONENT samples OPTIONAL) + + install(FILES "${path}/gradle/AndroidManifest.xml" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}/${__dir}" COMPONENT samples) + + set(ANDROID_ABI_FILTER "${ANDROID_INSTALL_ABI_FILTER}") + set(ANDROID_PROJECT_JNI_PATH "native/jni") + + string(REPLACE ";" "', '" ANDROID_SAMPLE_JAVA_PATH "['${ANDROID_SAMPLE_JAVA_PATH}']") + string(REPLACE ";" "', '" ANDROID_SAMPLE_RES_PATH "['${ANDROID_SAMPLE_RES_PATH}']") + configure_file("${path}/build.gradle.in" "${ANDROID_TMP_INSTALL_BASE_DIR}/${__dir}/build.gradle" @ONLY) + install(FILES "${ANDROID_TMP_INSTALL_BASE_DIR}/${__dir}/build.gradle" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}/${__dir}" COMPONENT samples) + + file(APPEND "${ANDROID_TMP_INSTALL_BASE_DIR}/settings.gradle" " +include ':${__dir}' +") + +endmacro() + +install(FILES "${ANDROID_TMP_INSTALL_BASE_DIR}/settings.gradle" DESTINATION "${ANDROID_INSTALL_SAMPLES_DIR}" COMPONENT samples) diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt index 8cc4bd07a6..a477490d14 100644 --- a/modules/java/CMakeLists.txt +++ b/modules/java/CMakeLists.txt @@ -3,8 +3,8 @@ if(OPENCV_INITIAL_PASS) add_subdirectory(generator) endif() -if(APPLE_FRAMEWORK OR WINRT OR NOT PYTHON_DEFAULT_AVAILABLE OR NOT ANT_EXECUTABLE - OR NOT (JNI_FOUND OR (ANDROID AND ANDROID_NATIVE_API_LEVEL GREATER 7)) +if(APPLE_FRAMEWORK OR WINRT OR NOT PYTHON_DEFAULT_AVAILABLE OR NOT (ANT_EXECUTABLE OR ANDROID_PROJECTS_BUILD_TYPE STREQUAL "GRADLE") + OR NOT (JNI_FOUND OR (ANDROID AND (NOT DEFINED ANDROID_NATIVE_API_LEVEL OR ANDROID_NATIVE_API_LEVEL GREATER 7))) OR BUILD_opencv_world ) ocv_module_disable(java) @@ -55,7 +55,7 @@ macro(copy_common_tests _src_location _dst_location _deps) endmacro() -add_subdirectory(jni) # generates ${the_module} target (${the_module}_jni doesn't work properly with Android samples) +add_subdirectory(jni) # generates ${the_module} target (${the_module}_jni doesn't work properly with Android non-gradle samples) if(ANDROID) add_subdirectory(android_sdk) # generates ${the_module}_android target else() diff --git a/modules/java/android_sdk/CMakeLists.txt b/modules/java/android_sdk/CMakeLists.txt index e57b0394a3..945dcf2b54 100644 --- a/modules/java/android_sdk/CMakeLists.txt +++ b/modules/java/android_sdk/CMakeLists.txt @@ -1,12 +1,11 @@ -if(NOT ANDROID_EXECUTABLE) - message(WARNING "'android' tool required to build Android SDK") - return() -endif() -ocv_assert(ANDROID_TOOLS_Pkg_Revision GREATER 13) project(${the_module}_android) -set(OPENCV_JAVA_DIR "${OpenCV_BINARY_DIR}/android_sdk" CACHE INTERNAL "") +if(ANDROID_EXECUTABLE) + set(OPENCV_JAVA_DIR "${OpenCV_BINARY_DIR}/android_sdk" CACHE INTERNAL "") +else() # gradle + set(OPENCV_JAVA_DIR "${ANDROID_BUILD_BASE_DIR}/opencv" CACHE INTERNAL "") +endif() set(OPENCV_ANDROID_LIB_DIR "${OPENCV_JAVA_DIR}" CACHE INTERNAL "") # for OpenCV samples file(REMOVE_RECURSE "${OPENCV_JAVA_DIR}") @@ -15,6 +14,11 @@ set(java_src_dir "${OPENCV_JAVA_DIR}/src") file(MAKE_DIRECTORY "${java_src_dir}") ocv_copyfiles_append_dir(JAVA_SRC_COPY "${OPENCV_JAVA_BINDINGS_DIR}/gen/java" "${java_src_dir}") + +if(ANDROID_EXECUTABLE) + +ocv_assert(ANDROID_TOOLS_Pkg_Revision GREATER 13) + ocv_copyfiles_append_dir(JAVA_SRC_COPY "${OPENCV_JAVA_BINDINGS_DIR}/gen/android/java" "${java_src_dir}") # calc default SDK Target @@ -90,5 +94,57 @@ FILE(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${JAVA_INSTALL_ROOT FILE(MAKE_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${JAVA_INSTALL_ROOT}/res\") " COMPONENT java) +ocv_update(ANDROID_COMPILE_SDK_VERSION "27") +ocv_update(ANDROID_MIN_SDK_VERSION "14") +ocv_update(ANDROID_TARGET_SDK_VERSION "21") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.gradle.in" "${CMAKE_CURRENT_BINARY_DIR}/build.gradle" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/build.gradle" DESTINATION ${JAVA_INSTALL_ROOT}/.. COMPONENT java) + + +else() # gradle build +# +# Android Gradle-based project +# + +#TODO: INSTALL ONLY +ocv_copyfiles_append_dir(JAVA_SRC_COPY "${OPENCV_JAVA_BINDINGS_DIR}/gen/android/java" "${java_src_dir}") +ocv_copyfiles_append_dir(JAVA_SRC_COPY "${OPENCV_JAVA_BINDINGS_DIR}/gen/android-21/java" "${java_src_dir}") + +# copy boilerplate +set(__base_dir "${CMAKE_CURRENT_SOURCE_DIR}/android_gradle_lib/") +file(GLOB_RECURSE seed_project_files_rel RELATIVE "${__base_dir}/" "${__base_dir}/*") +list(REMOVE_ITEM seed_project_files_rel "${ANDROID_MANIFEST_FILE}") +foreach(file ${seed_project_files_rel}) + configure_file("${__base_dir}/${file}" "${OPENCV_JAVA_DIR}/${file}" @ONLY) + list(APPEND depends "${__base_dir}/${file}") + get_filename_component(install_subdir "${file}" PATH) + install(FILES "${OPENCV_JAVA_DIR}/${file}" DESTINATION "${JAVA_INSTALL_ROOT}/${install_subdir}" COMPONENT java) +endforeach() + +list(APPEND depends gen_opencv_java_source "${OPENCV_DEPHELPER}/gen_opencv_java_source") +ocv_copyfiles_add_target(${the_module}_android_source_copy JAVA_SRC_COPY "Copy Java(Andoid SDK) source files" ${depends}) +file(REMOVE "${OPENCV_DEPHELPER}/${the_module}_android_source_copy") # force rebuild after CMake run + +set(depends ${the_module}_android_source_copy "${OPENCV_DEPHELPER}/${the_module}_android_source_copy") + +# build jar +set(AAR_FILE "${OPENCV_JAVA_DIR}/build/outputs/aar/opencv-release.aar") +ocv_update(OPENCV_GRADLE_VERBOSE_OPTIONS "-i") +add_custom_command( + OUTPUT "${AAR_FILE}" "${OPENCV_DEPHELPER}/${the_module}_android" + COMMAND ./gradlew ${OPENCV_GRADLE_VERBOSE_OPTIONS} "opencv:assemble" + COMMAND ${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/${the_module}_android" + WORKING_DIRECTORY "${ANDROID_BUILD_BASE_DIR}" + DEPENDS ${depends} ${the_module} + COMMENT "Building OpenCV Android library project" +) +file(REMOVE "${OPENCV_DEPHELPER}/${the_module}_android") # force rebuild after CMake run + +add_custom_target(${the_module}_android ALL DEPENDS "${OPENCV_DEPHELPER}/${the_module}_android" SOURCES "${__base_dir}/${ANDROID_MANIFEST_FILE}") + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.gradle.in" "${ANDROID_TMP_INSTALL_BASE_DIR}/opencv/build.gradle" @ONLY) +install(FILES "${ANDROID_TMP_INSTALL_BASE_DIR}/opencv/build.gradle" DESTINATION ${JAVA_INSTALL_ROOT}/.. COMPONENT java) + +install(DIRECTORY "${java_src_dir}" DESTINATION "${JAVA_INSTALL_ROOT}" COMPONENT java) + +endif() # gradle build diff --git a/modules/java/android_sdk/android_gradle_lib/AndroidManifest.xml b/modules/java/android_sdk/android_gradle_lib/AndroidManifest.xml new file mode 100644 index 0000000000..b62ded736d --- /dev/null +++ b/modules/java/android_sdk/android_gradle_lib/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + diff --git a/modules/java/android_sdk/android_gradle_lib/build.gradle b/modules/java/android_sdk/android_gradle_lib/build.gradle new file mode 100644 index 0000000000..8091293401 --- /dev/null +++ b/modules/java/android_sdk/android_gradle_lib/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + //buildToolsVersion "x.y.z" // not needed since com.android.tools.build:gradle:3.0.0 + + defaultConfig { + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_6 + targetCompatibility JavaVersion.VERSION_1_6 + } + + sourceSets { + main { + jniLibs.srcDirs = ['../../jni'] + java.srcDirs = ['src'] // TODO Use original files instead of copied into build directory + aidl.srcDirs = ['src'] + res.srcDirs = ['@OpenCV_SOURCE_DIR@/modules/java/android_sdk/android_gradle_lib/res'] + manifest.srcFile 'AndroidManifest.xml' + } + } +} + +dependencies { +} diff --git a/modules/java/android_sdk/android_gradle_lib/res/values/attrs.xml b/modules/java/android_sdk/android_gradle_lib/res/values/attrs.xml new file mode 100644 index 0000000000..6902621f66 --- /dev/null +++ b/modules/java/android_sdk/android_gradle_lib/res/values/attrs.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/modules/java/android_sdk/build.gradle.in b/modules/java/android_sdk/build.gradle.in index f4c260e40d..fbb65bdfdf 100644 --- a/modules/java/android_sdk/build.gradle.in +++ b/modules/java/android_sdk/build.gradle.in @@ -81,9 +81,9 @@ // splits { // abi { // enable true +// universalApk false // reset() // include 'armeabi-v7a' // , 'x86', 'x86_64', 'arm64-v8a' -// universalApk false // } // } // @@ -93,12 +93,12 @@ apply plugin: 'com.android.library' println "OpenCV: " + project.buildscript.sourceFile android { - compileSdkVersion 27 - //buildToolsVersion "27.0.3" // not needed since com.android.tools.build:gradle:3.0.0 + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + //buildToolsVersion "x.y.z" // not needed since com.android.tools.build:gradle:3.0.0 defaultConfig { - minSdkVersion 14 - targetSdkVersion 21 + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ } buildTypes { diff --git a/modules/java/jni/CMakeLists.txt b/modules/java/jni/CMakeLists.txt index bfb948bfb7..2a50ee238e 100644 --- a/modules/java/jni/CMakeLists.txt +++ b/modules/java/jni/CMakeLists.txt @@ -13,6 +13,12 @@ foreach(m ${OPENCV_MODULES_BUILD}) endif() endforeach() +if(ANDROID) + ocv_update(JNI_OUTPUT_PATH "${OpenCV_BINARY_DIR}/jni/${ANDROID_NDK_ABI_NAME}") +else() + ocv_update(JNI_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH}") +endif() + set(__type MODULE) if(BUILD_FAT_JAVA_LIB) set(__type SHARED) # samples link to libopencv_java @@ -60,7 +66,7 @@ endif() set_target_properties(${the_module} PROPERTIES OUTPUT_NAME "${the_module}${OPENCV_JAVA_LIB_NAME_SUFFIX}" ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} - LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} + LIBRARY_OUTPUT_DIRECTORY ${JNI_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} DEFINE_SYMBOL CVAPI_EXPORTS ) diff --git a/platforms/android/build-tests/test_ant_build.py b/platforms/android/build-tests/test_ant_build.py deleted file mode 100644 index 73ac4d018e..0000000000 --- a/platforms/android/build-tests/test_ant_build.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python - -import unittest -import os, sys, subprocess, argparse, shutil, re -from os.path import abspath - -class TestAntBuild(unittest.TestCase): - pass - - def __init__(self, target, workdir, lib_dir, sample_dir, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - self.target = target - self.workdir = workdir - self.src_lib_dir = lib_dir - self.src_sample_dir = sample_dir - self.lib_dir = os.path.join(self.workdir, "opencv") - self.sample_dir = os.path.join(self.workdir, "project") - - def shortDescription(self): - return "TARGET: %r, SAMPLE: %s" % (self.target, os.path.basename(self.src_sample_dir)) - - def setUp(self): - if os.path.exists(self.workdir): - shutil.rmtree(self.workdir) - os.mkdir(self.workdir) - shutil.copytree(self.src_lib_dir, self.lib_dir) - shutil.copytree(self.src_sample_dir, self.sample_dir) - os.remove(os.path.join(self.sample_dir, "project.properties")) - - def tearDown(self): - if os.path.exists(self.workdir): - shutil.rmtree(self.workdir) - - def runTest(self): - cmd = [os.path.join(os.environ["ANDROID_SDK"], "tools", "android"), "update", "project", "-p", self.lib_dir, "-t", self.target[0]] - retcode = subprocess.call(cmd) - self.assertEqual(retcode, 0, "android update opencv project failed") - - cmd = ["ant", "-f", os.path.join(self.lib_dir, "build.xml"), "debug"] - retcode = subprocess.call(cmd) - self.assertEqual(retcode, 0, "opencv ant build failed") - - cmd = [os.path.join(os.environ["ANDROID_SDK"], "tools", "android"), "update", "project", "-p", self.sample_dir, "-t", self.target[1], "-l", os.path.relpath(self.lib_dir, self.sample_dir)] - retcode = subprocess.call(cmd) - self.assertEqual(retcode, 0, "android update sample project failed") - - cmd = ["ant", "-f", os.path.join(self.sample_dir, "build.xml"), "debug"] - retcode = subprocess.call(cmd) - self.assertEqual(retcode, 0, "sample ant build failed") - -def suite(workdir, opencv_lib_path, opencv_samples_path): - suite = unittest.TestSuite() - for target in [("android-21", "android-14"), ("android-21", "android-17")]: - for item in os.listdir(opencv_samples_path): - item = os.path.join(opencv_samples_path, item) - if (os.path.exists(os.path.join(item, "AndroidManifest.xml"))): - suite.addTest(TestAntBuild(target, workdir, opencv_lib_path, item)) - return suite - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Test OpenCV for Android SDK with ant') - parser.add_argument('--sdk_path', help="Path to Android SDK to use for build") - parser.add_argument("--workdir", default="testspace", help="Working directory (and output)") - parser.add_argument("opencv_lib_path", help="Path to folder with SDK java library (usually /sdk/java/)") - parser.add_argument("opencv_samples_path", help="Path to folder with SDK samples (usually /samples/)") - - args = parser.parse_args() - - if args.sdk_path is not None: - os.environ["ANDROID_SDK"] = os.path.abspath(args.sdk_path) - - print("Using SDK: %s" % os.environ["ANDROID_SDK"]) - - s = suite(abspath(args.workdir), abspath(args.opencv_lib_path), abspath(args.opencv_samples_path)) - res = unittest.TextTestRunner(verbosity=3).run(s) - if not res.wasSuccessful(): - sys.exit(res) diff --git a/platforms/android/build-tests/test_cmake_build.py b/platforms/android/build-tests/test_cmake_build.py index eb4d43512a..b90bf5a133 100644 --- a/platforms/android/build-tests/test_cmake_build.py +++ b/platforms/android/build-tests/test_cmake_build.py @@ -44,18 +44,29 @@ int main(int argc, char* argv[]) #=================================================================================================== class TestCmakeBuild(unittest.TestCase): - def __init__(self, libset, abi, toolchain, opencv_cmake_path, workdir, *args, **kwargs): + def __init__(self, libset, abi, cmake_vars, opencv_cmake_path, workdir, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) self.libset = libset self.abi = abi - self.toolchain = toolchain + self.cmake_vars = cmake_vars self.opencv_cmake_path = opencv_cmake_path self.workdir = workdir self.srcdir = os.path.join(self.workdir, "src") self.bindir = os.path.join(self.workdir, "build") def shortDescription(self): - return "ABI: %s, TOOLCHAIN: %s, LIBSET: %s" % (self.abi, self.toolchain, self.libset) + return "ABI: %s, LIBSET: %s" % (self.abi, self.libset) + + def getCMakeToolchain(self): + if True: + toolchain = os.path.join(os.environ['ANDROID_NDK'], 'build', 'cmake', 'android.toolchain.cmake') + if os.path.exists(toolchain): + return toolchain + toolchain = os.path.join(self.opencv_cmake_path, "android.toolchain.cmake") + if os.path.exists(toolchain): + return toolchain + else: + raise Exception("Can't find toolchain") def gen_cmakelists(self): return CMAKE_TEMPLATE % {"libset": self.libset} @@ -78,43 +89,40 @@ class TestCmakeBuild(unittest.TestCase): os.chdir(self.bindir) def tearDown(self): - if os.path.exists(self.workdir): - shutil.rmtree(self.workdir) + pass + #if os.path.exists(self.workdir): + # shutil.rmtree(self.workdir) def runTest(self): cmd = [ "cmake", "-GNinja", "-DOpenCV_DIR=%s" % self.opencv_cmake_path, - "-DANDROID_ABI=%s" % self.abi, - "-DCMAKE_TOOLCHAIN_FILE=%s" % os.path.join(self.opencv_cmake_path, "android.toolchain.cmake"), - "-DANDROID_TOOLCHAIN_NAME=%s" % self.toolchain, + "-DCMAKE_TOOLCHAIN_FILE=%s" % self.getCMakeToolchain(), self.srcdir - ] + ] + [ "-D{}={}".format(key, value) for key, value in self.cmake_vars.items() ] log.info("Executing: %s" % cmd) retcode = subprocess.call(cmd) self.assertEqual(retcode, 0, "cmake failed") - cmd = ["ninja"] + cmd = ["ninja", "-v"] log.info("Executing: %s" % cmd) retcode = subprocess.call(cmd) self.assertEqual(retcode, 0, "make failed") def suite(workdir, opencv_cmake_path): abis = { - "armeabi":"arm-linux-androideabi-4.8", - "armeabi-v7a":"arm-linux-androideabi-4.8", - "arm64-v8a":"aarch64-linux-android-4.9", - "x86":"x86-4.8", - "x86_64":"x86_64-4.9", - "mips":"mipsel-linux-android-4.8", - "mips64":"mips64el-linux-android-4.9" + "armeabi-v7a": { "ANDROID_ABI": "armeabi-v7a", "ANDROID_TOOLCHAIN": "clang", "ANDROID_STL": "c++_static" }, + "arm64-v8a": { "ANDROID_ABI": "arm64-v8a", "ANDROID_TOOLCHAIN": "clang", "ANDROID_STL": "c++_static" }, + "x86": { "ANDROID_ABI": "x86", "ANDROID_TOOLCHAIN": "clang", "ANDROID_STL": "c++_static" }, + "x86_64": { "ANDROID_ABI": "x86_64", "ANDROID_TOOLCHAIN": "clang", "ANDROID_STL": "c++_static" }, } suite = unittest.TestSuite() for libset in ["", "opencv_java"]: - for abi, toolchain in abis.items(): - suite.addTest(TestCmakeBuild(libset, abi, toolchain, opencv_cmake_path, workdir)) + for abi, cmake_vars in abis.items(): + suite.addTest(TestCmakeBuild(libset, abi, cmake_vars, opencv_cmake_path, + os.path.join(workdir, "{}-{}".format(abi, "static" if libset == "" else "shared")))) return suite @@ -132,9 +140,15 @@ if __name__ == '__main__': if args.ndk_path is not None: os.environ["ANDROID_NDK"] = os.path.abspath(args.ndk_path) + if not 'ANDROID_HOME' in os.environ and 'ANDROID_SDK' in os.environ: + os.environ['ANDROID_HOME'] = os.environ["ANDROID_SDK"] + print("Using SDK: %s" % os.environ["ANDROID_SDK"]) print("Using NDK: %s" % os.environ["ANDROID_NDK"]) - res = unittest.TextTestRunner(verbosity=3).run(suite(os.path.abspath(args.workdir), os.path.abspath(args.opencv_cmake_path))) + workdir = os.path.abspath(args.workdir) + if not os.path.exists(workdir): + os.mkdir(workdir) + res = unittest.TextTestRunner(verbosity=3).run(suite(workdir, os.path.abspath(args.opencv_cmake_path))) if not res.wasSuccessful(): sys.exit(res) diff --git a/platforms/android/build-tests/test_gradle.sh b/platforms/android/build-tests/test_gradle.sh new file mode 100755 index 0000000000..9f1b233ff2 --- /dev/null +++ b/platforms/android/build-tests/test_gradle.sh @@ -0,0 +1,37 @@ +#!/bin/bash -e +SDK_DIR=$1 +echo "OpenCV Android SDK path: ${SDK_DIR}" + +ANDROID_HOME=${ANDROID_HOME:-${ANDROID_SDK_ROOT:-${ANDROID_SDK?Required ANDROID_HOME/ANDROID_SDK/ANDROID_SDK_ROOT}}} +ANDROID_NDK=${ANDROID_NDK_HOME-${ANDROID_NDK:-${NDKROOT?Required ANDROID_NDK_HOME/ANDROID_NDK/NDKROOT}}} + +echo "Android SDK: ${ANDROID_HOME}" +echo "Android NDK: ${ANDROID_NDK}" + +if [ ! -d "${ANDROID_HOME}" ]; then + echo "FATAL: Missing Android SDK directory" + exit 1 +fi +if [ ! -d "${ANDROID_NDK}" ]; then + echo "FATAL: Missing Android NDK directory" + exit 1 +fi + +export ANDROID_HOME=${ANDROID_HOME} +export ANDROID_SDK=${ANDROID_HOME} +export ANDROID_SDK_ROOT=${ANDROID_HOME} + +export ANDROID_NDK=${ANDROID_NDK} +export ANDROID_NDK_HOME=${ANDROID_NDK} + +echo "Cloning OpenCV Android SDK ..." +rm -rf "test-gradle" +cp -rp "${SDK_DIR}" "test-gradle" +echo "Cloning OpenCV Android SDK ... Done!" + +echo "Run gradle ..." +(cd "test-gradle/samples"; ./gradlew -i assemble) + +echo "#" +echo "# Done!" +echo "#" diff --git a/platforms/android/build-tests/test_ndk_build.py b/platforms/android/build-tests/test_ndk_build.py deleted file mode 100644 index cc1dbc0102..0000000000 --- a/platforms/android/build-tests/test_ndk_build.py +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env python - -import unittest -import os, sys, subprocess, argparse, shutil, re - -TEMPLATE_ANDROID_MK = '''\ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -{cut} -LOCAL_MODULE := mixed_sample -LOCAL_SRC_FILES := {cpp1} -LOCAL_LDLIBS += -llog -ldl -include $(BUILD_SHARED_LIBRARY) -include $(CLEAR_VARS) -{cut} -LOCAL_MODULE := mixed_sample2 -LOCAL_SRC_FILES := {cpp2} -LOCAL_LDLIBS += -llog -ldl -LOCAL_SHARED_LIBS := mixed_sample -include $(BUILD_SHARED_LIBRARY) -''' - -TEMPLATE_APPLICATION_MK = '''\ -APP_STL := gnustl_static -APP_CPPFLAGS := -frtti -fexceptions -std=c++11 -APP_ABI := {abi} -APP_PLATFORM := android-9 -''' - -TEMPLATE_JNI = '''\ -#include -#include -#include -#include -#include -using namespace std; -using namespace cv; -extern "C" { -JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4Mixed_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba); -JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4Mixed_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba) -{ - Mat& mGr = *(Mat*)addrGray; - Mat& mRgb = *(Mat*)addrRgba; - vector v; - Ptr detector = FastFeatureDetector::create(50); - detector->detect(mGr, v); - for( unsigned int i = 0; i < v.size(); i++ ) - { - const KeyPoint& kp = v[i]; - circle(mRgb, Point(kp.pt.x, kp.pt.y), 10, Scalar(255,0,0,255)); - } -} -} -''' - -#=================================================================================================== - -class TestNDKBuild(unittest.TestCase): - def __init__(self, abi, libtype, opencv_mk_path, workdir, *args, **kwargs): - unittest.TestCase.__init__(self, *args, **kwargs) - self.abi = abi # official NDK ABI name or 'all' - self.libtype = libtype # 'static', etc - self.opencv_mk_path = opencv_mk_path - self.workdir = workdir - self.jnidir = os.path.join(self.workdir, "jni") - self.cpp1 = "jni_part1.cpp" - self.cpp2 = "jni_part2.cpp" - - def shortDescription(self): - return "ABI: %s, LIBTYPE: %s" % (self.abi, self.libtype) - - def gen_android_mk(self): - p = [] - if self.libtype == "static": - p.append("OPENCV_LIB_TYPE := STATIC") - elif self.libtype == "shared": - p.append("OPENCV_LIB_TYPE := SHARED") - p.append("OPENCV_INSTALL_MODULES:=on") - elif self.libtype == "shared_opencv_manager": - p.append("OPENCV_LIB_TYPE := SHARED") - p.append("OPENCV_INSTALL_MODULES:=off") - p.append("include %s" % os.path.join(self.opencv_mk_path, "OpenCV.mk")) - return TEMPLATE_ANDROID_MK.format(cut = "\n".join(p), cpp1 = self.cpp1, cpp2 = self.cpp2) - - def gen_jni_code(self): - return TEMPLATE_JNI - - def gen_application_mk(self): - return TEMPLATE_APPLICATION_MK.format(abi = self.abi) - - def write_jni_file(self, fname, contents): - with open(os.path.join(self.jnidir, fname), "w") as f: - f.write(contents) - - def setUp(self): - if os.path.exists(self.workdir): - shutil.rmtree(self.workdir) - os.mkdir(self.workdir) - os.mkdir(self.jnidir) - self.write_jni_file("Android.mk", self.gen_android_mk()) - self.write_jni_file("Application.mk", self.gen_application_mk()) - self.write_jni_file(self.cpp1, self.gen_jni_code()) - self.write_jni_file(self.cpp2, self.gen_jni_code()) - os.chdir(self.workdir) - - def tearDown(self): - if os.path.exists(self.workdir): - shutil.rmtree(self.workdir) - - def runTest(self): - ndk_path = os.environ["ANDROID_NDK"] - retcode = subprocess.call([os.path.join(ndk_path, 'ndk-build'), "V=0"]) - self.assertEqual(retcode, 0) - -def suite(workdir, opencv_mk_path): - abis = ["armeabi", "armeabi-v7a", "x86", "mips"] - ndk_path = os.environ["ANDROID_NDK"] - if os.path.exists(os.path.join(ndk_path, "RELEASE.TXT")): - with open(os.path.join(ndk_path, "RELEASE.TXT"), "r") as f: - s = f.read() - if re.search(r'r10[b-e]', s): - abis.extend(["arm64-v8a", "x86_64"]) - if os.path.exists(os.path.join(ndk_path, "source.properties")): # Android NDK 11+ - abis.extend(["arm64-v8a", "x86_64"]) - abis.append("all") - - suite = unittest.TestSuite() - for libtype in ["static", "shared", "shared_opencv_manager"]: - for abi in abis: - suite.addTest(TestNDKBuild(abi, libtype, opencv_mk_path, workdir)) - return suite - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Test OpenCV for Android SDK with NDK') - parser.add_argument('--ndk_path', help="Path to Android NDK to use for build") - parser.add_argument("--workdir", default="testspace", help="Working directory (and output)") - parser.add_argument("opencv_mk_path", help="Path to folder with OpenCV.mk file (usually /sdk/native/jni/") - - args = parser.parse_args() - - if args.ndk_path is not None: - os.environ["ANDROID_NDK"] = os.path.abspath(args.ndk_path) - - print("Using NDK: %s" % os.environ["ANDROID_NDK"]) - - res = unittest.TextTestRunner(verbosity=3).run(suite(os.path.abspath(args.workdir), os.path.abspath(args.opencv_mk_path))) - if not res.wasSuccessful(): - sys.exit(res) diff --git a/platforms/android/build_sdk.py b/platforms/android/build_sdk.py index 4a5b8b19d6..b38fd7dc84 100755 --- a/platforms/android/build_sdk.py +++ b/platforms/android/build_sdk.py @@ -48,10 +48,6 @@ def check_dir(d, create=False, clean=False): os.makedirs(d) return d -def determine_engine_version(manifest_path): - with open(manifest_path, "rt") as f: - return re.search(r'android:versionName="(\d+\.\d+)"', f.read(), re.MULTILINE).group(1) - def determine_opencv_version(version_hpp_path): # version in 2.4 - CV_VERSION_EPOCH.CV_VERSION_MAJOR.CV_VERSION_MINOR.CV_VERSION_REVISION # version in master - CV_VERSION_MAJOR.CV_VERSION_MINOR.CV_VERSION_REVISION-CV_VERSION_STATUS @@ -133,7 +129,6 @@ class Builder: self.docdest = check_dir(os.path.join(self.workdir, 'OpenCV-android-sdk', 'sdk', 'java', 'javadoc'), create=True, clean=True) self.extra_packs = [] self.opencv_version = determine_opencv_version(os.path.join(self.opencvdir, "modules", "core", "include", "opencv2", "core", "version.hpp")) - self.engine_version = determine_engine_version(os.path.join(self.opencvdir, "platforms", "android", "service", "engine", "AndroidManifest.xml")) self.use_ccache = False if config.no_ccache else True def get_toolchain_file(self): @@ -163,6 +158,7 @@ class Builder: cmd = ["cmake", "-GNinja"] cmake_vars = dict( CMAKE_TOOLCHAIN_FILE=self.get_toolchain_file(), + INSTALL_CREATE_DISTRIB="ON", WITH_OPENCL="OFF", WITH_IPP=("ON" if abi.haveIPP() else "OFF"), WITH_TBB="ON", @@ -186,51 +182,7 @@ class Builder: cmd += [ "-D%s='%s'" % (k, v) for (k, v) in cmake_vars.items() if v is not None] cmd.append(self.opencvdir) execute(cmd) - if do_install: - execute(["ninja"]) - for c in ["libs", "dev", "java", "samples"]: - execute(["cmake", "-DCOMPONENT=%s" % c, "-P", "cmake_install.cmake"]) - else: - execute(["ninja", "install/strip"]) - - def build_engine(self, abi, engdest): - cmd = ["cmake", "-GNinja"] - cmake_vars = dict( - CMAKE_TOOLCHAIN_FILE=self.get_toolchain_file(), - WITH_OPENCL="OFF", - WITH_IPP="OFF", - BUILD_ANDROID_SERVICE = 'ON' - ) - cmake_vars.update(abi.cmake_vars) - cmd += [ "-D%s='%s'" % (k, v) for (k, v) in cmake_vars.items() if v is not None] - cmd.append(self.opencvdir) - execute(cmd) - apkdest = self.get_engine_apk_dest(engdest) - assert os.path.exists(apkdest), apkdest - # Add extra data - apkxmldest = check_dir(os.path.join(apkdest, "res", "xml"), create=True) - apklibdest = check_dir(os.path.join(apkdest, "libs", abi.name), create=True) - for ver, d in self.extra_packs + [("3.4.4", os.path.join(self.libdest, "lib"))]: - r = ET.Element("library", attrib={"version": ver}) - log.info("Adding libraries from %s", d) - - for f in glob.glob(os.path.join(d, abi.name, "*.so")): - log.info("Copy file: %s", f) - shutil.copy2(f, apklibdest) - if "libnative_camera" in f: - continue - log.info("Register file: %s", os.path.basename(f)) - n = ET.SubElement(r, "file", attrib={"name": os.path.basename(f)}) - - if len(list(r)) > 0: - xmlname = os.path.join(apkxmldest, "config%s.xml" % ver.replace(".", "")) - log.info("Generating XML config: %s", xmlname) - ET.ElementTree(r).write(xmlname, encoding="utf-8") - - execute(["ninja", "opencv_engine"]) - execute(["ant", "-f", os.path.join(apkdest, "build.xml"), "debug"], - shell=(sys.platform == 'win32')) - # TODO: Sign apk + execute(["ninja", "install/strip"]) def build_javadoc(self): classpaths = [] @@ -251,7 +203,7 @@ class Builder: ] execute(cmd) - def gather_results(self, engines): + def gather_results(self): # Copy all files root = os.path.join(self.libdest, "install") for item in os.listdir(root): @@ -270,25 +222,6 @@ class Builder: else: shutil.move(src, dst) - # Copy engines for all platforms - for abi, engdest in engines: - log.info("Copy engine: %s (%s)", abi, engdest) - f = os.path.join(self.get_engine_apk_dest(engdest), "bin", "opencv_engine-debug.apk") - resname = "OpenCV_%s_Manager_%s_%s.apk" % (self.opencv_version, self.engine_version, abi) - dst = os.path.join(self.resultdest, "apk", resname) - if self.config.force_copy: - shutil.copy2(f, dst) - else: - shutil.move(f, dst) - - # Clean samples - path = os.path.join(self.resultdest, "samples") - for item in os.listdir(path): - item = os.path.join(path, item) - if os.path.isdir(item): - for name in ["build.xml", "local.properties", "proguard-project.txt"]: - rm_one(os.path.join(item, name)) - #=================================================================================================== @@ -296,14 +229,13 @@ if __name__ == "__main__": parser = argparse.ArgumentParser(description='Build OpenCV for Android SDK') parser.add_argument("work_dir", nargs='?', default='.', help="Working directory (and output)") parser.add_argument("opencv_dir", nargs='?', default=os.path.join(SCRIPT_DIR, '../..'), help="Path to OpenCV source dir") - parser.add_argument('--config', default='ndk-10.config.py', type=str, help="Package build configuration", ) + parser.add_argument('--config', default='ndk-18.config.py', type=str, help="Package build configuration", ) parser.add_argument('--ndk_path', help="Path to Android NDK to use for build") parser.add_argument('--sdk_path', help="Path to Android SDK to use for build") parser.add_argument("--extra_modules_path", help="Path to extra modules to use for build") parser.add_argument('--sign_with', help="Certificate to sign the Manager apk") parser.add_argument('--build_doc', action="store_true", help="Build javadoc") parser.add_argument('--no_ccache', action="store_true", help="Do not use ccache during library build") - parser.add_argument('--extra_pack', action='append', help="provide extra OpenCV libraries for Manager apk in form :, for example '2.4.11:unpacked/sdk/native/libs'") parser.add_argument('--force_copy', action="store_true", help="Do not use file move during library build (useful for debug)") parser.add_argument('--force_opencv_toolchain', action="store_true", help="Do not use toolchain from Android NDK") args = parser.parse_args() @@ -316,6 +248,9 @@ if __name__ == "__main__": if args.sdk_path is not None: os.environ["ANDROID_SDK"] = args.sdk_path + if not 'ANDROID_HOME' in os.environ and 'ANDROID_SDK' in os.environ: + os.environ['ANDROID_HOME'] = os.environ["ANDROID_SDK"] + if os.path.realpath(args.work_dir) == os.path.realpath(SCRIPT_DIR): raise Fail("Specify workdir (building from script directory is not supported)") if os.path.realpath(args.work_dir) == os.path.realpath(args.opencv_dir): @@ -348,20 +283,9 @@ if __name__ == "__main__": builder = Builder(args.work_dir, args.opencv_dir, args) log.info("Detected OpenCV version: %s", builder.opencv_version) - log.info("Detected Engine version: %s", builder.engine_version) - if args.extra_pack: - for one in args.extra_pack: - i = one.find(":") - if i > 0 and i < len(one) - 1: - builder.add_extra_pack(one[:i], one[i+1:]) - else: - raise Fail("Bad extra pack provided: %s, should be in form ':'" % one) - - engines = [] for i, abi in enumerate(ABIs): do_install = (i == 0) - engdest = check_dir(os.path.join(builder.workdir, "build_service_%s" % abi.name), create=True, clean=True) log.info("=====") log.info("===== Building library for %s", abi) @@ -371,15 +295,7 @@ if __name__ == "__main__": builder.clean_library_build_dir() builder.build_library(abi, do_install) - log.info("=====") - log.info("===== Building engine for %s", abi) - log.info("=====") - - os.chdir(engdest) - builder.build_engine(abi, engdest) - engines.append((abi.name, engdest)) - - builder.gather_results(engines) + builder.gather_results() if args.build_doc: builder.build_javadoc() diff --git a/platforms/android/ndk-18.config.py b/platforms/android/ndk-18.config.py new file mode 100644 index 0000000000..9a9b5cc3e8 --- /dev/null +++ b/platforms/android/ndk-18.config.py @@ -0,0 +1,6 @@ +ABIs = [ + ABI("2", "armeabi-v7a", None, cmake_vars=dict(ANDROID_ABI='armeabi-v7a with NEON')), + ABI("3", "arm64-v8a", None), + ABI("5", "x86_64", None), + ABI("4", "x86", None), +] diff --git a/platforms/android/service/CMakeLists.txt b/platforms/android/service/CMakeLists.txt index b031003177..66e0c468a9 100644 --- a/platforms/android/service/CMakeLists.txt +++ b/platforms/android/service/CMakeLists.txt @@ -1,3 +1,8 @@ +if(NOT ANDROID_PROJECTS_BUILD_TYPE STREQUAL "ANT") + message(STATUS "Android OpenCV Manager is ignored") + return() +endif() + if(BUILD_ANDROID_SERVICE) add_subdirectory(engine) endif() diff --git a/samples/android/15-puzzle/build.gradle.in b/samples/android/15-puzzle/build.gradle.in new file mode 100644 index 0000000000..ad5c9f93f9 --- /dev/null +++ b/samples/android/15-puzzle/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.puzzle15" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/15-puzzle/gradle/AndroidManifest.xml b/samples/android/15-puzzle/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..c0c6cbbc8d --- /dev/null +++ b/samples/android/15-puzzle/gradle/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/CMakeLists.txt b/samples/android/CMakeLists.txt index 6135eaa0e6..360f1aa2cb 100644 --- a/samples/android/CMakeLists.txt +++ b/samples/android/CMakeLists.txt @@ -15,12 +15,3 @@ add_subdirectory(tutorial-1-camerapreview) add_subdirectory(tutorial-2-mixedprocessing) add_subdirectory(tutorial-3-cameracontrol) add_subdirectory(tutorial-4-opencl) - -# hello-android sample -if(HAVE_opencv_highgui) - add_executable(hello-android hello-android/main.cpp) - ocv_target_include_modules_recurse(hello-android opencv_imgcodecs opencv_videoio opencv_highgui opencv_core opencv_imgproc) - ocv_target_link_libraries(hello-android ${OPENCV_LINKER_LIBS} opencv_imgcodecs opencv_videoio opencv_highgui opencv_core opencv_imgproc) - set_target_properties(hello-android PROPERTIES OUTPUT_NAME hello-android RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}") - add_dependencies(opencv_android_examples hello-android) -endif() diff --git a/samples/android/build.gradle.in b/samples/android/build.gradle.in new file mode 100644 index 0000000000..49a60e290e --- /dev/null +++ b/samples/android/build.gradle.in @@ -0,0 +1,66 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:@ANDROID_GRADLE_PLUGIN_VERSION@' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} + +//allprojects { +// gradle.projectsEvaluated { +// tasks.withType(JavaCompile) { +// options.compilerArgs << "-Xlint:unchecked" +// options.compilerArgs << "-Xlint:deprecation" +// } +// } +//} + + +gradle.afterProject { project -> + if (project.pluginManager.hasPlugin('com.android.application') + || project.pluginManager.hasPlugin('com.android.library') + || project.pluginManager.hasPlugin('com.android.test') + || project.pluginManager.hasPlugin('com.android.feature') ) { + if (true) { + gradle.println("Override build ABIs for the project ${project.name}") + project.android { + splits { + abi { + enable true + universalApk false + @ANDROID_ABI_FILTER@ + } + } + } + } + + if (true) { + gradle.println("Override lintOptions for the project ${project.name}") + project.android { + lintOptions { + // checkReleaseBuilds false + abortOnError false + } + } + } + } +} diff --git a/samples/android/camera-calibration/build.gradle.in b/samples/android/camera-calibration/build.gradle.in new file mode 100644 index 0000000000..d62b151867 --- /dev/null +++ b/samples/android/camera-calibration/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.cameracalibration" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/camera-calibration/gradle/AndroidManifest.xml b/samples/android/camera-calibration/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..11444ff48c --- /dev/null +++ b/samples/android/camera-calibration/gradle/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/color-blob-detection/build.gradle.in b/samples/android/color-blob-detection/build.gradle.in new file mode 100644 index 0000000000..8900e25c16 --- /dev/null +++ b/samples/android/color-blob-detection/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.colorblobdetect" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/color-blob-detection/gradle/AndroidManifest.xml b/samples/android/color-blob-detection/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..1f09a5e3ca --- /dev/null +++ b/samples/android/color-blob-detection/gradle/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/face-detection/build.gradle.in b/samples/android/face-detection/build.gradle.in new file mode 100644 index 0000000000..9e3b187a84 --- /dev/null +++ b/samples/android/face-detection/build.gradle.in @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.facedetect" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + + externalNativeBuild { + cmake { + arguments "-DOpenCV_DIR=" + project(':opencv').projectDir + "/@ANDROID_PROJECT_JNI_PATH@"@OPENCV_ANDROID_CMAKE_EXTRA_ARGS@ + targets "detection_based_tracker" + } + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } + externalNativeBuild { + cmake { + path '@ANDROID_SAMPLE_JNI_PATH@/CMakeLists.txt' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/face-detection/gradle/AndroidManifest.xml b/samples/android/face-detection/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..c9c69fd243 --- /dev/null +++ b/samples/android/face-detection/gradle/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/face-detection/jni/CMakeLists.txt b/samples/android/face-detection/jni/CMakeLists.txt new file mode 100644 index 0000000000..d395999ce0 --- /dev/null +++ b/samples/android/face-detection/jni/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.6) + +# Enable C++11 +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +set(target detection_based_tracker) +project(${target} CXX) + +set(ANDROID_OPENCV_COMPONENTS "opencv_java" CACHE STRING "") +message(STATUS "ANDROID_ABI=${ANDROID_ABI}") +find_package(OpenCV REQUIRED COMPONENTS ${ANDROID_OPENCV_COMPONENTS}) + +file(GLOB srcs *.cpp *.c) +file(GLOB hdrs *.hpp *.h) + +include_directories("${CMAKE_CURRENT_LIST_DIR}") +add_library(${target} SHARED ${srcs} ${hdrs}) +target_link_libraries(${target} ${ANDROID_OPENCV_COMPONENTS}) diff --git a/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp b/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp index ef8c26f85b..6ce36bc527 100644 --- a/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp +++ b/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp @@ -96,8 +96,8 @@ JNIEXPORT jlong JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker je = jenv->FindClass("java/lang/Exception"); jenv->ThrowNew(je, e.what()); } - catch (...) - { + catch (...) + { LOGD("nativeCreateObject caught unknown exception"); jclass je = jenv->FindClass("java/lang/Exception"); jenv->ThrowNew(je, "Unknown exception in JNI code of DetectionBasedTracker.nativeCreateObject()"); diff --git a/samples/android/hello-android/CMakeLists.txt b/samples/android/hello-android/CMakeLists.txt deleted file mode 100644 index 032d98369d..0000000000 --- a/samples/android/hello-android/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) - -######################################################### -# Set project name -######################################################### - -IF( NOT PROJECT_NAME ) - IF ( NOT "x$ENV{PROJECT_NAME}" STREQUAL "x" ) - SET( PROJECT_NAME $ENV{PROJECT_NAME} ) - ELSE() - SET( PROJECT_NAME hello-android ) - ENDIF() -ENDIF() -SET( PROJECT_NAME ${PROJECT_NAME} CACHE STRING "The name of your project") - -PROJECT( ${PROJECT_NAME} ) - -######################################################### -# Find OpenCV -######################################################### - -FIND_PACKAGE( OpenCV REQUIRED ) - -######################################################### -# c/c++ flags, includes and lib dependencies -######################################################### - -#notice the "recycling" of CMAKE_C_FLAGS -#this is necessary to pick up android flags -SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic" ) -SET( CMAKE_CPP_FLAGS "${CMAKE_CPP_FLAGS} -Wall -pedantic" ) - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -SET( LIBRARY_DEPS ${OpenCV_LIBS} ) -IF( ANDROID ) - SET( LIBRARY_DEPS ${LIBRARY_DEPS} log dl ) -ENDIF() - -######################################################### -# source files -######################################################### - -FILE( GLOB hdrs "*.h*" ) -FILE( GLOB srcs "*.cpp" ) - -ADD_EXECUTABLE( ${PROJECT_NAME} ${srcs} ) -TARGET_LINK_LIBRARIES( ${PROJECT_NAME} ${LIBRARY_DEPS} ) - -######################################################### -# Summary report -######################################################### -message( STATUS "") -message( STATUS "General configuration for ${PROJECT_NAME} =====================================") -message( STATUS "") -message( STATUS " OpenCV path: ${OpenCV_DIR}") -message( STATUS " Compiler: ${CMAKE_CXX_COMPILER}") -message( STATUS " C++ flags (Release): ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}") -message( STATUS " C++ flags (Debug): ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}") -if(WIN32) -message( STATUS " Linker flags (Release): ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -message( STATUS " Linker flags (Debug): ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") -else() -message( STATUS " Linker flags (Release): ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -message( STATUS " Linker flags (Debug): ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") -endif() diff --git a/samples/android/hello-android/cmake_android.cmd b/samples/android/hello-android/cmake_android.cmd deleted file mode 100644 index 65a1461c2f..0000000000 --- a/samples/android/hello-android/cmake_android.cmd +++ /dev/null @@ -1,9 +0,0 @@ -@ECHO OFF -SETLOCAL -PUSHD %~dp0 -SET PROJECT_NAME=hello-android -SET BUILD_DIR=build_armeabi -SET ANDROID_ABI=armeabi -CALL ..\..\..\android\scripts\build.cmd %* -POPD -ENDLOCAL diff --git a/samples/android/hello-android/cmake_android.sh b/samples/android/hello-android/cmake_android.sh deleted file mode 100755 index f233e302ee..0000000000 --- a/samples/android/hello-android/cmake_android.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -cd `dirname $0` - -BUILD_DIR=build_armeabi -opencv_android=`pwd`/../../../android -opencv_build_dir=$opencv_android/$BUILD_DIR - -mkdir -p $BUILD_DIR -cd $BUILD_DIR - -RUN_CMAKE="cmake -DOpenCV_DIR=$opencv_build_dir -DARM_TARGET=armeabi -DCMAKE_TOOLCHAIN_FILE=$opencv_android/android.toolchain.cmake .." -echo $RUN_CMAKE -$RUN_CMAKE diff --git a/samples/android/hello-android/main.cpp b/samples/android/hello-android/main.cpp deleted file mode 100644 index 8684029672..0000000000 --- a/samples/android/hello-android/main.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include -#include - -using namespace cv; -const char* message = "Hello Android!"; - -int main(int argc, char* argv[]) -{ - (void)argc; (void)argv; - // print message to console - printf("%s\n", message); - - // put message to simple image - Size textsize = getTextSize(message, FONT_HERSHEY_COMPLEX, 3, 5, 0); - Mat img(textsize.height + 20, textsize.width + 20, CV_32FC1, Scalar(230,230,230)); - putText(img, message, Point(10, img.rows - 10), FONT_HERSHEY_COMPLEX, 3, Scalar(0, 0, 0), 5); - - // save\show resulting image -#if ANDROID - imwrite("/mnt/sdcard/HelloAndroid.png", img); -#else - imshow("test", img); - waitKey(); -#endif - return 0; -} diff --git a/samples/android/hello-android/run.cmd b/samples/android/hello-android/run.cmd deleted file mode 100644 index 54a73f0402..0000000000 --- a/samples/android/hello-android/run.cmd +++ /dev/null @@ -1,49 +0,0 @@ -:: this batch file copies compiled executable to the device, -:: runs it and gets resulting image back to the host -:: -:: Here is sample output of successful run: -:: -:: 204 KB/s (2887388 bytes in 13.790s) -:: Hello Android! -:: 304 KB/s (8723 bytes in 0.028s) - -@ECHO OFF - -:: enable command extensions -VERIFY BADVALUE 2>NUL -SETLOCAL ENABLEEXTENSIONS || (ECHO Unable to enable command extensions. & EXIT \B) - -PUSHD %~dp0 -:: project specific settings -SET PROJECT_NAME=hello-android - -:: try to load config file -SET CFG_PATH=..\..\..\android\scripts\wincfg.cmd -IF EXIST %CFG_PATH% CALL %CFG_PATH% - -:: check if sdk path defined -IF NOT DEFINED ANDROID_SDK (ECHO. & ECHO You should set an environment variable ANDROID_SDK to the full path to your copy of Android SDK & GOTO end) -(PUSHD "%ANDROID_SDK%" 2>NUL && POPD) || (ECHO. & ECHO Directory "%ANDROID_SDK%" specified by ANDROID_SDK variable does not exist & GOTO end) -SET adb=%ANDROID_SDK%\platform-tools\adb.exe - -:: copy file to device (usually takes 10 seconds or more) -%adb% push .\bin\%PROJECT_NAME% /data/bin/sample/%PROJECT_NAME% || GOTO end - -:: set execute permission -%adb% shell chmod 777 /data/bin/sample/%PROJECT_NAME% || GOTO end - -:: execute our application -%adb% shell /data/bin/sample/%PROJECT_NAME% || GOTO end - -:: get image result from device -%adb% pull /mnt/sdcard/HelloAndroid.png || GOTO end - -GOTO end - -:: cleanup (comment out GOTO above to enable cleanup) -%adb% shell rm /data/bin/sample/%PROJECT_NAME% -%adb% shell rm /mnt/sdcard/HelloAndroid.png - -:end -POPD -ENDLOCAL diff --git a/samples/android/hello-android/run.sh b/samples/android/hello-android/run.sh deleted file mode 100755 index 1168c51df6..0000000000 --- a/samples/android/hello-android/run.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -cd `dirname $0` -PROJECT_NAME=hello-android - -# copy file to device (usually takes 10 seconds or more) -adb push ./bin/$PROJECT_NAME /data/bin/sample/$PROJECT_NAME || return - -# set execute permission -adb shell chmod 777 /data/bin/sample/$PROJECT_NAME || return - -# execute our application -adb shell /data/bin/sample/$PROJECT_NAME || return - -# get image result from device -adb pull /mnt/sdcard/HelloAndroid.png || return diff --git a/samples/android/image-manipulations/build.gradle.in b/samples/android/image-manipulations/build.gradle.in new file mode 100644 index 0000000000..0d685ed410 --- /dev/null +++ b/samples/android/image-manipulations/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.imagemanipulations" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/image-manipulations/gradle/AndroidManifest.xml b/samples/android/image-manipulations/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..5c3b71a77b --- /dev/null +++ b/samples/android/image-manipulations/gradle/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/mobilenet-objdetect/AndroidManifest.xml b/samples/android/mobilenet-objdetect/AndroidManifest.xml index cfe8d4ed69..e8d17ba6a3 100644 --- a/samples/android/mobilenet-objdetect/AndroidManifest.xml +++ b/samples/android/mobilenet-objdetect/AndroidManifest.xml @@ -2,27 +2,27 @@ - - - - - - - - + + + + + + + + - - - - - - + + + + + + diff --git a/samples/android/mobilenet-objdetect/build.gradle.in b/samples/android/mobilenet-objdetect/build.gradle.in new file mode 100644 index 0000000000..e8238f7324 --- /dev/null +++ b/samples/android/mobilenet-objdetect/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.opencv_mobilenet" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 341 + versionName "3.41" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/mobilenet-objdetect/gradle/AndroidManifest.xml b/samples/android/mobilenet-objdetect/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..d17e633b41 --- /dev/null +++ b/samples/android/mobilenet-objdetect/gradle/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/tutorial-1-camerapreview/build.gradle.in b/samples/android/tutorial-1-camerapreview/build.gradle.in new file mode 100644 index 0000000000..5a649175dc --- /dev/null +++ b/samples/android/tutorial-1-camerapreview/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.tutorial1" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/tutorial-1-camerapreview/gradle/AndroidManifest.xml b/samples/android/tutorial-1-camerapreview/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..490dd6a1e7 --- /dev/null +++ b/samples/android/tutorial-1-camerapreview/gradle/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/tutorial-2-mixedprocessing/build.gradle.in b/samples/android/tutorial-2-mixedprocessing/build.gradle.in new file mode 100644 index 0000000000..7eca49b1b1 --- /dev/null +++ b/samples/android/tutorial-2-mixedprocessing/build.gradle.in @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.tutorial2" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + + externalNativeBuild { + cmake { + arguments "-DOpenCV_DIR=" + project(':opencv').projectDir + "/@ANDROID_PROJECT_JNI_PATH@"@OPENCV_ANDROID_CMAKE_EXTRA_ARGS@ + targets "mixed_sample" + } + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } + externalNativeBuild { + cmake { + path '@ANDROID_SAMPLE_JNI_PATH@/CMakeLists.txt' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/tutorial-2-mixedprocessing/gradle/AndroidManifest.xml b/samples/android/tutorial-2-mixedprocessing/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..34753e4daa --- /dev/null +++ b/samples/android/tutorial-2-mixedprocessing/gradle/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/tutorial-2-mixedprocessing/jni/CMakeLists.txt b/samples/android/tutorial-2-mixedprocessing/jni/CMakeLists.txt new file mode 100644 index 0000000000..2219121fde --- /dev/null +++ b/samples/android/tutorial-2-mixedprocessing/jni/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.6) + +# Enable C++11 +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +set(target mixed_sample) +project(${target} CXX) + +set(ANDROID_OPENCV_COMPONENTS "opencv_java" CACHE STRING "") +message(STATUS "ANDROID_ABI=${ANDROID_ABI}") +find_package(OpenCV REQUIRED COMPONENTS ${ANDROID_OPENCV_COMPONENTS}) + +file(GLOB srcs *.cpp *.c) +file(GLOB hdrs *.hpp *.h) + +include_directories("${CMAKE_CURRENT_LIST_DIR}") +add_library(${target} SHARED ${srcs} ${hdrs}) +target_link_libraries(${target} ${ANDROID_OPENCV_COMPONENTS}) diff --git a/samples/android/tutorial-3-cameracontrol/build.gradle.in b/samples/android/tutorial-3-cameracontrol/build.gradle.in new file mode 100644 index 0000000000..0ba304f5e5 --- /dev/null +++ b/samples/android/tutorial-3-cameracontrol/build.gradle.in @@ -0,0 +1,31 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.tutorial3" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/tutorial-3-cameracontrol/gradle/AndroidManifest.xml b/samples/android/tutorial-3-cameracontrol/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..4985185b10 --- /dev/null +++ b/samples/android/tutorial-3-cameracontrol/gradle/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/tutorial-4-opencl/build.gradle.in b/samples/android/tutorial-4-opencl/build.gradle.in new file mode 100644 index 0000000000..2cb9a7bcb9 --- /dev/null +++ b/samples/android/tutorial-4-opencl/build.gradle.in @@ -0,0 +1,43 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion @ANDROID_COMPILE_SDK_VERSION@ + defaultConfig { + applicationId "org.opencv.samples.tutorial4" + minSdkVersion @ANDROID_MIN_SDK_VERSION@ + targetSdkVersion @ANDROID_TARGET_SDK_VERSION@ + versionCode 301 + versionName "3.01" + + externalNativeBuild { + cmake { + arguments "-DOpenCV_DIR=" + project(':opencv').projectDir + "/@ANDROID_PROJECT_JNI_PATH@"@OPENCV_ANDROID_CMAKE_EXTRA_ARGS@ + targets "JNIpart" + } + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + sourceSets { + main { + java.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + aidl.srcDirs = @ANDROID_SAMPLE_JAVA_PATH@ + res.srcDirs = @ANDROID_SAMPLE_RES_PATH@ + manifest.srcFile '@ANDROID_SAMPLE_MANIFEST_PATH@' + } + } + externalNativeBuild { + cmake { + path '@ANDROID_SAMPLE_JNI_PATH@/CMakeLists.txt' + } + } +} + +dependencies { + //implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation project(':opencv') +} diff --git a/samples/android/tutorial-4-opencl/gradle/AndroidManifest.xml b/samples/android/tutorial-4-opencl/gradle/AndroidManifest.xml new file mode 100644 index 0000000000..6bce3c7191 --- /dev/null +++ b/samples/android/tutorial-4-opencl/gradle/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/samples/android/tutorial-4-opencl/jni/CMakeLists.txt b/samples/android/tutorial-4-opencl/jni/CMakeLists.txt new file mode 100644 index 0000000000..6b3f3a0940 --- /dev/null +++ b/samples/android/tutorial-4-opencl/jni/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.6) + +# Enable C++11 +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +set(target mixed_sample) +project(${target} CXX) + +set(ANDROID_OPENCV_COMPONENTS "opencv_java" CACHE STRING "") +message(STATUS "ANDROID_ABI=${ANDROID_ABI}") +find_package(OpenCV REQUIRED COMPONENTS ${ANDROID_OPENCV_COMPONENTS}) + +file(GLOB srcs *.cpp *.c) +file(GLOB hdrs *.hpp *.h) + +include_directories("${CMAKE_CURRENT_LIST_DIR}") +add_library(${target} SHARED ${srcs} ${hdrs}) +target_link_libraries(${target} ${ANDROID_OPENCV_COMPONENTS} -lGLESv2 -lEGL -lOpenCL) From cbf80117afb488e7f18bf1616b30169e5f652f20 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 19 Dec 2018 15:42:38 +0300 Subject: [PATCH 3/3] eliminate build warnings --- 3rdparty/carotene/hal/CMakeLists.txt | 2 ++ 3rdparty/cpufeatures/cpu-features.h | 1 + 2 files changed, 3 insertions(+) diff --git a/3rdparty/carotene/hal/CMakeLists.txt b/3rdparty/carotene/hal/CMakeLists.txt index e382f037e8..c4b9acaedd 100644 --- a/3rdparty/carotene/hal/CMakeLists.txt +++ b/3rdparty/carotene/hal/CMakeLists.txt @@ -12,6 +12,8 @@ elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64.*|AARCH64.*") set(AARCH64 TRUE) endif() +ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-function) + set(TEGRA_COMPILER_FLAGS "") if(CV_GCC OR CV_CLANG) diff --git a/3rdparty/cpufeatures/cpu-features.h b/3rdparty/cpufeatures/cpu-features.h index 1e9724197a..e109f02cf0 100644 --- a/3rdparty/cpufeatures/cpu-features.h +++ b/3rdparty/cpufeatures/cpu-features.h @@ -30,6 +30,7 @@ #include #include +#include __BEGIN_DECLS