replate-camera 0.17.1 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/app/build.gradle +76 -0
- package/android/app/src/debug/AndroidManifest.xml +4 -0
- package/android/app/src/main/AndroidManifest.xml +30 -0
- package/android/app/src/main/assets/unlit_color.filamat +0 -0
- package/android/app/src/main/java/com/lucarinaldii/replatecamera/MainActivity.kt +13 -0
- package/android/app/src/main/java/com/lucarinaldii/replatecamera/MainApplication.kt +50 -0
- package/android/app/src/main/java/com/replatecamera/FocusNode.kt +131 -0
- package/android/app/src/main/java/com/replatecamera/HighQualityPhotoCapture.kt +361 -0
- package/android/app/src/main/java/com/replatecamera/ReplateCameraCaptureController.kt +349 -0
- package/android/app/src/main/java/com/replatecamera/ReplateCameraController.kt +270 -0
- package/android/app/src/main/java/com/replatecamera/ReplateCameraPackage.kt +17 -0
- package/android/app/src/main/java/com/replatecamera/ReplateCameraView.kt +1816 -0
- package/android/app/src/main/java/com/replatecamera/ReplateCameraViewManager.kt +25 -0
- package/android/build.gradle +19 -74
- package/android/gradle.properties +15 -5
- package/android/lib/build/generated/source/buildConfig/debug/com/replatecamera/BuildConfig.java +10 -0
- package/android/lib/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml +18 -0
- package/android/lib/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json +18 -0
- package/android/lib/build/intermediates/aar_metadata/debug/aar-metadata.properties +5 -0
- package/android/lib/build/intermediates/annotation_processor_list/debug/annotationProcessors.json +1 -0
- package/android/lib/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
- package/android/lib/build/intermediates/compile_r_class_jar/debug/R.jar +0 -0
- package/android/lib/build/intermediates/compile_symbol_list/debug/R.txt +0 -0
- package/android/lib/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
- package/android/lib/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
- package/android/lib/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
- package/android/lib/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
- package/android/lib/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
- package/android/lib/build/intermediates/java_res/debug/out/META-INF/replate-camera_debug.kotlin_module +0 -0
- package/android/lib/build/intermediates/javac/debug/classes/com/replatecamera/BuildConfig.class +0 -0
- package/android/lib/build/intermediates/library_assets/debug/out/unlit_color.filamat +0 -0
- package/android/lib/build/intermediates/local_only_symbol_list/debug/R-def.txt +2 -0
- package/android/lib/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt +28 -0
- package/android/lib/build/intermediates/merged_manifest/debug/AndroidManifest.xml +18 -0
- package/android/lib/build/intermediates/navigation_json/debug/navigation.json +1 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/META-INF/replate-camera_debug.kotlin_module +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$CaptureError.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$InvalidAnchor.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$NoAnchor.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$NotInFocus.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$NotInRange.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$ProcessingError.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$SavingError.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$TooManyImages.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$TransformError.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError$Unknown.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ARError.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/BuildConfig.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/DeviceTargetInfo.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/FocusNode$Companion.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/FocusNode$buildSquare$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/FocusNode$loadUnlitMaterial$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/FocusNode.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/HighQualityPhotoCapture$Companion.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/HighQualityPhotoCapture$capture$1$1$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/HighQualityPhotoCapture$takeSensorJpeg$sessionCallback$1$onConfigured$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/HighQualityPhotoCapture$takeSensorJpeg$sessionCallback$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/HighQualityPhotoCapture$takeSensorJpeg$stateCallback$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/HighQualityPhotoCapture.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraCaptureController$Companion.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraCaptureController$processAndSaveImage$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraCaptureController$processTargetedDevice$1$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraCaptureController$triggerAutoCaptureIfNewAngle$1$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraCaptureController$triggerAutoCaptureIfNewAngle$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraCaptureController.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraController$Companion.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraController.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraPackage.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$Companion.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$GestureListener.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$ScaleListener.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$WhenMappings.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$initializeSceneView$1$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$makeUnlitMaterial$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$makeUnlitMaterial$2$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$makeUnlitMaterial$3.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$prebuildBaseMaterial$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$selectBestCameraConfig$$inlined$compareBy$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$selectBestCameraConfig$$inlined$thenBy$1.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView$updateSphereColor$4.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraView.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/ReplateCameraViewManager.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_dir/debug/com/replatecamera/SafeCallbackHandler.class +0 -0
- package/android/lib/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
- package/android/lib/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt +1 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.s +1 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +2 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.s +1 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/lib/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/lib/build/outputs/logs/manifest-merger-debug-report.txt +37 -0
- package/android/lib/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/META-INF/replate-camera_debug.kotlin_module +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$CaptureError.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$InvalidAnchor.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$NoAnchor.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$NotInFocus.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$NotInRange.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$ProcessingError.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$SavingError.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$TooManyImages.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$TransformError.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError$Unknown.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ARError.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/DeviceTargetInfo.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/FocusNode$Companion.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/FocusNode$buildSquare$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/FocusNode$loadUnlitMaterial$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/FocusNode.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/HighQualityPhotoCapture$Companion.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/HighQualityPhotoCapture$capture$1$1$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/HighQualityPhotoCapture$takeSensorJpeg$sessionCallback$1$onConfigured$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/HighQualityPhotoCapture$takeSensorJpeg$sessionCallback$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/HighQualityPhotoCapture$takeSensorJpeg$stateCallback$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/HighQualityPhotoCapture.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraCaptureController$Companion.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraCaptureController$processAndSaveImage$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraCaptureController$processTargetedDevice$1$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraCaptureController$triggerAutoCaptureIfNewAngle$1$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraCaptureController$triggerAutoCaptureIfNewAngle$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraCaptureController.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraController$Companion.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraController.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraPackage.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$Companion.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$GestureListener.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$ScaleListener.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$WhenMappings.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$initializeSceneView$1$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$makeUnlitMaterial$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$makeUnlitMaterial$2$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$makeUnlitMaterial$3.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$prebuildBaseMaterial$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$selectBestCameraConfig$$inlined$compareBy$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$selectBestCameraConfig$$inlined$thenBy$1.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView$updateSphereColor$4.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraView.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/ReplateCameraViewManager.class +0 -0
- package/android/lib/build/tmp/kotlin-classes/debug/com/replatecamera/SafeCallbackHandler.class +0 -0
- package/android/lib/build.gradle +85 -0
- package/android/lib/gradle.properties +6 -0
- package/android/lib/src/main/AndroidManifest.xml +11 -0
- package/android/lib/src/main/assets/unlit_color.filamat +0 -0
- package/android/lib/src/main/java/com/replatecamera/ReplateCameraPackage.kt +14 -0
- package/android/settings.gradle +5 -0
- package/android/src/main/java/com/replatecamera/FocusNode.kt +2 -2
- package/android/src/main/java/com/replatecamera/ReplateCameraController.kt +14 -44
- package/android/src/main/java/com/replatecamera/ReplateCameraModule.kt +1 -1
- package/android/src/main/java/com/replatecamera/ReplateCameraView.kt +133 -79
- package/ios/ReplateCameraViewManager.swift +29 -21
- package/lib/commonjs/index.js +8 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/package.json +6 -1
- package/src/index.tsx +19 -1
- package/lib/typescript/src/index.d.ts +0 -28
- package/lib/typescript/src/index.d.ts.map +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
apply plugin: "com.android.application"
|
|
2
|
+
apply plugin: "org.jetbrains.kotlin.android"
|
|
3
|
+
apply plugin: "com.facebook.react"
|
|
4
|
+
|
|
5
|
+
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
|
|
6
|
+
|
|
7
|
+
react {
|
|
8
|
+
def reactNativePackageDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile()
|
|
9
|
+
entryFile = file("../../index.js")
|
|
10
|
+
reactNativeDir = reactNativePackageDir
|
|
11
|
+
hermesCommand = new File(reactNativePackageDir, "sdks/hermesc/%OS-BIN%/hermesc").getAbsolutePath()
|
|
12
|
+
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean()
|
|
16
|
+
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
|
17
|
+
|
|
18
|
+
android {
|
|
19
|
+
ndkVersion rootProject.ext.ndkVersion
|
|
20
|
+
buildToolsVersion rootProject.ext.buildToolsVersion
|
|
21
|
+
compileSdk rootProject.ext.compileSdkVersion
|
|
22
|
+
|
|
23
|
+
namespace 'com.lucarinaldii.replatecamera'
|
|
24
|
+
defaultConfig {
|
|
25
|
+
applicationId 'com.lucarinaldii.replatecamera'
|
|
26
|
+
minSdkVersion rootProject.ext.minSdkVersion
|
|
27
|
+
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
28
|
+
versionCode 1
|
|
29
|
+
versionName "0.18.0"
|
|
30
|
+
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
|
|
31
|
+
}
|
|
32
|
+
signingConfigs {
|
|
33
|
+
debug {
|
|
34
|
+
storeFile file('debug.keystore')
|
|
35
|
+
storePassword 'android'
|
|
36
|
+
keyAlias 'androiddebugkey'
|
|
37
|
+
keyPassword 'android'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
buildTypes {
|
|
41
|
+
debug {
|
|
42
|
+
signingConfig signingConfigs.debug
|
|
43
|
+
}
|
|
44
|
+
release {
|
|
45
|
+
signingConfig signingConfigs.debug
|
|
46
|
+
minifyEnabled enableMinifyInReleaseBuilds
|
|
47
|
+
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
compileOptions {
|
|
51
|
+
sourceCompatibility JavaVersion.VERSION_17
|
|
52
|
+
targetCompatibility JavaVersion.VERSION_17
|
|
53
|
+
}
|
|
54
|
+
kotlinOptions {
|
|
55
|
+
jvmTarget = "17"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
dependencies {
|
|
60
|
+
implementation("com.facebook.react:react-android")
|
|
61
|
+
implementation("com.google.ar:core:1.31.0")
|
|
62
|
+
implementation("com.gorisse.thomas.sceneform:sceneform:1.23.0")
|
|
63
|
+
implementation("com.gorisse.thomas.sceneform:ux:1.23.0")
|
|
64
|
+
implementation("androidx.exifinterface:exifinterface:1.3.7")
|
|
65
|
+
implementation("androidx.lifecycle:lifecycle-process:2.8.5")
|
|
66
|
+
implementation("com.google.android.material:material:1.12.0")
|
|
67
|
+
|
|
68
|
+
if (hermesEnabled.toBoolean()) {
|
|
69
|
+
implementation("com.facebook.react:hermes-android")
|
|
70
|
+
} else {
|
|
71
|
+
implementation jscFlavor
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle")
|
|
76
|
+
applyNativeModulesAppBuildGradle(project)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
|
|
3
|
+
<uses-permission android:name="android.permission.INTERNET" />
|
|
4
|
+
<uses-permission android:name="android.permission.CAMERA" />
|
|
5
|
+
<uses-permission android:name="android.permission.VIBRATE" />
|
|
6
|
+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
7
|
+
|
|
8
|
+
<uses-feature android:name="android.hardware.camera.ar" android:required="true" />
|
|
9
|
+
|
|
10
|
+
<application
|
|
11
|
+
android:name=".MainApplication"
|
|
12
|
+
android:label="@string/app_name"
|
|
13
|
+
android:icon="@mipmap/ic_launcher"
|
|
14
|
+
android:roundIcon="@mipmap/ic_launcher_round"
|
|
15
|
+
android:allowBackup="false"
|
|
16
|
+
android:theme="@style/AppTheme">
|
|
17
|
+
<activity
|
|
18
|
+
android:name=".MainActivity"
|
|
19
|
+
android:label="@string/app_name"
|
|
20
|
+
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
|
|
21
|
+
android:launchMode="singleTask"
|
|
22
|
+
android:windowSoftInputMode="adjustResize"
|
|
23
|
+
android:exported="true">
|
|
24
|
+
<intent-filter>
|
|
25
|
+
<action android:name="android.intent.action.MAIN" />
|
|
26
|
+
<category android:name="android.intent.category.LAUNCHER" />
|
|
27
|
+
</intent-filter>
|
|
28
|
+
</activity>
|
|
29
|
+
</application>
|
|
30
|
+
</manifest>
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package com.lucarinaldii.replatecamera
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactActivity
|
|
4
|
+
import com.facebook.react.ReactActivityDelegate
|
|
5
|
+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
|
|
6
|
+
import com.facebook.react.defaults.DefaultReactActivityDelegate
|
|
7
|
+
|
|
8
|
+
class MainActivity : ReactActivity() {
|
|
9
|
+
override fun getMainComponentName(): String = "ReplateCameraApp"
|
|
10
|
+
|
|
11
|
+
override fun createReactActivityDelegate(): ReactActivityDelegate =
|
|
12
|
+
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
|
|
13
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package com.lucarinaldii.replatecamera
|
|
2
|
+
|
|
3
|
+
import android.app.Application
|
|
4
|
+
import android.content.res.Configuration
|
|
5
|
+
import android.util.Log
|
|
6
|
+
|
|
7
|
+
import com.facebook.react.PackageList
|
|
8
|
+
import com.facebook.react.ReactApplication
|
|
9
|
+
import com.facebook.react.ReactPackage
|
|
10
|
+
import com.facebook.react.ReactHost
|
|
11
|
+
import com.facebook.react.ReactNativeHost
|
|
12
|
+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
|
|
13
|
+
import com.facebook.react.defaults.DefaultReactHost
|
|
14
|
+
import com.facebook.react.defaults.DefaultReactNativeHost
|
|
15
|
+
import com.facebook.soloader.SoLoader
|
|
16
|
+
import com.replatecamera.ReplateCameraPackage
|
|
17
|
+
|
|
18
|
+
class MainApplication : Application(), ReactApplication {
|
|
19
|
+
|
|
20
|
+
companion object {
|
|
21
|
+
private const val TAG = "ReplateMainApplication"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override val reactNativeHost: ReactNativeHost =
|
|
25
|
+
object : DefaultReactNativeHost(this) {
|
|
26
|
+
override fun getPackages(): List<ReactPackage> =
|
|
27
|
+
PackageList(this).packages.apply {
|
|
28
|
+
add(ReplateCameraPackage())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override fun getJSMainModuleName(): String = "index"
|
|
32
|
+
|
|
33
|
+
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
|
34
|
+
|
|
35
|
+
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
|
36
|
+
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
override val reactHost: ReactHost
|
|
40
|
+
get() = DefaultReactHost.getDefaultReactHost(this.applicationContext, reactNativeHost)
|
|
41
|
+
|
|
42
|
+
override fun onCreate() {
|
|
43
|
+
super.onCreate()
|
|
44
|
+
Log.i(TAG, "onCreate newArch=${BuildConfig.IS_NEW_ARCHITECTURE_ENABLED} hermes=${BuildConfig.IS_HERMES_ENABLED}")
|
|
45
|
+
SoLoader.init(this, false)
|
|
46
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
47
|
+
DefaultNewArchitectureEntryPoint.load()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
package com.replatecamera
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.google.ar.core.Frame
|
|
5
|
+
import com.google.ar.core.HitResult
|
|
6
|
+
import com.google.ar.core.Plane
|
|
7
|
+
import com.google.ar.core.TrackingState
|
|
8
|
+
import com.google.ar.sceneform.ArSceneView
|
|
9
|
+
import com.google.ar.sceneform.Node
|
|
10
|
+
import com.google.ar.sceneform.math.Quaternion
|
|
11
|
+
import com.google.ar.sceneform.math.Vector3
|
|
12
|
+
import com.google.ar.sceneform.rendering.Color
|
|
13
|
+
import com.google.ar.sceneform.rendering.Material
|
|
14
|
+
import com.google.ar.sceneform.rendering.MaterialFactory
|
|
15
|
+
import com.google.ar.sceneform.rendering.ShapeFactory
|
|
16
|
+
import kotlin.math.sqrt
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A white unfilled square that sits flat on detected horizontal planes,
|
|
20
|
+
* centered on the hit point from screen centre.
|
|
21
|
+
* Hidden entirely when no plane is found (no "searching" animation).
|
|
22
|
+
*/
|
|
23
|
+
class FocusNode(private val context: Context) : Node() {
|
|
24
|
+
|
|
25
|
+
companion object {
|
|
26
|
+
// Half-size of the square in metres (actual size is scaled by distance)
|
|
27
|
+
private const val HALF = 0.12f
|
|
28
|
+
// Thickness of each side bar
|
|
29
|
+
private const val BAR_THICKNESS = 0.004f
|
|
30
|
+
// Vertical height of the bar (flat on the plane)
|
|
31
|
+
private const val BAR_HEIGHT = 0.002f
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private val sideNodes = mutableListOf<Node>()
|
|
35
|
+
|
|
36
|
+
init {
|
|
37
|
+
buildSquare()
|
|
38
|
+
isEnabled = false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private fun buildSquare() {
|
|
42
|
+
loadUnlitMaterial { material ->
|
|
43
|
+
// Top and Bottom bars — extend along X
|
|
44
|
+
for (z in listOf(-HALF, HALF)) {
|
|
45
|
+
val node = Node()
|
|
46
|
+
node.renderable = ShapeFactory.makeCube(
|
|
47
|
+
Vector3(HALF * 2, BAR_HEIGHT, BAR_THICKNESS),
|
|
48
|
+
Vector3.zero(),
|
|
49
|
+
material.makeCopy()
|
|
50
|
+
)
|
|
51
|
+
node.localPosition = Vector3(0f, 0f, z)
|
|
52
|
+
addChild(node)
|
|
53
|
+
sideNodes.add(node)
|
|
54
|
+
}
|
|
55
|
+
// Left and Right bars — extend along Z
|
|
56
|
+
for (x in listOf(-HALF, HALF)) {
|
|
57
|
+
val node = Node()
|
|
58
|
+
node.renderable = ShapeFactory.makeCube(
|
|
59
|
+
Vector3(BAR_THICKNESS, BAR_HEIGHT, HALF * 2),
|
|
60
|
+
Vector3.zero(),
|
|
61
|
+
material.makeCopy()
|
|
62
|
+
)
|
|
63
|
+
node.localPosition = Vector3(x, 0f, 0f)
|
|
64
|
+
addChild(node)
|
|
65
|
+
sideNodes.add(node)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private fun loadUnlitMaterial(onReady: (Material) -> Unit) {
|
|
71
|
+
try {
|
|
72
|
+
val bytes = context.assets.open("unlit_color.filamat").use { it.readBytes() }
|
|
73
|
+
val buffer = java.nio.ByteBuffer.wrap(bytes)
|
|
74
|
+
Material.builder()
|
|
75
|
+
.setSource(buffer)
|
|
76
|
+
.build()
|
|
77
|
+
.thenAccept { material ->
|
|
78
|
+
material.setFloat4("baseColor", 1f, 1f, 1f, 1f)
|
|
79
|
+
try { material.setFloat(MaterialFactory.MATERIAL_METALLIC, 0f) } catch (_: Exception) {}
|
|
80
|
+
try { material.setFloat(MaterialFactory.MATERIAL_ROUGHNESS, 1f) } catch (_: Exception) {}
|
|
81
|
+
try { material.setFloat(MaterialFactory.MATERIAL_REFLECTANCE, 0f) } catch (_: Exception) {}
|
|
82
|
+
onReady(material)
|
|
83
|
+
}
|
|
84
|
+
.exceptionally {
|
|
85
|
+
MaterialFactory.makeOpaqueWithColor(context, Color(1f, 1f, 1f, 1f))
|
|
86
|
+
.thenAccept(onReady)
|
|
87
|
+
null
|
|
88
|
+
}
|
|
89
|
+
} catch (e: Exception) {
|
|
90
|
+
MaterialFactory.makeOpaqueWithColor(context, Color(1f, 1f, 1f, 1f))
|
|
91
|
+
.thenAccept(onReady)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
fun updateFromFrame(frame: Frame, sceneView: ArSceneView) {
|
|
96
|
+
val hit = getCenterHitResult(frame, sceneView)
|
|
97
|
+
if (hit != null) {
|
|
98
|
+
isEnabled = true
|
|
99
|
+
worldPosition = Vector3(hit.hitPose.tx(), hit.hitPose.ty(), hit.hitPose.tz())
|
|
100
|
+
worldRotation = Quaternion(
|
|
101
|
+
hit.hitPose.qx(),
|
|
102
|
+
hit.hitPose.qy(),
|
|
103
|
+
hit.hitPose.qz(),
|
|
104
|
+
hit.hitPose.qw()
|
|
105
|
+
)
|
|
106
|
+
// Scale square with distance so it stays visually consistent
|
|
107
|
+
val pose = frame.camera.pose
|
|
108
|
+
val dx = pose.tx() - hit.hitPose.tx()
|
|
109
|
+
val dy = pose.ty() - hit.hitPose.ty()
|
|
110
|
+
val dz = pose.tz() - hit.hitPose.tz()
|
|
111
|
+
val distance = sqrt(dx * dx + dy * dy + dz * dz)
|
|
112
|
+
val scale = (distance * 0.55f).coerceIn(0.4f, 1.6f)
|
|
113
|
+
localScale = Vector3.one().scaled(scale)
|
|
114
|
+
} else {
|
|
115
|
+
isEnabled = false
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private fun getCenterHitResult(frame: Frame, sceneView: ArSceneView): HitResult? {
|
|
120
|
+
if (sceneView.width <= 0 || sceneView.height <= 0) return null
|
|
121
|
+
val cx = sceneView.width / 2f
|
|
122
|
+
val cy = sceneView.height / 2f
|
|
123
|
+
return frame.hitTest(cx, cy).firstOrNull { hit ->
|
|
124
|
+
val trackable = hit.trackable
|
|
125
|
+
trackable is Plane &&
|
|
126
|
+
trackable.trackingState == TrackingState.TRACKING &&
|
|
127
|
+
trackable.isPoseInPolygon(hit.hitPose) &&
|
|
128
|
+
trackable.type == Plane.Type.HORIZONTAL_UPWARD_FACING
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
package com.replatecamera
|
|
2
|
+
|
|
3
|
+
import android.content.ContentValues
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.graphics.ImageFormat
|
|
6
|
+
import android.hardware.camera2.CameraAccessException
|
|
7
|
+
import android.hardware.camera2.CameraCaptureSession
|
|
8
|
+
import android.hardware.camera2.CameraCharacteristics
|
|
9
|
+
import android.hardware.camera2.CameraDevice
|
|
10
|
+
import android.hardware.camera2.CameraManager
|
|
11
|
+
import android.hardware.camera2.CaptureFailure
|
|
12
|
+
import android.hardware.camera2.CaptureRequest
|
|
13
|
+
import android.media.ImageReader
|
|
14
|
+
import android.os.Build
|
|
15
|
+
import android.os.Environment
|
|
16
|
+
import android.os.Handler
|
|
17
|
+
import android.os.HandlerThread
|
|
18
|
+
import android.os.Looper
|
|
19
|
+
import android.provider.MediaStore
|
|
20
|
+
import android.util.Log
|
|
21
|
+
import java.io.File
|
|
22
|
+
import java.io.FileOutputStream
|
|
23
|
+
import java.util.concurrent.Semaphore
|
|
24
|
+
import java.util.concurrent.TimeUnit
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Captures a high-quality JPEG from the raw camera sensor via Camera2
|
|
28
|
+
* TEMPLATE_STILL_CAPTURE, completely independent of ARCore rendering.
|
|
29
|
+
*
|
|
30
|
+
* The resulting JPEG contains ONLY the native sensor image — no AR overlays,
|
|
31
|
+
* no 3D nodes, no anchor, no spheres.
|
|
32
|
+
*
|
|
33
|
+
* Usage:
|
|
34
|
+
* 1. call start() once (e.g. in initializeSceneView)
|
|
35
|
+
* 2. call capture() each time a still is needed
|
|
36
|
+
* 3. call stop() on destroy
|
|
37
|
+
*/
|
|
38
|
+
class HighQualityPhotoCapture(private val context: Context) {
|
|
39
|
+
|
|
40
|
+
companion object {
|
|
41
|
+
private const val TAG = "HighQualityCapture"
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* When true, every saved JPEG is also inserted into the device gallery
|
|
45
|
+
* via MediaStore so it is visible in the Photos app.
|
|
46
|
+
* Flip to false for production builds.
|
|
47
|
+
*/
|
|
48
|
+
var debugSaveToGallery: Boolean = false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private var backgroundThread: HandlerThread? = null
|
|
52
|
+
private var backgroundHandler: Handler? = null
|
|
53
|
+
|
|
54
|
+
fun start() {
|
|
55
|
+
backgroundThread = HandlerThread("HQCaptureThread").also { it.start() }
|
|
56
|
+
backgroundHandler = Handler(backgroundThread!!.looper)
|
|
57
|
+
Log.i(TAG, "HighQualityPhotoCapture started")
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fun stop() {
|
|
61
|
+
backgroundThread?.quitSafely()
|
|
62
|
+
try { backgroundThread?.join() } catch (_: InterruptedException) { }
|
|
63
|
+
backgroundThread = null
|
|
64
|
+
backgroundHandler = null
|
|
65
|
+
Log.i(TAG, "HighQualityPhotoCapture stopped")
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// -------------------------------------------------------------------------
|
|
69
|
+
// Public capture API
|
|
70
|
+
// -------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Pause [arSession] (releases the camera to the system), take a Camera2
|
|
74
|
+
* JPEG still capture, then resume [arSession].
|
|
75
|
+
*
|
|
76
|
+
* [onResume] is called on the MAIN THREAD once the ARCore session has been
|
|
77
|
+
* resumed — the caller is responsible for restoring gorisse / ArSceneView
|
|
78
|
+
* state (see ReplateCameraView.captureHighQuality).
|
|
79
|
+
*
|
|
80
|
+
* [onResult] is called with the saved File (or null + exception on failure).
|
|
81
|
+
* It is called AFTER the ARCore session has been resumed.
|
|
82
|
+
*/
|
|
83
|
+
fun capture(
|
|
84
|
+
arSceneView: com.google.ar.sceneform.ArSceneView,
|
|
85
|
+
onResume: () -> Unit,
|
|
86
|
+
onResult: (File?, Exception?) -> Unit
|
|
87
|
+
) {
|
|
88
|
+
val handler = backgroundHandler
|
|
89
|
+
if (handler == null) {
|
|
90
|
+
Log.e(TAG, "capture() called but HighQualityPhotoCapture was not started")
|
|
91
|
+
onResult(null, IllegalStateException("HighQualityPhotoCapture not started"))
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// arSceneView.pause() must run on the main thread.
|
|
96
|
+
// It stops the Choreographer frame callback AND pauses the ARCore session
|
|
97
|
+
// atomically — preventing SessionPausedException from onBeginFrame.
|
|
98
|
+
Handler(Looper.getMainLooper()).post {
|
|
99
|
+
try {
|
|
100
|
+
Log.i(TAG, "TRIGGER: pausing ArSceneView (Choreographer + ARCore) for Camera2 capture")
|
|
101
|
+
arSceneView.pause()
|
|
102
|
+
Log.i(TAG, "ArSceneView paused — camera released to system")
|
|
103
|
+
} catch (e: Exception) {
|
|
104
|
+
Log.e(TAG, "Failed to pause ArSceneView before Camera2 capture", e)
|
|
105
|
+
onResult(null, e)
|
|
106
|
+
return@post
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Give the camera driver a moment to fully release
|
|
110
|
+
handler.postDelayed({
|
|
111
|
+
takeSensorJpeg { file, error ->
|
|
112
|
+
// session.resume() must also run on the main thread
|
|
113
|
+
Handler(Looper.getMainLooper()).post {
|
|
114
|
+
onResume() // caller resumes gorisse / ArSceneView
|
|
115
|
+
onResult(file, error)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}, 150L)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// -------------------------------------------------------------------------
|
|
123
|
+
// Camera2 still capture
|
|
124
|
+
// -------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
private fun takeSensorJpeg(onResult: (File?, Exception?) -> Unit) {
|
|
127
|
+
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
|
128
|
+
|
|
129
|
+
// Find back-facing camera
|
|
130
|
+
val cameraId = try {
|
|
131
|
+
cameraManager.cameraIdList.firstOrNull { id ->
|
|
132
|
+
cameraManager.getCameraCharacteristics(id)
|
|
133
|
+
.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK
|
|
134
|
+
}
|
|
135
|
+
} catch (e: CameraAccessException) {
|
|
136
|
+
Log.e(TAG, "Cannot enumerate cameras", e)
|
|
137
|
+
onResult(null, e)
|
|
138
|
+
return
|
|
139
|
+
} ?: run {
|
|
140
|
+
val e = IllegalStateException("No back-facing camera found")
|
|
141
|
+
Log.e(TAG, e.message!!)
|
|
142
|
+
onResult(null, e)
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
|
|
147
|
+
val sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 90
|
|
148
|
+
val streamMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
|
|
149
|
+
val maxJpegSize = streamMap.getOutputSizes(ImageFormat.JPEG)
|
|
150
|
+
.maxByOrNull { it.width * it.height }
|
|
151
|
+
?: run {
|
|
152
|
+
onResult(null, IllegalStateException("No JPEG output sizes available"))
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Log.i(TAG, "Camera2 still: cameraId=$cameraId size=${maxJpegSize.width}x${maxJpegSize.height} sensorOrientation=$sensorOrientation")
|
|
157
|
+
|
|
158
|
+
val imageReader = ImageReader.newInstance(
|
|
159
|
+
maxJpegSize.width, maxJpegSize.height,
|
|
160
|
+
ImageFormat.JPEG, 2
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
val openSemaphore = Semaphore(0)
|
|
164
|
+
var cameraDevice: CameraDevice? = null
|
|
165
|
+
var openError: Exception? = null
|
|
166
|
+
|
|
167
|
+
val stateCallback = object : CameraDevice.StateCallback() {
|
|
168
|
+
override fun onOpened(device: CameraDevice) {
|
|
169
|
+
Log.i(TAG, "CameraDevice opened — starting TEMPLATE_STILL_CAPTURE session")
|
|
170
|
+
cameraDevice = device
|
|
171
|
+
openSemaphore.release()
|
|
172
|
+
}
|
|
173
|
+
override fun onDisconnected(device: CameraDevice) {
|
|
174
|
+
Log.w(TAG, "CameraDevice disconnected before capture")
|
|
175
|
+
device.close()
|
|
176
|
+
openError = IllegalStateException("Camera disconnected")
|
|
177
|
+
openSemaphore.release()
|
|
178
|
+
}
|
|
179
|
+
override fun onError(device: CameraDevice, error: Int) {
|
|
180
|
+
Log.e(TAG, "CameraDevice error=$error")
|
|
181
|
+
device.close()
|
|
182
|
+
openError = IllegalStateException("CameraDevice error: $error")
|
|
183
|
+
openSemaphore.release()
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
cameraManager.openCamera(cameraId, stateCallback, backgroundHandler)
|
|
189
|
+
} catch (e: Exception) {
|
|
190
|
+
Log.e(TAG, "openCamera failed", e)
|
|
191
|
+
imageReader.close()
|
|
192
|
+
onResult(null, e)
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (!openSemaphore.tryAcquire(4, TimeUnit.SECONDS)) {
|
|
197
|
+
Log.e(TAG, "Camera open timed out after 4s")
|
|
198
|
+
imageReader.close()
|
|
199
|
+
onResult(null, Exception("Camera open timed out"))
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
val device = cameraDevice
|
|
204
|
+
if (device == null || openError != null) {
|
|
205
|
+
imageReader.close()
|
|
206
|
+
onResult(null, openError ?: Exception("Camera did not open"))
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ---- Capture session -----------------------------------------------
|
|
211
|
+
val captureSemaphore = Semaphore(0)
|
|
212
|
+
var captureFile: File? = null
|
|
213
|
+
var captureError: Exception? = null
|
|
214
|
+
|
|
215
|
+
imageReader.setOnImageAvailableListener({ reader ->
|
|
216
|
+
var image: android.media.Image? = null
|
|
217
|
+
try {
|
|
218
|
+
image = reader.acquireLatestImage()
|
|
219
|
+
if (image == null) {
|
|
220
|
+
captureError = Exception("acquireLatestImage returned null")
|
|
221
|
+
captureSemaphore.release()
|
|
222
|
+
return@setOnImageAvailableListener
|
|
223
|
+
}
|
|
224
|
+
val buffer = image.planes[0].buffer
|
|
225
|
+
val bytes = ByteArray(buffer.remaining()).also { buffer.get(it) }
|
|
226
|
+
captureFile = saveJpegBytes(bytes)
|
|
227
|
+
Log.i(TAG, "JPEG saved — camera-only, zero AR overlays: ${captureFile?.absolutePath} (${bytes.size} bytes, ${maxJpegSize.width}x${maxJpegSize.height})")
|
|
228
|
+
|
|
229
|
+
if (debugSaveToGallery) {
|
|
230
|
+
saveToGallery(bytes, captureFile!!.name)
|
|
231
|
+
}
|
|
232
|
+
} catch (e: Exception) {
|
|
233
|
+
Log.e(TAG, "Error saving JPEG from ImageReader", e)
|
|
234
|
+
captureError = e
|
|
235
|
+
} finally {
|
|
236
|
+
image?.close()
|
|
237
|
+
captureSemaphore.release()
|
|
238
|
+
}
|
|
239
|
+
}, backgroundHandler)
|
|
240
|
+
|
|
241
|
+
val sessionCallback = object : CameraCaptureSession.StateCallback() {
|
|
242
|
+
override fun onConfigured(session: CameraCaptureSession) {
|
|
243
|
+
try {
|
|
244
|
+
val request = device.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply {
|
|
245
|
+
addTarget(imageReader.surface)
|
|
246
|
+
set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
|
|
247
|
+
set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
|
|
248
|
+
set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO)
|
|
249
|
+
// Correct JPEG orientation so the image is upright without external rotation
|
|
250
|
+
set(CaptureRequest.JPEG_ORIENTATION, sensorOrientation)
|
|
251
|
+
set(CaptureRequest.JPEG_QUALITY, 95.toByte())
|
|
252
|
+
}.build()
|
|
253
|
+
|
|
254
|
+
session.capture(request, object : CameraCaptureSession.CaptureCallback() {
|
|
255
|
+
override fun onCaptureFailed(
|
|
256
|
+
session: CameraCaptureSession,
|
|
257
|
+
request: CaptureRequest,
|
|
258
|
+
failure: CaptureFailure
|
|
259
|
+
) {
|
|
260
|
+
Log.e(TAG, "TEMPLATE_STILL_CAPTURE failed reason=${failure.reason}")
|
|
261
|
+
captureError = Exception("Capture failed: reason=${failure.reason}")
|
|
262
|
+
captureSemaphore.release()
|
|
263
|
+
}
|
|
264
|
+
}, backgroundHandler)
|
|
265
|
+
|
|
266
|
+
Log.i(TAG, "TEMPLATE_STILL_CAPTURE submitted (ImageReader target only — no AR surfaces)")
|
|
267
|
+
} catch (e: Exception) {
|
|
268
|
+
Log.e(TAG, "Failed to submit capture request", e)
|
|
269
|
+
captureError = e
|
|
270
|
+
captureSemaphore.release()
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
override fun onConfigureFailed(session: CameraCaptureSession) {
|
|
275
|
+
Log.e(TAG, "CameraCaptureSession configuration failed")
|
|
276
|
+
captureError = Exception("CaptureSession configure failed")
|
|
277
|
+
captureSemaphore.release()
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
device.createCaptureSession(listOf(imageReader.surface), sessionCallback, backgroundHandler)
|
|
283
|
+
} catch (e: Exception) {
|
|
284
|
+
Log.e(TAG, "createCaptureSession failed", e)
|
|
285
|
+
imageReader.close()
|
|
286
|
+
device.close()
|
|
287
|
+
onResult(null, e)
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Wait for image (max 10s)
|
|
292
|
+
if (!captureSemaphore.tryAcquire(10, TimeUnit.SECONDS)) {
|
|
293
|
+
captureError = Exception("Still capture timed out after 10s")
|
|
294
|
+
Log.e(TAG, captureError!!.message!!)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Always close Camera2 before handing camera back to ARCore
|
|
298
|
+
try {
|
|
299
|
+
imageReader.close()
|
|
300
|
+
device.close()
|
|
301
|
+
Log.i(TAG, "Camera2 device closed — camera available for ARCore resume")
|
|
302
|
+
} catch (e: Exception) {
|
|
303
|
+
Log.w(TAG, "Error closing Camera2 resources", e)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
onResult(captureFile, captureError)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// -------------------------------------------------------------------------
|
|
310
|
+
// Storage helpers
|
|
311
|
+
// -------------------------------------------------------------------------
|
|
312
|
+
|
|
313
|
+
private fun saveJpegBytes(bytes: ByteArray): File {
|
|
314
|
+
val dir = File(context.getExternalFilesDir(null), "photos")
|
|
315
|
+
if (!dir.exists()) dir.mkdirs()
|
|
316
|
+
val file = File(dir, "replate_${System.currentTimeMillis()}.jpg")
|
|
317
|
+
FileOutputStream(file).use { it.write(bytes) }
|
|
318
|
+
return file
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* DEBUG: copies the JPEG bytes into the device gallery (MediaStore).
|
|
323
|
+
* The file will be visible in the Photos / Gallery app.
|
|
324
|
+
* Only called when [debugSaveToGallery] == true.
|
|
325
|
+
*/
|
|
326
|
+
private fun saveToGallery(bytes: ByteArray, displayName: String) {
|
|
327
|
+
try {
|
|
328
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
329
|
+
val values = ContentValues().apply {
|
|
330
|
+
put(MediaStore.Images.Media.DISPLAY_NAME, displayName)
|
|
331
|
+
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
|
332
|
+
put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/Replate")
|
|
333
|
+
put(MediaStore.Images.Media.IS_PENDING, 1)
|
|
334
|
+
}
|
|
335
|
+
val resolver = context.contentResolver
|
|
336
|
+
val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
|
|
337
|
+
if (uri != null) {
|
|
338
|
+
resolver.openOutputStream(uri)?.use { it.write(bytes) }
|
|
339
|
+
values.clear()
|
|
340
|
+
values.put(MediaStore.Images.Media.IS_PENDING, 0)
|
|
341
|
+
resolver.update(uri, values, null, null)
|
|
342
|
+
Log.i(TAG, "DEBUG: JPEG saved to gallery via MediaStore uri=$uri")
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
@Suppress("DEPRECATION")
|
|
346
|
+
val dir = File(
|
|
347
|
+
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
|
|
348
|
+
"Replate"
|
|
349
|
+
)
|
|
350
|
+
dir.mkdirs()
|
|
351
|
+
val file = File(dir, displayName)
|
|
352
|
+
FileOutputStream(file).use { it.write(bytes) }
|
|
353
|
+
// Notify media scanner
|
|
354
|
+
android.media.MediaScannerConnection.scanFile(context, arrayOf(file.absolutePath), null, null)
|
|
355
|
+
Log.i(TAG, "DEBUG: JPEG saved to gallery (legacy) path=${file.absolutePath}")
|
|
356
|
+
}
|
|
357
|
+
} catch (e: Exception) {
|
|
358
|
+
Log.e(TAG, "DEBUG: Failed to save JPEG to gallery", e)
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|