diff --git a/libraries/include/arcore_c_api.h b/libraries/include/arcore_c_api.h index 19ff3bf1b..abbadd815 100644 --- a/libraries/include/arcore_c_api.h +++ b/libraries/include/arcore_c_api.h @@ -110,6 +110,9 @@ /// @defgroup config Configuration /// Session configuration. +/// @defgroup cameraconfig CameraConfig +/// Camera configuration. + /// @defgroup frame Frame /// Per-frame state. @@ -158,10 +161,31 @@ typedef struct ArConfig_ ArConfig; /// @} +// CameraConfig objects and list. + +/// @addtogroup cameraconfig +/// @{ + +/// A camera config struct that contains the config supported by +/// the physical camera obtained from the low level device profiles. +/// (@ref ownership "value type"). +/// +/// Allocate with ArCameraConfig_create()
+/// Release with ArCameraConfig_destroy() +typedef struct ArCameraConfig_ ArCameraConfig; + +/// A list of camera config (@ref ownership "value type"). +/// +/// Allocate with ArCameraConfigList_create()
+/// Release with ArCameraConfigList_destroy() +typedef struct ArCameraConfigList_ ArCameraConfigList; + +/// @} + /// @addtogroup session /// @{ -/// The ArCore session (@ref ownership "value type"). +/// The ARCore session (@ref ownership "value type"). /// /// Create with ArSession_create()
/// Release with ArSession_destroy() @@ -443,7 +467,7 @@ inline ArPoint *ArAsPoint(ArTrackable *trackable) { inline ArAugmentedImage *ArAsAugmentedImage(ArTrackable *trackable) { return reinterpret_cast(trackable); } -#endif +#endif // __cplusplus /// @} // If compiling for C++11, use the 'enum underlying type' feature to enforce @@ -568,6 +592,13 @@ AR_DEFINE_ENUM(ArStatus){ /// of the SDK. AR_ERROR_DATA_UNSUPPORTED_VERSION = -19, + /// A function has been invoked at an illegal or inappropriate time. A + /// message will be printed to logcat with additional details for the + /// developer. For example, ArSession_resume() will return this status if + /// the camera configuration was changed and there are any unreleased + /// images. + AR_ERROR_ILLEGAL_STATE = -20, + /// The ARCore APK is not installed on this device. AR_UNAVAILABLE_ARCORE_NOT_INSTALLED = -100, @@ -755,6 +786,24 @@ AR_DEFINE_ENUM(ArUpdateMode){ /// ::ArFrame object. AR_UPDATE_MODE_LATEST_CAMERA_IMAGE = 1}; +/// @ingroup config +/// Selects the desired behavior of the camera focus subsystem. Currently, the +/// default focus mode is AR_FOCUS_MODE_FIXED, but the default might change in +/// the future. +/// +/// For optimal AR tracking performance, use the focus mode provided by the +/// default session config. While capturing pictures or video, use +/// AR_FOCUS_MODE_AUTO. For optimal AR tracking, revert to the default focus +/// mode once auto focus behavior is no longer needed. If your app requires +/// fixed focus camera, call ArConfig_setFocusMode(…, …, AR_FOCUS_MODE_FIXED) +/// before enabling the AR session. This will ensure that your app always uses +/// fixed focus, even if the default camera config focus mode changes in a +/// future release. +AR_DEFINE_ENUM(ArFocusMode){/// Focus is fixed. + AR_FOCUS_MODE_FIXED = 0, + /// Auto-focus is enabled. + AR_FOCUS_MODE_AUTO = 1}; + /// @ingroup plane /// Simple summary of the normal vector of a plane, for filtering purposes. AR_DEFINE_ENUM(ArPlaneType){ @@ -794,8 +843,6 @@ AR_DEFINE_ENUM(ArCloudAnchorMode){ /// will require that the application have the Android INTERNET permission. AR_CLOUD_ANCHOR_MODE_ENABLED = 1}; -#undef AR_DEFINE_ENUM - #ifdef __cplusplus extern "C" { #endif @@ -1035,6 +1082,74 @@ void ArConfig_getAugmentedImageDatabase( const ArConfig *config, ArAugmentedImageDatabase *out_augmented_image_database); +/// Sets the focus mode that should be used. See ::ArFocusMode for available +/// options. +void ArConfig_setFocusMode(const ArSession *session, + ArConfig *config, + ArFocusMode focus_mode); + +/// Stores the currently configured focus mode into @c *focus_mode. +void ArConfig_getFocusMode(const ArSession *session, + ArConfig *config, + ArFocusMode *focus_mode); + +/// @} + +// === ArCameraConfigList and ArCameraConfig methods === + +/// @addtogroup cameraconfig +/// @{ + +// === ArCameraConfigList methods === + +/// Creates a camera config list object. +/// +/// @param[in] session The ARCore session +/// @param[out] out_list A pointer to an @c ArCameraConfigList* to receive +/// the address of the newly allocated ArCameraConfigList. +void ArCameraConfigList_create(const ArSession *session, + ArCameraConfigList **out_list); + +/// Releases the memory used by a camera config list object, +/// along with all the camera config references it holds. +void ArCameraConfigList_destroy(ArCameraConfigList *list); + +/// Retrieves the number of camera configs in this list. +void ArCameraConfigList_getSize(const ArSession *session, + const ArCameraConfigList *list, + int32_t *out_size); + +/// Retrieves the specific camera config based on the position in this list. +void ArCameraConfigList_getItem(const ArSession *session, + const ArCameraConfigList *list, + int32_t index, + ArCameraConfig *out_camera_config); + +// === ArCameraConfig methods === + +/// Creates a camera config object. +/// +/// @param[in] session The ARCore session +/// @param[out] out_camera_config A pointer to an @c ArCameraConfig* to receive +/// the address of the newly allocated ArCameraConfig. +void ArCameraConfig_create(const ArSession *session, + ArCameraConfig **out_camera_config); + +/// Releases the memory used by a camera config object. +void ArCameraConfig_destroy(ArCameraConfig *camera_config); + +/// Obtains the camera image dimensions for the given camera config. +void ArCameraConfig_getImageDimensions(const ArSession *session, + const ArCameraConfig *camera_config, + int32_t *out_width, + int32_t *out_height); + +/// Obtains the texture dimensions for the given camera config. +void ArCameraConfig_getTextureDimensions(const ArSession *session, + const ArCameraConfig *camera_config, + int32_t *out_width, + int32_t *out_height); + /// @} // === ArSession methods === @@ -1043,6 +1158,10 @@ void ArConfig_getAugmentedImageDatabase( /// @{ /// Releases resources used by an ARCore session. +/// This method will take several seconds to complete. To prevent blocking +/// the main thread, call ArSession_pause() on the main thread, and then call +/// ArSession_destroy() on a background thread. +/// void ArSession_destroy(ArSession *session); /// Before release 1.2.0: Checks if the provided configuration is usable on the @@ -1088,10 +1207,18 @@ void ArSession_getConfig(ArSession *session, ArConfig *out_config); /// href="https://developer.android.com/reference/android/app/Activity.html#onResume()" /// >Activity.onResume(). /// +/// Note that if the camera configuration has been changed by +/// ArSession_setCameraConfig() since the last call to ArSession_resume(), all +/// images previously acquired using ArFrame_acquireCameraImage() must be +/// released by calling ArImage_release() before calling ArSession_resume(). If +/// there are open images, ArSession_resume will return AR_ERROR_ILLEGAL_STATE +/// and the session will not resume. +/// /// @returns #AR_SUCCESS or any of: /// - #AR_ERROR_FATAL /// - #AR_ERROR_CAMERA_PERMISSION_NOT_GRANTED /// - #AR_ERROR_CAMERA_NOT_AVAILABLE +/// - #AR_ERROR_ILLEGAL_STATE ArStatus ArSession_resume(ArSession *session); /// Pause the current session. This method will stop the camera feed and release @@ -1101,6 +1228,9 @@ ArStatus ArSession_resume(ArSession *session); /// href="https://developer.android.com/reference/android/app/Activity.html#onPause()" /// >Activity.onPause(). /// +/// Note that ARCore might continue consuming substantial computing resources +/// for up to 10 seconds after calling this method. +/// /// @returns #AR_SUCCESS or any of: /// - #AR_ERROR_FATAL ArStatus ArSession_pause(ArSession *session); @@ -1248,6 +1378,57 @@ ArStatus ArSession_resolveAndAcquireNewCloudAnchor(ArSession *session, const char *cloud_anchor_id, ArAnchor **out_cloud_anchor); +/// Enumerates the list of supported camera configs on the device. +/// Can be called at any time. The supported camera configs will be filled in +/// the provided list after clearing it. +/// +/// The list will always return 3 camera configs. The GPU texture resolutions +/// are the same in all three configs. Currently, most devices provide GPU +/// texture resolution of 1920 x 1080, but devices might provide higher or lower +/// resolution textures, depending on device capabilities. The CPU image +/// resolutions returned are VGA, 720p, and a resolution matching the GPU +/// texture. +/// +/// @param[in] session The ARCore session +/// @param[inout] list The list to fill. This list must have already +/// been allocated with ArCameraConfigList_create(). The list is cleared +/// to remove any existing elements. Once it is no longer needed, the list +/// must be destroyed using ArCameraConfigList_destroy to release allocated +/// memory. +void ArSession_getSupportedCameraConfigs(const ArSession *session, + ArCameraConfigList *list); + +/// Sets the ArCameraConfig that the ArSession should use. Can only be called +/// while the session is paused. The provided ArCameraConfig must be one of the +/// configs returned by ArSession_getSupportedCameraConfigs. +/// +/// The camera config will be applied once the session is resumed. +/// All previously acquired frame images must be released via ArImage_release +/// before calling resume(). Failure to do so will cause resume() to return +/// AR_ERROR_ILLEGAL_STATE error. +/// +/// @param[in] session The ARCore session +/// @param[in] camera_config The provided ArCameraConfig must be from a +/// list returned by ArSession_getSupportedCameraConfigs. +/// @return #AR_SUCCESS or any of: +/// - #AR_ERROR_INVALID_ARGUMENT +/// - #AR_ERROR_SESSION_NOT_PAUSED +ArStatus ArSession_setCameraConfig(const ArSession *session, + const ArCameraConfig *camera_config); + +/// Gets the ArCameraConfig that the ArSession is currently using. If the +/// camera config was not explicitly set then it returns the default +/// camera config. Use ArCameraConfig_destroy to release memory associated with +/// the returned camera config once it is no longer needed. +/// +/// @param[in] session The ARCore session +/// @param[inout] out_camera_config The camera config object to fill. This +/// object must have already been allocated with ArCameraConfig_create(). +/// Use ArCameraConfig_destroy to release memory associated with +/// out_camera_config once it is no longer needed. +void ArSession_getCameraConfig(const ArSession *session, + ArCameraConfig *out_camera_config); + /// @} // === ArPose methods === @@ -1526,6 +1707,24 @@ void ArFrame_hitTest(const ArSession *session, float pixel_y, ArHitResultList *hit_result_list); +/// Similar to ArFrame_hitTest, but takes an arbitrary ray in world space +/// coordinates instead of a screen space point. +/// +/// @param[in] session The ARCore session. +/// @param[in] frame The current frame. +/// @param[in] ray_origin_3 A pointer to float[3] array containing ray +/// origin in world space coordinates. +/// @param[in] ray_direction_3 A pointer to float[3] array containing ray +/// direction in world space coordinates. Does not have to be normalized. +/// @param[inout] hit_result_list The list to fill. This list must have been +/// previously allocated using ArHitResultList_create(). If the list has +/// been previously used, it will first be cleared. +void ArFrame_hitTestRay(const ArSession *session, + const ArFrame *frame, + const float *ray_origin_3, + const float *ray_direction_3, + ArHitResultList *hit_result_list); + /// Gets the current ambient light estimate, if light estimation was enabled. /// /// @param[in] session The ARCore session. @@ -1577,6 +1776,22 @@ ArStatus ArFrame_acquireImageMetadata(const ArSession *session, const ArFrame *frame, ArImageMetadata **out_metadata); +/// Gets the image of the tracking camera relative to the input session and +/// frame. Caller is responsible for later releasing the image with @c +/// ArImage_release. +/// Return values: +/// @returns #AR_SUCCESS or any of: +/// - #AR_ERROR_INVALID_ARGUMENT - one more input arguments are invalid. +/// - #AR_ERROR_DEADLINE_EXCEEDED - the input frame is not the current frame. +/// - #AR_ERROR_RESOURCE_EXHAUSTED - the caller app has exceeded maximum number +/// of images that it can hold without releasing. +/// - #AR_ERROR_NOT_YET_AVAILABLE - image with the timestamp of the input frame +/// was not found within a bounded amount of time, or the camera failed to +/// produce the image +ArStatus ArFrame_acquireCameraImage(ArSession *session, + ArFrame *frame, + ArImage **out_image); + /// Gets the set of anchors that were changed by the ArSession_update() that /// produced this Frame. /// @@ -1670,23 +1885,8 @@ void ArImageMetadata_getNdkCameraMetadata( /// This method may safely be called with @c nullptr - it will do nothing. void ArImageMetadata_release(ArImageMetadata *metadata); -// === CPU Image Access types and methods === -/// Gets the image of the tracking camera relative to the input session and -/// frame. -/// Return values: -/// @returns #AR_SUCCESS or any of: -/// - #AR_ERROR_INVALID_ARGUMENT - one more input arguments are invalid. -/// - #AR_ERROR_DEADLINE_EXCEEDED - the input frame is not the current frame. -/// - #AR_ERROR_RESOURCE_EXHAUSTED - the caller app has exceeded maximum number -/// of images that it can hold without releasing. -/// - #AR_ERROR_NOT_YET_AVAILABLE - image with the timestamp of the input frame -/// was not found within a bounded amount of time, or the camera failed to -/// produce the image -ArStatus ArFrame_acquireCameraImage(ArSession *session, - ArFrame *frame, - ArImage **out_image); - -/// Converts an ArImage object to an Android NDK AImage object. +/// Converts an ArImage object to an Android NDK AImage object. The +/// converted image object format is AIMAGE_FORMAT_YUV_420_888. void ArImage_getNdkImage(const ArImage *image, const AImage **out_ndk_image); /// Releases an instance of ArImage returned by ArFrame_acquireCameraImage(). @@ -2025,7 +2225,7 @@ void ArPoint_getPose(const ArSession *session, /// Returns the OrientationMode of the point. For @c Point objects created by /// ArFrame_hitTest(). /// If OrientationMode is ESTIMATED_SURFACE_NORMAL, then normal of the surface -/// centered around the ArPoint was estimated succesfully. +/// centered around the ArPoint was estimated successfully. /// /// @param[in] session The ARCore session. /// @param[in] point The point to retrieve the pose of. @@ -2340,6 +2540,8 @@ void ArString_release(char *str); /// Releases a byte array created using an ARCore API function. void ArByteArray_release(uint8_t *byte_array); +#undef AR_DEFINE_ENUM + #ifdef __cplusplus } #endif diff --git a/samples/augmented_image_c/app/build.gradle b/samples/augmented_image_c/app/build.gradle index 43cc8df0e..ce50fb089 100644 --- a/samples/augmented_image_c/app/build.gradle +++ b/samples/augmented_image_c/app/build.gradle @@ -32,6 +32,10 @@ android { abiFilters "arm64-v8a", "x86" } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -47,8 +51,8 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' - natives 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' + natives 'com.google.ar:core:1.4.0' implementation 'com.android.support:appcompat-v7:27.0.2' implementation 'com.android.support:design:27.0.2' diff --git a/samples/augmented_image_c/app/src/main/assets/models/andy.png b/samples/augmented_image_c/app/src/main/assets/models/andy.png index f88b1d6b4..6aa50ec2b 100644 Binary files a/samples/augmented_image_c/app/src/main/assets/models/andy.png and b/samples/augmented_image_c/app/src/main/assets/models/andy.png differ diff --git a/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar b/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar and b/samples/augmented_image_c/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/augmented_image_c/gradlew.bat b/samples/augmented_image_c/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/augmented_image_c/gradlew.bat +++ b/samples/augmented_image_c/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/augmented_image_java/app/build.gradle b/samples/augmented_image_java/app/build.gradle index d79b429a0..f48d6751e 100644 --- a/samples/augmented_image_java/app/build.gradle +++ b/samples/augmented_image_java/app/build.gradle @@ -11,7 +11,10 @@ android { versionCode 1 versionName "1.0" } - + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -22,7 +25,7 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/augmented_image_java/app/src/main/assets/models/andy.png b/samples/augmented_image_java/app/src/main/assets/models/andy.png index f88b1d6b4..6aa50ec2b 100644 Binary files a/samples/augmented_image_java/app/src/main/assets/models/andy.png and b/samples/augmented_image_java/app/src/main/assets/models/andy.png differ diff --git a/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java b/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java index d84573788..87dc77daa 100644 --- a/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java +++ b/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java @@ -123,7 +123,7 @@ public void update(PointCloud cloud) { } /** - * Renders the point cloud. ArCore point cloud is given in world space. + * Renders the point cloud. ARCore point cloud is given in world space. * * @param cameraView the camera view matrix for this frame, typically from {@link * com.google.ar.core.Camera#getViewMatrix(float[], int)}. diff --git a/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar b/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar and b/samples/augmented_image_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/augmented_image_java/gradlew.bat b/samples/augmented_image_java/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/augmented_image_java/gradlew.bat +++ b/samples/augmented_image_java/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/cloud_anchor_c/app/build.gradle b/samples/cloud_anchor_c/app/build.gradle index 05275a5c8..2f10d08af 100644 --- a/samples/cloud_anchor_c/app/build.gradle +++ b/samples/cloud_anchor_c/app/build.gradle @@ -32,6 +32,10 @@ android { abiFilters "arm64-v8a", "x86" } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -51,8 +55,8 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' - natives 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' + natives 'com.google.ar:core:1.4.0' implementation 'com.android.support:appcompat-v7:27.0.2' implementation 'com.android.support:design:27.0.2' diff --git a/samples/cloud_anchor_c/app/src/main/assets/models/andy.png b/samples/cloud_anchor_c/app/src/main/assets/models/andy.png index f88b1d6b4..6aa50ec2b 100644 Binary files a/samples/cloud_anchor_c/app/src/main/assets/models/andy.png and b/samples/cloud_anchor_c/app/src/main/assets/models/andy.png differ diff --git a/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.cc b/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.cc index ba597dcf4..148e610a6 100644 --- a/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.cc +++ b/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.cc @@ -4,6 +4,36 @@ #include "util.h" namespace cloud_anchor { +namespace { + +#define CASE_VALUE_RETURN_STRING(_value) \ + case _value: \ + return #_value; + +std::string CloudAnchorStateString(ArCloudAnchorState cloud_state) { + switch (cloud_state) { + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_SUCCESS); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_ERROR_INTERNAL); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_TASK_IN_PROGRESS); + CASE_VALUE_RETURN_STRING( + AR_CLOUD_ANCHOR_STATE_ERROR_HOSTING_DATASET_PROCESSING_FAILED); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_ERROR_SERVICE_UNAVAILABLE); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_ERROR_RESOURCE_EXHAUSTED); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_ERROR_CLOUD_ID_NOT_FOUND); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_ERROR_NOT_AUTHORIZED); + CASE_VALUE_RETURN_STRING( + AR_CLOUD_ANCHOR_STATE_ERROR_RESOLVING_LOCALIZATION_NO_MATCH); + CASE_VALUE_RETURN_STRING( + AR_CLOUD_ANCHOR_STATE_ERROR_RESOLVING_SDK_VERSION_TOO_NEW); + CASE_VALUE_RETURN_STRING( + AR_CLOUD_ANCHOR_STATE_ERROR_RESOLVING_SDK_VERSION_TOO_OLD); + CASE_VALUE_RETURN_STRING(AR_CLOUD_ANCHOR_STATE_NONE); + } +} + +#undef CASE_VALUE_RETURN_STRING + +} // namespace CloudAnchorManager::CloudAnchorManager() : host_resolve_mode_(HostResolveMode::NONE) {} @@ -53,22 +83,9 @@ void CloudAnchorManager::SetTrackedCloudAnchor(ArAnchor* anchor) { ArAnchor_release(ar_cloud_anchor_); } ar_cloud_anchor_ = anchor; - pending_anchor_ = nullptr; } -bool CloudAnchorManager::PromotePendingAnchorToCloudAnchor() { - // Note: This function is private and it is assumed the write lock is held. - if (!pending_anchor_) { - return false; - } - if (AnchorInReturnableState(pending_anchor_)) { - SetTrackedCloudAnchor(pending_anchor_); - return true; - } - return false; -} - void CloudAnchorManager::OnHostButtonPress() { std::lock_guard lock(mutex_); CHECK(host_resolve_mode_ == HostResolveMode::NONE || @@ -85,7 +102,7 @@ void CloudAnchorManager::OnHostButtonPress() { case HostResolveMode::HOSTING: // When the host button is pressed in hosting state, it cancels. SetTrackedCloudAnchor(nullptr); - host_resolve_mode_ = HostResolveMode::NONE, + host_resolve_mode_ = HostResolveMode::NONE; util::SetHostAndResolveButtonVisibility( util::HostResolveVisibilityEnum::ALL); util::UpdateFirebaseRoomCode(false, 0); @@ -168,9 +185,21 @@ void CloudAnchorManager::OnUpdate(const ArFrame* ar_frame) { CHECK(ar_session_); CHECK(ar_frame); - if (PromotePendingAnchorToCloudAnchor()) { + if (pending_anchor_ == nullptr || !AnchorInReturnableState(pending_anchor_)) { + return; + } + + ArCloudAnchorState cloud_state; + ArAnchor_getCloudAnchorState(ar_session_, pending_anchor_, &cloud_state); + if (cloud_state == AR_CLOUD_ANCHOR_STATE_SUCCESS) { + SetTrackedCloudAnchor(pending_anchor_); util::MaybeUpdateFirebase(GetCloudAnchorId()); + } else { + SetTrackedCloudAnchor(nullptr); + util::DisplayMessageOnLowerSnackbar("Error while hosting anchor: " + + CloudAnchorStateString(cloud_state)); } + host_resolve_mode_ = HostResolveMode::NONE; } const ArAnchor* CloudAnchorManager::GetCloudAnchor() const { diff --git a/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.h b/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.h index 1d97d5613..277eeba91 100644 --- a/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.h +++ b/samples/cloud_anchor_c/app/src/main/cpp/cloud_anchor_manager.h @@ -63,12 +63,6 @@ class CloudAnchorManager { // anchor will become unset. void SetTrackedCloudAnchor(ArAnchor* anchor); - // If there is a pending anchor and it has reached a valid tracking state then - // the current cloud anchor will be updated and this will return true. If - // this function returns false there either was no anchor pending or the - // anchor is not in a tracking state. - bool PromotePendingAnchorToCloudAnchor(); - // This pointer is owned by the application context. ArSession* ar_session_ = nullptr; diff --git a/samples/cloud_anchor_c/gradle/wrapper/gradle-wrapper.jar b/samples/cloud_anchor_c/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/cloud_anchor_c/gradle/wrapper/gradle-wrapper.jar and b/samples/cloud_anchor_c/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/cloud_anchor_c/gradlew.bat b/samples/cloud_anchor_c/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/cloud_anchor_c/gradlew.bat +++ b/samples/cloud_anchor_c/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/cloud_anchor_java/app/build.gradle b/samples/cloud_anchor_java/app/build.gradle index 7e16879b5..e5cd5fab6 100644 --- a/samples/cloud_anchor_java/app/build.gradle +++ b/samples/cloud_anchor_java/app/build.gradle @@ -25,7 +25,7 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/cloud_anchor_java/app/src/main/assets/models/andy.png b/samples/cloud_anchor_java/app/src/main/assets/models/andy.png index f88b1d6b4..6aa50ec2b 100644 Binary files a/samples/cloud_anchor_java/app/src/main/assets/models/andy.png and b/samples/cloud_anchor_java/app/src/main/assets/models/andy.png differ diff --git a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java index d84573788..87dc77daa 100644 --- a/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java +++ b/samples/cloud_anchor_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java @@ -123,7 +123,7 @@ public void update(PointCloud cloud) { } /** - * Renders the point cloud. ArCore point cloud is given in world space. + * Renders the point cloud. ARCore point cloud is given in world space. * * @param cameraView the camera view matrix for this frame, typically from {@link * com.google.ar.core.Camera#getViewMatrix(float[], int)}. diff --git a/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar b/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar and b/samples/cloud_anchor_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/cloud_anchor_java/gradlew.bat b/samples/cloud_anchor_java/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/cloud_anchor_java/gradlew.bat +++ b/samples/cloud_anchor_java/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/computervision_c/app/build.gradle b/samples/computervision_c/app/build.gradle index 31de9157c..e065fc90e 100644 --- a/samples/computervision_c/app/build.gradle +++ b/samples/computervision_c/app/build.gradle @@ -32,6 +32,10 @@ android { abiFilters "arm64-v8a", "x86" } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -47,8 +51,8 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' - natives 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' + natives 'com.google.ar:core:1.4.0' implementation 'com.android.support:appcompat-v7:27.0.2' implementation 'com.android.support:design:27.0.2' diff --git a/samples/computervision_c/app/src/main/cpp/computer_vision_application.cc b/samples/computervision_c/app/src/main/cpp/computer_vision_application.cc index 8477adf6d..a086d86b1 100644 --- a/samples/computervision_c/app/src/main/cpp/computer_vision_application.cc +++ b/samples/computervision_c/app/src/main/cpp/computer_vision_application.cc @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "util.h" @@ -51,9 +53,17 @@ ComputerVisionApplication::ComputerVisionApplication( : asset_manager_(asset_manager) {} ComputerVisionApplication::~ComputerVisionApplication() { - ArSession_destroy(ar_session_); - ArFrame_destroy(ar_frame_); - ArCameraIntrinsics_destroy(ar_camera_intrinsics_); + if (ar_session_ != nullptr) { + destroyCameraConfigs(); + ArSession_destroy(ar_session_); + ArConfig_destroy(ar_config_); + } + if (ar_frame_ != nullptr) { + ArFrame_destroy(ar_frame_); + } + if (ar_camera_intrinsics_ != nullptr) { + ArCameraIntrinsics_destroy(ar_camera_intrinsics_); + } } void ComputerVisionApplication::OnPause() { @@ -96,9 +106,14 @@ void ComputerVisionApplication::OnResume(void* env, void* context, CHECK(ArSession_create(env, context, &ar_session_) == AR_SUCCESS); CHECK(ar_session_); + ArConfig_create(ar_session_, &ar_config_); + CHECK(ar_config_); + ArFrame_create(ar_session_, &ar_frame_); CHECK(ar_frame_); + obtainCameraConfigs(); + ArCameraIntrinsics_create(ar_session_, &ar_camera_intrinsics_); CHECK(ar_camera_intrinsics_); @@ -158,21 +173,172 @@ void ComputerVisionApplication::OnDrawFrame(float split_position) { "ComputerVisionApplication::OnDrawFrame acquire camera image not " "ready."); } + cpu_image_renderer_.Draw(ar_session_, ar_frame_, ndk_image, aspect_ratio_, camera_to_display_rotation_, split_position); } +std::string ComputerVisionApplication::getCameraConfigLabel( + bool is_low_resolution) { + if (is_low_resolution && cpu_low_resolution_camera_config_ptr_ != nullptr) { + return "Low Resolution" + + cpu_low_resolution_camera_config_ptr_->config_label; + } else if (!is_low_resolution && + cpu_high_resolution_camera_config_ptr_ != nullptr) { + return "High Resolution" + + cpu_high_resolution_camera_config_ptr_->config_label; + } else { + return ""; + } +} + +ArStatus ComputerVisionApplication::setCameraConfig(bool is_low_resolution) { + // To change the AR camera config - first we pause the AR session, set the + // desired camera config and then resume the AR session. + CHECK(ar_session_) + + ArSession_pause(ar_session_); + + if (is_low_resolution) { + ArSession_setCameraConfig(ar_session_, + cpu_low_resolution_camera_config_ptr_->config); + } else { + ArSession_setCameraConfig(ar_session_, + cpu_high_resolution_camera_config_ptr_->config); + } + + ArStatus status = ArSession_resume(ar_session_); + if (status != ArStatus::AR_SUCCESS) { + // In a rare case (such as another camera app launching) the camera may be + // given to a different app and so may not be available to this app. Handle + // this properly and recreate the session at the next iteration. + ArSession_destroy(ar_session_); + ArConfig_destroy(ar_config_); + ArFrame_destroy(ar_frame_); + } + + return status; +} + +void ComputerVisionApplication::SetFocusMode(bool enable_auto_focus) { + CHECK(ar_session_); + CHECK(ar_config_); + + ArConfig_setFocusMode( + ar_session_, ar_config_, + enable_auto_focus ? AR_FOCUS_MODE_AUTO : AR_FOCUS_MODE_FIXED); + + CHECK(ArSession_configure(ar_session_, ar_config_) == AR_SUCCESS); +} + +bool ComputerVisionApplication::GetFocusMode() { + CHECK(ar_session_); + CHECK(ar_config_); + + ArFocusMode focus_mode; + ArConfig_getFocusMode(ar_session_, ar_config_, &focus_mode); + + return (focus_mode == AR_FOCUS_MODE_AUTO); +} + +void ComputerVisionApplication::obtainCameraConfigs() { + // Retrieve supported camera configs. + ArCameraConfigList* all_camera_configs = nullptr; + int32_t num_configs = 0; + ArCameraConfigList_create(ar_session_, &all_camera_configs); + ArSession_getSupportedCameraConfigs(ar_session_, all_camera_configs); + ArCameraConfigList_getSize(ar_session_, all_camera_configs, &num_configs); + + if (num_configs < 1) { + LOGE("No camera config found"); + return; + } + + camera_configs_.resize(num_configs); + for (int i = 0; i < num_configs; ++i) { + copyCameraConfig(ar_session_, all_camera_configs, i, num_configs, + &camera_configs_[i]); + } + + // Determine the highest and lowest CPU resolutions. + cpu_low_resolution_camera_config_ptr_ = nullptr; + cpu_high_resolution_camera_config_ptr_ = nullptr; + getCameraConfigLowestAndHighestResolutions( + &cpu_low_resolution_camera_config_ptr_, + &cpu_high_resolution_camera_config_ptr_); + + // Cleanup the list obtained as it is safe to destroy the list as camera + // config instances were explicitly created and copied. Refer to the + // previous comment. + ArCameraConfigList_destroy(all_camera_configs); +} + +void ComputerVisionApplication::getCameraConfigLowestAndHighestResolutions( + CameraConfig** lowest_resolution_config, + CameraConfig** highest_resolution_config) { + if (camera_configs_.empty()) { + return; + } + + int low_resolution_config_idx = 0; + int high_resolution_config_idx = 0; + int32_t smallest_height = camera_configs_[0].height; + int32_t largest_height = camera_configs_[0].height; + + for (int i = 1; i < camera_configs_.size(); ++i) { + int32_t image_height = camera_configs_[i].height; + if (image_height < smallest_height) { + smallest_height = image_height; + low_resolution_config_idx = i; + } else if (image_height > largest_height) { + largest_height = image_height; + high_resolution_config_idx = i; + } + } + + if (low_resolution_config_idx == high_resolution_config_idx) { + *lowest_resolution_config = &camera_configs_[low_resolution_config_idx]; + } else { + *lowest_resolution_config = &camera_configs_[low_resolution_config_idx]; + *highest_resolution_config = &camera_configs_[high_resolution_config_idx]; + } +} + +void ComputerVisionApplication::copyCameraConfig( + const ArSession* ar_session, const ArCameraConfigList* all_configs, + int index, int num_configs, CameraConfig* camera_config) { + if (camera_config != nullptr && index >= 0 && index < num_configs) { + ArCameraConfig_create(ar_session, &camera_config->config); + ArCameraConfigList_getItem(ar_session, all_configs, index, + camera_config->config); + ArCameraConfig_getImageDimensions(ar_session, camera_config->config, + &camera_config->width, + &camera_config->height); + camera_config->config_label = "(" + std::to_string(camera_config->width) + + "x" + std::to_string(camera_config->height) + + ")"; + } +} + +void ComputerVisionApplication::destroyCameraConfigs() { + for (int i = 0; i < camera_configs_.size(); ++i) { + if (camera_configs_[i].config != nullptr) { + ArCameraConfig_destroy(camera_configs_[i].config); + } + } +} + std::string ComputerVisionApplication::GetCameraIntrinsicsText( - bool show_cpu_intrinsics) { + bool for_gpu_texture) { if (ar_session_ == nullptr) return ""; ArCamera* ar_camera; ArFrame_acquireCamera(ar_session_, ar_frame_, &ar_camera); - if (show_cpu_intrinsics) { - ArCamera_getImageIntrinsics(ar_session_, ar_camera, ar_camera_intrinsics_); - } else { + if (for_gpu_texture) { ArCamera_getTextureIntrinsics(ar_session_, ar_camera, ar_camera_intrinsics_); + } else { + ArCamera_getImageIntrinsics(ar_session_, ar_camera, ar_camera_intrinsics_); } float fx; @@ -196,15 +362,17 @@ std::string ComputerVisionApplication::GetCameraIntrinsicsText( fov_x *= kRadiansToDegrees; fov_y *= kRadiansToDegrees; - std::string intrinsics_type_label(show_cpu_intrinsics ? "Image" : "Texture"); - - return "Unrotated Camera " + intrinsics_type_label + - " Intrinsics:\n\tFocal Length: (" + std::to_string(fx) + ", " + - std::to_string(fy) + ")\n\tPrincipal Point: (" + std::to_string(cx) + - ", " + std::to_string(cy) + ")\n\tImage Dimensions: (" + - std::to_string(image_width) + ", " + std::to_string(image_height) + - ")\n\tUnrotated Field of View: (" + std::to_string(fov_x) + "º, " + - std::to_string(fov_y) + "º)"; + std::ostringstream intrinsics_text; + intrinsics_text << std::fixed << std::setprecision(2) << "Unrotated Camera " + << (for_gpu_texture ? "GPU Texture" : "CPU Image") + << " Intrinsics:\n\tFocal Length: (" << fx << ", " << fy + << ")\n\tPrincipal Point: (" << cx << ", " << cy << ")\n\t" + << (for_gpu_texture ? "GPU" : "CPU") << " Image Dimensions: (" + << image_width << ", " << image_height + << ")\n\tUnrotated Field of View: (" << fov_x << "º, " + << fov_y << "º)"; + + return intrinsics_text.str(); } } // namespace computer_vision diff --git a/samples/computervision_c/app/src/main/cpp/computer_vision_application.h b/samples/computervision_c/app/src/main/cpp/computer_vision_application.h index 57ccb1531..3a1e85ea1 100644 --- a/samples/computervision_c/app/src/main/cpp/computer_vision_application.h +++ b/samples/computervision_c/app/src/main/cpp/computer_vision_application.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "arcore_c_api.h" #include "cpu_image_renderer.h" @@ -62,11 +63,22 @@ class ComputerVisionApplication { // OnDrawFrame is called on the OpenGL thread to render the next frame. void OnDrawFrame(float split_position); + // Get the text label of a camera config. + // Return an empty string if the camera config is not available. + std::string getCameraConfigLabel(bool is_low_resolution); + + // Set camera config with low or high resolution. + ArStatus setCameraConfig(bool is_low_resolution); + + void SetFocusMode(bool enable_auto_focus); + bool GetFocusMode(); + // Get the text logs for the camera intrinsics. - std::string GetCameraIntrinsicsText(bool show_cpu_intrinsics); + std::string GetCameraIntrinsicsText(bool for_gpu_texture); private: ArSession* ar_session_ = nullptr; + ArConfig* ar_config_ = nullptr; ArFrame* ar_frame_ = nullptr; ArCameraIntrinsics* ar_camera_intrinsics_ = nullptr; @@ -80,6 +92,35 @@ class ComputerVisionApplication { AAssetManager* const asset_manager_; CpuImageRenderer cpu_image_renderer_; + + struct CameraConfig { + int32_t width = 0; + int32_t height = 0; + std::string config_label; + ArCameraConfig* config = nullptr; + }; + + std::vector camera_configs_; + CameraConfig* cpu_low_resolution_camera_config_ptr_ = nullptr; + CameraConfig* cpu_high_resolution_camera_config_ptr_ = nullptr; + + // Obtain all camera configs (and update camera_configs_) and sort out the + // configs with lowest and highest image resolutions. + void obtainCameraConfigs(); + + // Copy one camera config from ArCameraConfigList to a CameraConfig. + void copyCameraConfig(const ArSession* ar_session, + const ArCameraConfigList* all_configs, int index, + int num_configs, CameraConfig* camera_config); + + // Release memory in camera_configs_. + void destroyCameraConfigs(); + + // Help function (called by obtainCameraConfigs()) to return pointers to + // camera_configs_ the lowest and highest resolutions configs. + void getCameraConfigLowestAndHighestResolutions( + CameraConfig** lowest_resolution_config, + CameraConfig** highest_resolution_config); }; } // namespace computer_vision diff --git a/samples/computervision_c/app/src/main/cpp/cpu_image_renderer.cc b/samples/computervision_c/app/src/main/cpp/cpu_image_renderer.cc index 6e2a59195..0af29b542 100644 --- a/samples/computervision_c/app/src/main/cpp/cpu_image_renderer.cc +++ b/samples/computervision_c/app/src/main/cpp/cpu_image_renderer.cc @@ -96,14 +96,14 @@ bool DetectEdge(const AImage* ndk_image, int32_t width, int32_t height, int offset = (j * stride) + i; // Neighbour pixels around the pixel at [i, j]. - int a00 = input_pixels[offset - width - 1]; - int a01 = input_pixels[offset - width]; - int a02 = input_pixels[offset - width + 1]; + int a00 = input_pixels[offset - stride - 1]; + int a01 = input_pixels[offset - stride]; + int a02 = input_pixels[offset - stride + 1]; int a10 = input_pixels[offset - 1]; int a12 = input_pixels[offset + 1]; - int a20 = input_pixels[offset + width - 1]; - int a21 = input_pixels[offset + width]; - int a22 = input_pixels[offset + width + 1]; + int a20 = input_pixels[offset + stride - 1]; + int a21 = input_pixels[offset + stride]; + int a22 = input_pixels[offset + stride + 1]; // Sobel X filter: // -1, 0, 1, diff --git a/samples/computervision_c/app/src/main/cpp/jni_interface.cc b/samples/computervision_c/app/src/main/cpp/jni_interface.cc index 6a7b5f872..89137ca6f 100644 --- a/samples/computervision_c/app/src/main/cpp/jni_interface.cc +++ b/samples/computervision_c/app/src/main/cpp/jni_interface.cc @@ -27,7 +27,7 @@ extern "C" { namespace { -// maintain a reference to the JVM so we can use it later. +// Maintain a reference to the JVM so we can use it later. static JavaVM *g_vm = nullptr; inline jlong jptr(computer_vision::ComputerVisionApplication @@ -97,12 +97,35 @@ jclass FindClass(const char *classname) { return env->FindClass(classname); } +JNI_METHOD(jstring, getCameraConfigLabel) +(JNIEnv *env, jclass, jlong native_application, jboolean is_low_resolution) { + auto label = + native(native_application)->getCameraConfigLabel(is_low_resolution); + return env->NewStringUTF(label.c_str()); +} + +JNI_METHOD(jint, setCameraConfig) +(JNIEnv *env, jclass, jlong native_application, jboolean is_low_resolution) { + ArStatus status = + native(native_application)->setCameraConfig(is_low_resolution); + return static_cast(status); +} + JNI_METHOD(jstring, getCameraIntrinsicsText) -(JNIEnv *env, jclass, jlong native_application, jboolean show_cpu_intrinsics) { +(JNIEnv *env, jclass, jlong native_application, jboolean for_gpu_texture) { auto label = - native(native_application) - ->GetCameraIntrinsicsText(static_cast(show_cpu_intrinsics)); + native(native_application)->GetCameraIntrinsicsText(for_gpu_texture); return env->NewStringUTF(label.c_str()); } +JNI_METHOD(void, setFocusMode) +(JNIEnv *, jclass, jlong native_application, jboolean enable_auto_focus) { + native(native_application)->SetFocusMode(enable_auto_focus); +} + +JNI_METHOD(jboolean, getFocusMode) +(JNIEnv *, jclass, jlong native_application) { + return native(native_application)->GetFocusMode(); +} + } // extern "C" diff --git a/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/ComputerVisionActivity.java b/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/ComputerVisionActivity.java index 5e93f8276..9689b7b1e 100644 --- a/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/ComputerVisionActivity.java +++ b/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/ComputerVisionActivity.java @@ -27,6 +27,10 @@ import android.view.Surface; import android.view.View; import android.view.WindowManager; +import android.widget.CompoundButton; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; import javax.microedition.khronos.egl.EGLConfig; @@ -48,29 +52,32 @@ public class ComputerVisionActivity extends AppCompatActivity private int viewportHeight; // Using float value to set the splitter position in shader in native code. private float splitterPosition = 0.0f; + private boolean isLowResolutionSelected = true; // Camera intrinsics text elements. private TextView cameraIntrinsicsTextView; - private boolean isShowingCpuIntrinsics = true; + + private Switch focusModeSwitch; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cameraIntrinsicsTextView = findViewById(R.id.camera_intrinsics_view); + focusModeSwitch = (Switch) findViewById(R.id.switch_focus_mode); + focusModeSwitch.setOnCheckedChangeListener(this::onFocusModeChanged); surfaceView = findViewById(R.id.surfaceview); surfaceView.setOnTouchListener( - new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (motionEvent.getAction() == MotionEvent.ACTION_UP) { - isShowingCpuIntrinsics = (splitterPosition > 0.5f); - splitterPosition = isShowingCpuIntrinsics ? 0.0f : 1.0f; - } - - return true; + (View view, MotionEvent motionEvent) -> { + if (motionEvent.getAction() == MotionEvent.ACTION_UP) { + splitterPosition = (splitterPosition < 0.5f) ? 1.0f : 0.0f; + + // Turn off the CPU resolution radio buttons if CPU image is not displayed. + showCameraConfigMenu(splitterPosition < 0.5f); } + + return true; }); // Set up renderer. @@ -96,6 +103,24 @@ protected void onResume() { JniInterface.onResume(nativeApplication, getApplicationContext(), this); surfaceView.onResume(); + // Update the radio buttons with the resolution info. + String lowResLabel = JniInterface.getCameraConfigLabel(nativeApplication, true); + String highResLabel = JniInterface.getCameraConfigLabel(nativeApplication, false); + RadioButton lowResolutionRadioButton = (RadioButton) findViewById(R.id.radio_low_res); + RadioButton highResolutionRadioButton = (RadioButton) findViewById(R.id.radio_high_res); + if (!lowResLabel.isEmpty()) { + lowResolutionRadioButton.setText(lowResLabel); + } else { + lowResolutionRadioButton.setVisibility(View.INVISIBLE); + } + if (!highResLabel.isEmpty()) { + highResolutionRadioButton.setText(highResLabel); + } else { + highResolutionRadioButton.setVisibility(View.INVISIBLE); + } + + focusModeSwitch.setChecked(JniInterface.getFocusMode(nativeApplication)); + // Listen to display changed events to detect 180° rotation, which does not cause a config // change or view resize. getSystemService(DisplayManager.class).registerDisplayListener(this, null); @@ -219,16 +244,13 @@ public void onDrawFrame(GL10 gl) { viewportHeight); viewportChanged = false; } + JniInterface.onGlSurfaceDrawFrame(nativeApplication, splitterPosition); final String cameraIntrinsicsText = - JniInterface.getCameraIntrinsicsText(nativeApplication, isShowingCpuIntrinsics); - runOnUiThread( - new Runnable() { - @Override - public void run() { - cameraIntrinsicsTextView.setText(cameraIntrinsicsText); - } - }); + JniInterface.getCameraIntrinsicsText( + nativeApplication, /*forGpuTexture=*/ (splitterPosition > 0.5f)); + + runOnUiThread(() -> cameraIntrinsicsTextView.setText(cameraIntrinsicsText)); } } @@ -256,4 +278,42 @@ public void onDisplayRemoved(int displayId) {} public void onDisplayChanged(int displayId) { viewportChanged = true; } + + public void onLowResolutionRadioButtonClicked(View view) { + boolean checked = ((RadioButton) view).isChecked(); + if (checked && !isLowResolutionSelected) { + // Display low resolution. + isLowResolutionSelected = true; + String label = (String) ((RadioButton) view).getText(); + onCameraConfigChanged(isLowResolutionSelected, label); + } + } + + public void onHighResolutionRadioButtonClicked(View view) { + boolean checked = ((RadioButton) view).isChecked(); + if (checked && isLowResolutionSelected) { + // Display high resolution + isLowResolutionSelected = false; + String label = (String) ((RadioButton) view).getText(); + onCameraConfigChanged(isLowResolutionSelected, label); + } + } + + private void onFocusModeChanged(CompoundButton unusedButton, boolean isChecked) { + JniInterface.setFocusMode(nativeApplication, isChecked); + } + + private void onCameraConfigChanged(boolean isLowResolution, String label) { + int status = JniInterface.setCameraConfig(nativeApplication, isLowResolution); + if (status == 0) { + // Let the user know that the camera config is set. + String message = "Set the camera config with " + label; + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } + } + + private void showCameraConfigMenu(boolean show) { + RadioGroup radioGroup = (RadioGroup) findViewById(R.id.radio_camera_configs); + radioGroup.setVisibility(show ? View.VISIBLE : View.INVISIBLE); + } } diff --git a/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/JniInterface.java b/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/JniInterface.java index 191bb124b..1b6fd7408 100644 --- a/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/JniInterface.java +++ b/samples/computervision_c/app/src/main/java/com/google/ar/core/examples/c/computervision/JniInterface.java @@ -58,12 +58,20 @@ static native void onDisplayGeometryChanged( */ static native void onGlSurfaceDrawFrame(long nativeApplication, float splitPosition); + static native String getCameraConfigLabel( + long nativeApplication, boolean isLowResolutionSelected); + + static native int setCameraConfig(long nativeApplication, boolean isLowResolutionSelected); + /** * Retrieves the text for the intrinsic values of the current camera configuration. * * @param nativeApplication the native application handle. - * @param showCpuIntrinsics if true, retrieves the text for the CPU image's intrinsics. Otherwise, - * retrieves the text for the GPU texture's intrinsics. + * @param forGpuTexture is the intrinsic text required for GPU texture or for CPU image. */ - static native String getCameraIntrinsicsText(long nativeApplication, boolean showCpuIntrinsics); + static native String getCameraIntrinsicsText(long nativeApplication, boolean forGpuTexture); + + static native void setFocusMode(long nativeApplication, boolean isFixedFocus); + + static native boolean getFocusMode(long nativeApplication); } diff --git a/samples/computervision_c/app/src/main/res/layout/activity_main.xml b/samples/computervision_c/app/src/main/res/layout/activity_main.xml index 74a1a521e..02c0181fc 100644 --- a/samples/computervision_c/app/src/main/res/layout/activity_main.xml +++ b/samples/computervision_c/app/src/main/res/layout/activity_main.xml @@ -25,13 +25,46 @@ android:layout_height="match_parent" android:layout_gravity="top"/> - + android:layout_marginTop="10dp" + android:layout_marginLeft="10dp" + android:checkedButton="@+id/radio_low_res" + android:orientation="vertical"> + + + + + + + + + diff --git a/samples/computervision_c/app/src/main/res/values/strings.xml b/samples/computervision_c/app/src/main/res/values/strings.xml index b65c992c7..b553abb66 100644 --- a/samples/computervision_c/app/src/main/res/values/strings.xml +++ b/samples/computervision_c/app/src/main/res/values/strings.xml @@ -16,4 +16,9 @@ --> CV C + + + Low Resolution + High Resolution + Auto Focus diff --git a/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar b/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar and b/samples/computervision_c/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/computervision_c/gradlew.bat b/samples/computervision_c/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/computervision_c/gradlew.bat +++ b/samples/computervision_c/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/computervision_java/app/build.gradle b/samples/computervision_java/app/build.gradle index 2c87ab4ae..805b56274 100644 --- a/samples/computervision_java/app/build.gradle +++ b/samples/computervision_java/app/build.gradle @@ -11,7 +11,10 @@ android { versionCode 1 versionName "1.0" } - + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -22,7 +25,7 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java index d84573788..87dc77daa 100644 --- a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java @@ -123,7 +123,7 @@ public void update(PointCloud cloud) { } /** - * Renders the point cloud. ArCore point cloud is given in world space. + * Renders the point cloud. ARCore point cloud is given in world space. * * @param cameraView the camera view matrix for this frame, typically from {@link * com.google.ar.core.Camera#getViewMatrix(float[], int)}. diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/ComputerVisionActivity.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/ComputerVisionActivity.java index f20b742eb..9399d0d99 100644 --- a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/ComputerVisionActivity.java +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/ComputerVisionActivity.java @@ -23,11 +23,18 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; +import android.util.Size; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.RadioButton; +import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; import com.google.ar.core.ArCoreApk; import com.google.ar.core.Camera; +import com.google.ar.core.CameraConfig; import com.google.ar.core.CameraIntrinsics; +import com.google.ar.core.Config; import com.google.ar.core.Frame; import com.google.ar.core.Session; import com.google.ar.core.examples.java.common.helpers.CameraPermissionHelper; @@ -41,6 +48,7 @@ import com.google.ar.core.exceptions.UnavailableUserDeclinedInstallationException; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.List; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; @@ -48,8 +56,10 @@ public class ComputerVisionActivity extends AppCompatActivity implements GLSurfaceView.Renderer { private static final String TAG = ComputerVisionActivity.class.getSimpleName(); private static final String CAMERA_INTRINSICS_TEXT_FORMAT = - "Unrotated Camera %s Intrinsics:\n\tFocal Length: (%.2f, %.2f)\n\tPrincipal Point: " - + "(%.2f, %.2f)\n\tImage Dimensions: (%d, %d)\n\tUnrotated Field of View: (%.2fº, %.2fº)"; + "Unrotated Camera %s %s Intrinsics:\n\tFocal Length: (%.2f, %.2f)" + + "\n\tPrincipal Point: (%.2f, %.2f)" + + "\n\t%s Image Dimensions: (%d, %d)" + + "\n\tUnrotated Field of View: (%.2fº, %.2fº)"; private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI); // This app demonstrates two approaches to obtaining image data accessible on CPU: @@ -68,6 +78,7 @@ private enum ImageAcquisitionPath { // Session management and rendering. private GLSurfaceView surfaceView; private Session session; + private Config config; private boolean installRequested; private final SnackbarHelper messageSnackbarHelper = new SnackbarHelper(); private CpuImageDisplayRotationHelper cpuImageDisplayRotationHelper; @@ -90,14 +101,25 @@ private enum ImageAcquisitionPath { private static final int IMAGE_WIDTH = 1280; private static final int IMAGE_HEIGHT = 720; + // For Camera Configuration APIs usage. + private boolean isLowResolutionSelected; + private CameraConfig cpuLowResolutionCameraConfig; + private CameraConfig cpuHighResolutionCameraConfig; + + private Switch focusModeSwitch; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + surfaceView = findViewById(R.id.surfaceview); cameraIntrinsicsTextView = findViewById(R.id.camera_intrinsics_view); surfaceView = findViewById(R.id.surfaceview); + focusModeSwitch = (Switch) findViewById(R.id.switch_focus_mode); + focusModeSwitch.setOnCheckedChangeListener(this::onFocusModeChanged); + cpuImageDisplayRotationHelper = new CpuImageDisplayRotationHelper(/*context=*/ this); - cpuImageTouchListener = new CpuImageTouchListener(cpuImageRenderer); + cpuImageTouchListener = new CpuImageTouchListener(cpuImageRenderer, /*context=*/ this); // Setup a touch listener to control the texture splitter position. surfaceView.setOnTouchListener(cpuImageTouchListener); @@ -136,6 +158,7 @@ protected void onResume() { } session = new Session(/* context= */ this); + config = new Config(session); } catch (UnavailableArcoreNotInstalledException | UnavailableUserDeclinedInstallationException e) { message = "Please install ARCore"; @@ -158,6 +181,10 @@ protected void onResume() { } } + obtainCameraConfigs(); + + focusModeSwitch.setChecked(config.getFocusMode() != Config.FocusMode.FIXED); + // Note that order matters - see the note in onPause(), the reverse applies here. try { session.resume(); @@ -259,13 +286,7 @@ public void onDrawFrame(GL10 gl) { } // Update the camera intrinsics' text. - runOnUiThread( - new Runnable() { - @Override - public void run() { - cameraIntrinsicsTextView.setText(getCameraIntrinsicsText(frame)); - } - }); + runOnUiThread(() -> cameraIntrinsicsTextView.setText(getCameraIntrinsicsText(frame))); } catch (Exception t) { // Avoid crashing the application due to unhandled exceptions. Log.e(TAG, "Exception on the OpenGL thread", t); @@ -337,13 +358,112 @@ private void renderProcessedImageGpuDownload(Frame frame) { textureReader.submitFrame(cpuImageRenderer.getTextureId(), TEXTURE_WIDTH, TEXTURE_HEIGHT); } + public void onLowResolutionRadioButtonClicked(View view) { + boolean checked = ((RadioButton) view).isChecked(); + if (checked && !isLowResolutionSelected) { + // Display low resolution + onCameraConfigChanged(cpuLowResolutionCameraConfig); + isLowResolutionSelected = true; + } + } + + public void onHighResolutionRadioButtonClicked(View view) { + boolean checked = ((RadioButton) view).isChecked(); + if (checked && isLowResolutionSelected) { + // Display high resolution + onCameraConfigChanged(cpuHighResolutionCameraConfig); + isLowResolutionSelected = false; + } + } + + private void onFocusModeChanged(CompoundButton unusedButton, boolean isChecked) { + config.setFocusMode(isChecked ? Config.FocusMode.AUTO : Config.FocusMode.FIXED); + session.configure(config); + } + + private void onCameraConfigChanged(CameraConfig cameraConfig) { + // To change the AR camera config - first we pause the AR session, set the desired camera + // config and then resume the AR session. + if (session != null) { + session.pause(); + session.setCameraConfig(cameraConfig); + try { + session.resume(); + } catch (CameraNotAvailableException ex) { + // In a rare case (such as another camera app launching) the camera may be given to a + // different app and so may not be available to this app. Handle this properly by showing a + // message and recreate the session at the next iteration. + messageSnackbarHelper.showError(this, "Camera not available. Please restart the app."); + session = null; + return; + } + + // Let the user know that the camera config is set. + String toastMessage = + "Set the camera config with CPU image resolution of " + + cameraConfig.getImageSize().getWidth() + + "x" + + cameraConfig.getImageSize().getHeight() + + "."; + Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show(); + } + } + + // Obtains the supported camera configs and build the list of radio button one for each camera + // config. + private void obtainCameraConfigs() { + // First obtain the session handle before getting the list of various camera configs. + if (session != null) { + List cameraConfigs = session.getSupportedCameraConfigs(); + + // Determine the highest and lowest CPU resolutions. + cpuLowResolutionCameraConfig = + getCameraConfigWithLowestOrHighestResolution(cameraConfigs, true); + cpuHighResolutionCameraConfig = + getCameraConfigWithLowestOrHighestResolution(cameraConfigs, false); + + // Update the radio buttons with the resolution info. + updateRadioButtonText( + R.id.radio_low_res, cpuLowResolutionCameraConfig, getString(R.string.label_low_res)); + updateRadioButtonText( + R.id.radio_high_res, cpuHighResolutionCameraConfig, getString(R.string.label_high_res)); + isLowResolutionSelected = true; + } + } + + private void updateRadioButtonText(int id, CameraConfig cameraConfig, String prefix) { + RadioButton radioButton = (RadioButton) findViewById(id); + Size resolution = cameraConfig.getImageSize(); + radioButton.setText(prefix + " (" + resolution.getWidth() + "x" + resolution.getHeight() + ")"); + } + + private CameraConfig getCameraConfigWithLowestOrHighestResolution( + List cameraConfigs, boolean lowest) { + CameraConfig cameraConfig = cameraConfigs.get(0); + for (int index = 1; index < cameraConfigs.size(); index++) { + if (lowest) { + if (cameraConfigs.get(index).getImageSize().getHeight() + < cameraConfig.getImageSize().getHeight()) { + cameraConfig = cameraConfigs.get(index); + } + } else { + if (cameraConfigs.get(index).getImageSize().getHeight() + > cameraConfig.getImageSize().getHeight()) { + cameraConfig = cameraConfigs.get(index); + } + } + } + return cameraConfig; + } + private String getCameraIntrinsicsText(Frame frame) { Camera camera = frame.getCamera(); - boolean shouldShowCpuIntrinsics = (cpuImageRenderer.getSplitterPosition() < 0.5f); + boolean forGpuTexture = (cpuImageRenderer.getSplitterPosition() > 0.5f); CameraIntrinsics intrinsics = - shouldShowCpuIntrinsics ? camera.getImageIntrinsics() : camera.getTextureIntrinsics(); - String intrinsicsLabel = shouldShowCpuIntrinsics ? "Image" : "Texture"; + forGpuTexture ? camera.getTextureIntrinsics() : camera.getImageIntrinsics(); + String intrinsicsLabel = forGpuTexture ? "Texture" : "Image"; + String imageType = forGpuTexture ? "GPU" : "CPU"; float[] focalLength = intrinsics.getFocalLength(); float[] principalPoint = intrinsics.getPrincipalPoint(); @@ -356,11 +476,13 @@ private String getCameraIntrinsicsText(Frame frame) { return String.format( CAMERA_INTRINSICS_TEXT_FORMAT, + imageType, intrinsicsLabel, focalLength[0], focalLength[1], principalPoint[0], principalPoint[1], + imageType, imageSize[0], imageSize[1], fovX, diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageRenderer.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageRenderer.java index a9b14b9b0..66c8c527c 100644 --- a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageRenderer.java +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageRenderer.java @@ -292,7 +292,7 @@ private void updateTextureCoordinates( } // Crop the CPU image to fit the screen aspect ratio. - float imageAspectRatio = (float) (imageWidth) / imageHeight; + float imageAspectRatio = (float) imageWidth / imageHeight; float croppedWidth = 0.f; float croppedHeight = 0.f; if (screenAspectRatio < imageAspectRatio) { diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageTouchListener.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageTouchListener.java index 4ff814345..a18b5de38 100644 --- a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageTouchListener.java +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/CpuImageTouchListener.java @@ -1,7 +1,10 @@ package com.google.ar.core.examples.java.computervision; +import android.app.Activity; +import android.content.Context; import android.view.MotionEvent; import android.view.View; +import android.widget.RadioGroup; /** * Tracks the touches to the rendering view and updates the splitter position in {@link @@ -10,9 +13,11 @@ class CpuImageTouchListener implements View.OnTouchListener { private final CpuImageRenderer cpuImageRenderer; + private final Context context; - public CpuImageTouchListener(CpuImageRenderer cpuImageRenderer) { + public CpuImageTouchListener(CpuImageRenderer cpuImageRenderer, Context context) { this.cpuImageRenderer = cpuImageRenderer; + this.context = context; } @Override @@ -20,6 +25,12 @@ public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_UP) { float newPosition = (cpuImageRenderer.getSplitterPosition() < 0.5f) ? 1.0f : 0.0f; cpuImageRenderer.setSplitterPosition(newPosition); + + // Display the CPU resolution related UI only when CPU image is being displayed. + boolean show = (newPosition < 0.5f); + RadioGroup radioGroup = + (RadioGroup) ((Activity) context).findViewById(R.id.radio_camera_configs); + radioGroup.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } return true; diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/EdgeDetector.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/EdgeDetector.java index bdd82b457..66ec104f5 100644 --- a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/EdgeDetector.java +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/EdgeDetector.java @@ -34,7 +34,7 @@ public class EdgeDetector { */ public synchronized ByteBuffer detect(int width, int height, int stride, ByteBuffer input) { // Reallocate input byte array if its size is different from the required size. - if (stride * height != inputPixels.length) { + if (stride * height > inputPixels.length) { inputPixels = new byte[stride * height]; } @@ -44,7 +44,12 @@ public synchronized ByteBuffer detect(int width, int height, int stride, ByteBuf // Copy input buffer into a java array for ease of access. This is not the most optimal // way to process an image, but used here for simplicity. input.position(0); - input.get(inputPixels); + + // Note: On certain devices with specific resolution where the stride is not equal to the width. + // In such situation the memory allocated for the frame may not be exact multiple of stride x + // height hence the capacity of the ByteBuffer could be less. To handle such situations it will + // be better to transfer the exact amount of image bytes to the destination bytes. + input.get(inputPixels, 0, input.capacity()); // Detect edges. for (int j = 1; j < height - 1; j++) { @@ -53,14 +58,14 @@ public synchronized ByteBuffer detect(int width, int height, int stride, ByteBuf int offset = (j * stride) + i; // Neighbour pixels around the pixel at [i, j]. - int a00 = inputPixels[offset - width - 1]; - int a01 = inputPixels[offset - width]; - int a02 = inputPixels[offset - width + 1]; + int a00 = inputPixels[offset - stride - 1]; + int a01 = inputPixels[offset - stride]; + int a02 = inputPixels[offset - stride + 1]; int a10 = inputPixels[offset - 1]; int a12 = inputPixels[offset + 1]; - int a20 = inputPixels[offset + width - 1]; - int a21 = inputPixels[offset + width]; - int a22 = inputPixels[offset + width + 1]; + int a20 = inputPixels[offset + stride - 1]; + int a21 = inputPixels[offset + stride]; + int a22 = inputPixels[offset + stride + 1]; // Sobel X filter: // -1, 0, 1, diff --git a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/TextureReader.java b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/TextureReader.java index 7313ef200..1814adbd6 100644 --- a/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/TextureReader.java +++ b/samples/computervision_java/app/src/main/java/com/google/ar/core/examples/java/computervision/TextureReader.java @@ -412,8 +412,8 @@ private void drawTexture(int textureId, int textureWidth, int textureHeight) { if (keepAspectRatio) { int renderWidth = 0; int renderHeight = 0; - float textureAspectRatio = (float) (textureWidth) / textureHeight; - float imageAspectRatio = (float) (imageWidth) / imageHeight; + float textureAspectRatio = (float) textureWidth / textureHeight; + float imageAspectRatio = (float) imageWidth / imageHeight; if (textureAspectRatio < imageAspectRatio) { renderWidth = imageWidth; renderHeight = textureHeight * imageWidth / textureWidth; diff --git a/samples/computervision_java/app/src/main/res/layout/activity_main.xml b/samples/computervision_java/app/src/main/res/layout/activity_main.xml index 0f7a603e4..aeab644c6 100644 --- a/samples/computervision_java/app/src/main/res/layout/activity_main.xml +++ b/samples/computervision_java/app/src/main/res/layout/activity_main.xml @@ -25,6 +25,35 @@ android:layout_height="fill_parent" android:layout_gravity="top"/> + + + + + + + CV Java + Low Resolution + High Resolution + Auto Focus diff --git a/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar b/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar and b/samples/computervision_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/computervision_java/gradlew.bat b/samples/computervision_java/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/computervision_java/gradlew.bat +++ b/samples/computervision_java/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/hello_ar_c/app/build.gradle b/samples/hello_ar_c/app/build.gradle index 1abd337d4..d98a13a3e 100644 --- a/samples/hello_ar_c/app/build.gradle +++ b/samples/hello_ar_c/app/build.gradle @@ -32,6 +32,10 @@ android { abiFilters "arm64-v8a", "x86" } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -47,8 +51,8 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' - natives 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' + natives 'com.google.ar:core:1.4.0' implementation 'com.android.support:appcompat-v7:27.0.2' implementation 'com.android.support:design:27.0.2' diff --git a/samples/hello_ar_c/app/src/main/assets/models/andy.png b/samples/hello_ar_c/app/src/main/assets/models/andy.png index f88b1d6b4..6aa50ec2b 100644 Binary files a/samples/hello_ar_c/app/src/main/assets/models/andy.png and b/samples/hello_ar_c/app/src/main/assets/models/andy.png differ diff --git a/samples/hello_ar_c/app/src/main/java/com/google/ar/core/examples/c/helloar/HelloArActivity.java b/samples/hello_ar_c/app/src/main/java/com/google/ar/core/examples/c/helloar/HelloArActivity.java index e0c1c47c4..693d16eb0 100644 --- a/samples/hello_ar_c/app/src/main/java/com/google/ar/core/examples/c/helloar/HelloArActivity.java +++ b/samples/hello_ar_c/app/src/main/java/com/google/ar/core/examples/c/helloar/HelloArActivity.java @@ -88,12 +88,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override public boolean onSingleTapUp(final MotionEvent e) { surfaceView.queueEvent( - new Runnable() { - @Override - public void run() { - JniInterface.onTouched(nativeApplication, e.getX(), e.getY()); - } - }); + () -> JniInterface.onTouched(nativeApplication, e.getX(), e.getY())); return true; } @@ -104,12 +99,7 @@ public boolean onDown(MotionEvent e) { }); surfaceView.setOnTouchListener( - new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return gestureDetector.onTouchEvent(event); - } - }); + (View v, MotionEvent event) -> gestureDetector.onTouchEvent(event)); // Set up renderer. surfaceView.setPreserveEGLContextOnPause(true); diff --git a/samples/hello_ar_c/gradle/wrapper/gradle-wrapper.jar b/samples/hello_ar_c/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/hello_ar_c/gradle/wrapper/gradle-wrapper.jar and b/samples/hello_ar_c/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/hello_ar_c/gradlew.bat b/samples/hello_ar_c/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/hello_ar_c/gradlew.bat +++ b/samples/hello_ar_c/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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 diff --git a/samples/hello_ar_java/app/build.gradle b/samples/hello_ar_java/app/build.gradle index 1567b5f1e..e84e2cf4b 100644 --- a/samples/hello_ar_java/app/build.gradle +++ b/samples/hello_ar_java/app/build.gradle @@ -11,7 +11,10 @@ android { versionCode 1 versionName "1.0" } - + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } buildTypes { release { minifyEnabled false @@ -22,7 +25,7 @@ android { dependencies { // ARCore library - implementation 'com.google.ar:core:1.3.0' + implementation 'com.google.ar:core:1.4.0' // Obj - a simple Wavefront OBJ file loader // https://github.com/javagl/Obj diff --git a/samples/hello_ar_java/app/src/main/assets/models/andy.png b/samples/hello_ar_java/app/src/main/assets/models/andy.png index f88b1d6b4..6aa50ec2b 100644 Binary files a/samples/hello_ar_java/app/src/main/assets/models/andy.png and b/samples/hello_ar_java/app/src/main/assets/models/andy.png differ diff --git a/samples/hello_ar_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java b/samples/hello_ar_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java index d84573788..87dc77daa 100644 --- a/samples/hello_ar_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java +++ b/samples/hello_ar_java/app/src/main/java/com/google/ar/core/examples/java/common/rendering/PointCloudRenderer.java @@ -123,7 +123,7 @@ public void update(PointCloud cloud) { } /** - * Renders the point cloud. ArCore point cloud is given in world space. + * Renders the point cloud. ARCore point cloud is given in world space. * * @param cameraView the camera view matrix for this frame, typically from {@link * com.google.ar.core.Camera#getViewMatrix(float[], int)}. diff --git a/samples/hello_ar_java/gradle/wrapper/gradle-wrapper.jar b/samples/hello_ar_java/gradle/wrapper/gradle-wrapper.jar index c44b679ac..758de960e 100644 Binary files a/samples/hello_ar_java/gradle/wrapper/gradle-wrapper.jar and b/samples/hello_ar_java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/hello_ar_java/gradlew.bat b/samples/hello_ar_java/gradlew.bat index f9553162f..e95643d6a 100644 --- a/samples/hello_ar_java/gradlew.bat +++ b/samples/hello_ar_java/gradlew.bat @@ -1,84 +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= - -@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 +@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= + +@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