Devops: KTLint to lint Kotlin code (#6)
* Adds KTLint as a GitHub action * Adds KTLint to the gradle project for IDE integration * Adds .editorconfig to configure KTLint (android/)
This commit is contained in:
		
							
								
								
									
										11
									
								
								.github/workflows/validate-android.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/validate-android.yml
									
									
									
									
										vendored
									
									
								
							| @@ -7,10 +7,12 @@ on: | |||||||
|     paths: |     paths: | ||||||
|       - '.github/workflows/validate-android.yml' |       - '.github/workflows/validate-android.yml' | ||||||
|       - 'android/**' |       - 'android/**' | ||||||
|  |       - '.editorconfig' | ||||||
|   pull_request: |   pull_request: | ||||||
|     paths: |     paths: | ||||||
|       - '.github/workflows/validate-android.yml' |       - '.github/workflows/validate-android.yml' | ||||||
|       - 'android/**' |       - 'android/**' | ||||||
|  |       - '.editorconfig' | ||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   lint: |   lint: | ||||||
| @@ -32,3 +34,12 @@ jobs: | |||||||
|       - uses: yutailang0119/action-android-lint@v1.0.2 |       - uses: yutailang0119/action-android-lint@v1.0.2 | ||||||
|         with: |         with: | ||||||
|           xml_path: android/build/reports/lint-results.xml |           xml_path: android/build/reports/lint-results.xml | ||||||
|  |   ktlint: | ||||||
|  |     name: Kotlin Lint | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v2 | ||||||
|  |       - name: Run KTLint | ||||||
|  |         uses: mrousavy/action-ktlint@v1.6 | ||||||
|  |         with: | ||||||
|  |           github_token: ${{ secrets.github_token }} | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								android/.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								android/.editorconfig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | [*.{kt,kts}] | ||||||
|  | indent_size=2 | ||||||
|  | insert_final_newline=true | ||||||
|  | max_line_length=off | ||||||
|  | disabled_rules=no-wildcard-imports | ||||||
							
								
								
									
										16
									
								
								android/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								android/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | # android | ||||||
|  |  | ||||||
|  | This folder contains the Android-platform-specific code for react-native-vision-camera. | ||||||
|  |  | ||||||
|  | ## Prerequesites | ||||||
|  |  | ||||||
|  | 1. Install ktlint | ||||||
|  |     ```sh | ||||||
|  |     brew install ktlint | ||||||
|  |     ``` | ||||||
|  |  | ||||||
|  | ## Getting Started | ||||||
|  |  | ||||||
|  | It is recommended that you work on the code using the Example project (`example/android/`), since that always includes the React Native header files, plus you can easily test changes that way. | ||||||
|  |  | ||||||
|  | You can however still edit the library project here by opening this folder with Android Studio. | ||||||
| @@ -15,12 +15,15 @@ buildscript { | |||||||
|     // noinspection DifferentKotlinGradleVersion |     // noinspection DifferentKotlinGradleVersion | ||||||
|     classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" |     classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||||||
|     classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" |     classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" | ||||||
|  |     // ktlint | ||||||
|  |     classpath "org.jlleitschuh.gradle:ktlint-gradle:10.0.0" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| apply plugin: 'com.android.library' | apply plugin: 'com.android.library' | ||||||
| apply plugin: 'kotlin-android' | apply plugin: 'kotlin-android' | ||||||
| apply plugin: 'kotlin-android-extensions' | apply plugin: 'kotlin-android-extensions' | ||||||
|  | apply plugin: 'org.jlleitschuh.gradle.ktlint' | ||||||
|  |  | ||||||
| def getExtOrDefault(name) { | def getExtOrDefault(name) { | ||||||
|   return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['VisionCamera_' + name] |   return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['VisionCamera_' + name] | ||||||
|   | |||||||
| @@ -2,8 +2,8 @@ package com.mrousavy.camera | |||||||
|  |  | ||||||
| import android.annotation.SuppressLint | import android.annotation.SuppressLint | ||||||
| import androidx.camera.core.VideoCapture | import androidx.camera.core.VideoCapture | ||||||
| import com.mrousavy.camera.utils.makeErrorMap |  | ||||||
| import com.facebook.react.bridge.* | import com.facebook.react.bridge.* | ||||||
|  | import com.mrousavy.camera.utils.makeErrorMap | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
| import java.io.File | import java.io.File | ||||||
|  |  | ||||||
| @@ -26,7 +26,9 @@ suspend fun CameraView.startRecording(options: ReadableMap, onRecordCallback: Ca | |||||||
|   } |   } | ||||||
|   val videoFileOptions = VideoCapture.OutputFileOptions.Builder(videoFile) |   val videoFileOptions = VideoCapture.OutputFileOptions.Builder(videoFile) | ||||||
|  |  | ||||||
|     videoCapture!!.startRecording(videoFileOptions.build(), recordVideoExecutor, object : VideoCapture.OnVideoSavedCallback { |   videoCapture!!.startRecording( | ||||||
|  |     videoFileOptions.build(), recordVideoExecutor, | ||||||
|  |     object : VideoCapture.OnVideoSavedCallback { | ||||||
|       override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) { |       override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) { | ||||||
|         val map = Arguments.createMap() |         val map = Arguments.createMap() | ||||||
|         map.putString("path", videoFile.absolutePath) |         map.putString("path", videoFile.absolutePath) | ||||||
| @@ -52,12 +54,12 @@ suspend fun CameraView.startRecording(options: ReadableMap, onRecordCallback: Ca | |||||||
|         // reset the torch mode |         // reset the torch mode | ||||||
|         camera!!.cameraControl.enableTorch(torch == "on") |         camera!!.cameraControl.enableTorch(torch == "on") | ||||||
|       } |       } | ||||||
|     }) |     } | ||||||
|  |   ) | ||||||
|  |  | ||||||
|   return TemporaryFile(videoFile.absolutePath) |   return TemporaryFile(videoFile.absolutePath) | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @SuppressLint("RestrictedApi") | @SuppressLint("RestrictedApi") | ||||||
| fun CameraView.stopRecording() { | fun CameraView.stopRecording() { | ||||||
|   if (videoCapture == null) { |   if (videoCapture == null) { | ||||||
|   | |||||||
| @@ -7,10 +7,10 @@ import androidx.camera.camera2.interop.Camera2CameraInfo | |||||||
| import androidx.camera.core.ImageCapture | import androidx.camera.core.ImageCapture | ||||||
| import androidx.camera.core.ImageProxy | import androidx.camera.core.ImageProxy | ||||||
| import androidx.exifinterface.media.ExifInterface | import androidx.exifinterface.media.ExifInterface | ||||||
| import com.mrousavy.camera.utils.* |  | ||||||
| import com.facebook.react.bridge.Arguments | import com.facebook.react.bridge.Arguments | ||||||
| import com.facebook.react.bridge.ReadableMap | import com.facebook.react.bridge.ReadableMap | ||||||
| import com.facebook.react.bridge.WritableMap | import com.facebook.react.bridge.WritableMap | ||||||
|  | import com.mrousavy.camera.utils.* | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
| import java.io.File | import java.io.File | ||||||
|  |  | ||||||
| @@ -70,7 +70,8 @@ suspend fun CameraView.takePhoto(options: ReadableMap): WritableMap = coroutineS | |||||||
|     async(Dispatchers.IO) { |     async(Dispatchers.IO) { | ||||||
|       Log.d(CameraView.REACT_CLASS, "Creating temp file...") |       Log.d(CameraView.REACT_CLASS, "Creating temp file...") | ||||||
|       File.createTempFile("mrousavy", ".jpg", context.cacheDir).apply { deleteOnExit() } |       File.createTempFile("mrousavy", ".jpg", context.cacheDir).apply { deleteOnExit() } | ||||||
|             }) |     } | ||||||
|  |   ) | ||||||
|   val photo = results.first { it is ImageProxy } as ImageProxy |   val photo = results.first { it is ImageProxy } as ImageProxy | ||||||
|   val file = results.first { it is File } as File |   val file = results.first { it is File } as File | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,10 +2,10 @@ package com.mrousavy.camera | |||||||
|  |  | ||||||
| import android.graphics.Bitmap | import android.graphics.Bitmap | ||||||
| import androidx.exifinterface.media.ExifInterface | import androidx.exifinterface.media.ExifInterface | ||||||
| import com.mrousavy.camera.utils.buildMetadataMap |  | ||||||
| import com.facebook.react.bridge.Arguments | import com.facebook.react.bridge.Arguments | ||||||
| import com.facebook.react.bridge.ReadableMap | import com.facebook.react.bridge.ReadableMap | ||||||
| import com.facebook.react.bridge.WritableMap | import com.facebook.react.bridge.WritableMap | ||||||
|  | import com.mrousavy.camera.utils.buildMetadataMap | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
| import kotlinx.coroutines.coroutineScope | import kotlinx.coroutines.coroutineScope | ||||||
| import kotlinx.coroutines.withContext | import kotlinx.coroutines.withContext | ||||||
|   | |||||||
| @@ -20,9 +20,9 @@ import androidx.camera.extensions.NightPreviewExtender | |||||||
| import androidx.camera.view.PreviewView | import androidx.camera.view.PreviewView | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
| import androidx.lifecycle.* | import androidx.lifecycle.* | ||||||
| import com.mrousavy.camera.utils.* |  | ||||||
| import com.facebook.react.bridge.* | import com.facebook.react.bridge.* | ||||||
| import com.facebook.react.uimanager.events.RCTEventEmitter | import com.facebook.react.uimanager.events.RCTEventEmitter | ||||||
|  | import com.mrousavy.camera.utils.* | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
| import java.lang.IllegalArgumentException | import java.lang.IllegalArgumentException | ||||||
| import java.util.concurrent.Executors | import java.util.concurrent.Executors | ||||||
| @@ -342,7 +342,7 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner { | |||||||
|  |  | ||||||
|       Log.d(REACT_CLASS, "Session configured! Camera: ${camera!!}") |       Log.d(REACT_CLASS, "Session configured! Camera: ${camera!!}") | ||||||
|       invokeOnInitialized() |       invokeOnInitialized() | ||||||
|         } catch(exc: Throwable) { |     } catch (exc: Throwable) { | ||||||
|       throw when (exc) { |       throw when (exc) { | ||||||
|         is CameraError -> exc |         is CameraError -> exc | ||||||
|         is IllegalArgumentException -> InvalidCameraDeviceError(exc) |         is IllegalArgumentException -> InvalidCameraDeviceError(exc) | ||||||
|   | |||||||
| @@ -1,14 +1,12 @@ | |||||||
| package com.mrousavy.camera | package com.mrousavy.camera | ||||||
|  |  | ||||||
| import android.util.Log | import android.util.Log | ||||||
| import com.facebook.react.bridge.ReactContext |  | ||||||
| import com.facebook.react.bridge.ReadableArray | import com.facebook.react.bridge.ReadableArray | ||||||
| import com.facebook.react.bridge.ReadableMap | import com.facebook.react.bridge.ReadableMap | ||||||
| import com.facebook.react.common.MapBuilder | import com.facebook.react.common.MapBuilder | ||||||
| import com.facebook.react.uimanager.SimpleViewManager | import com.facebook.react.uimanager.SimpleViewManager | ||||||
| import com.facebook.react.uimanager.ThemedReactContext | import com.facebook.react.uimanager.ThemedReactContext | ||||||
| import com.facebook.react.uimanager.annotations.ReactProp | import com.facebook.react.uimanager.annotations.ReactProp | ||||||
| import java.lang.ref.WeakReference |  | ||||||
|  |  | ||||||
| class CameraViewManager : SimpleViewManager<CameraView>() { | class CameraViewManager : SimpleViewManager<CameraView>() { | ||||||
|   private fun addChangedPropToTransaction(view: CameraView, changedProp: String) { |   private fun addChangedPropToTransaction(view: CameraView, changedProp: String) { | ||||||
|   | |||||||
| @@ -14,11 +14,11 @@ import androidx.camera.core.ImageCapture | |||||||
| import androidx.camera.extensions.HdrImageCaptureExtender | import androidx.camera.extensions.HdrImageCaptureExtender | ||||||
| import androidx.camera.extensions.NightImageCaptureExtender | import androidx.camera.extensions.NightImageCaptureExtender | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
| import com.mrousavy.camera.parsers.* |  | ||||||
| import com.mrousavy.camera.utils.* |  | ||||||
| import com.facebook.react.bridge.* | import com.facebook.react.bridge.* | ||||||
| import com.facebook.react.modules.core.PermissionAwareActivity | import com.facebook.react.modules.core.PermissionAwareActivity | ||||||
| import com.facebook.react.modules.core.PermissionListener | import com.facebook.react.modules.core.PermissionListener | ||||||
|  | import com.mrousavy.camera.parsers.* | ||||||
|  | import com.mrousavy.camera.utils.* | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
| import kotlinx.coroutines.GlobalScope | import kotlinx.coroutines.GlobalScope | ||||||
| import kotlinx.coroutines.launch | import kotlinx.coroutines.launch | ||||||
| @@ -29,7 +29,7 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase | |||||||
|     var RequestCode = 10 |     var RequestCode = 10 | ||||||
|  |  | ||||||
|     fun parsePermissionStatus(status: Int): String { |     fun parsePermissionStatus(status: Int): String { | ||||||
|             return when(status) { |       return when (status) { | ||||||
|         PackageManager.PERMISSION_DENIED -> "denied" |         PackageManager.PERMISSION_DENIED -> "denied" | ||||||
|         PackageManager.PERMISSION_GRANTED -> "authorized" |         PackageManager.PERMISSION_GRANTED -> "authorized" | ||||||
|         else -> "not-determined" |         else -> "not-determined" | ||||||
| @@ -127,8 +127,11 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase | |||||||
|  |  | ||||||
|         // Filters out cameras that are LEGACY hardware level. Those don't support Preview + Photo Capture + Video Capture at the same time. |         // Filters out cameras that are LEGACY hardware level. Those don't support Preview + Photo Capture + Video Capture at the same time. | ||||||
|         if (hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { |         if (hardwareLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { | ||||||
|                     Log.i(REACT_CLASS, "Skipping Camera #${id} because it does not meet the minimum requirements for react-native-vision-camera. " + |           Log.i( | ||||||
|                             "See the tables at https://developer.android.com/reference/android/hardware/camera2/CameraDevice#regular-capture for more information.") |             REACT_CLASS, | ||||||
|  |             "Skipping Camera #$id because it does not meet the minimum requirements for react-native-vision-camera. " + | ||||||
|  |               "See the tables at https://developer.android.com/reference/android/hardware/camera2/CameraDevice#regular-capture for more information." | ||||||
|  |           ) | ||||||
|           return@loop |           return@loop | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,37 +25,42 @@ abstract class CameraError( | |||||||
|    * A throwable that caused this error. |    * A throwable that caused this error. | ||||||
|    */ |    */ | ||||||
|   cause: Throwable? = null |   cause: Throwable? = null | ||||||
| ): Throwable("[$domain/$id] $message", cause) | ) : Throwable("[$domain/$id] $message", cause) | ||||||
|  |  | ||||||
| val CameraError.code: String | val CameraError.code: String | ||||||
|   get() = "$domain/$id" |   get() = "$domain/$id" | ||||||
|  |  | ||||||
|  | class MicrophonePermissionError : CameraError("permission", "microphone-permission-denied", "The Microphone permission was denied!") | ||||||
|  | class CameraPermissionError : CameraError("permission", "camera-permission-denied", "The Camera permission was denied!") | ||||||
|  |  | ||||||
| class MicrophonePermissionError: CameraError("permission", "microphone-permission-denied", "The Microphone permission was denied!") | class InvalidTypeScriptUnionError(unionName: String, unionValue: String) : CameraError("parameter", "invalid-parameter", "The given value for $unionName could not be parsed! (Received: $unionValue)") | ||||||
| class CameraPermissionError: CameraError("permission", "camera-permission-denied", "The Camera permission was denied!") | class UnsupportedOSError(unionName: String, unionValue: String, supportedOnOS: String) : CameraError("parameter", "unsupported-os", "The given value \"$unionValue\" could not be used for $unionName, as it is only available on Android $supportedOnOS and above!") | ||||||
|  |  | ||||||
| class InvalidTypeScriptUnionError(unionName: String, unionValue: String): CameraError("parameter", "invalid-parameter", "The given value for $unionName could not be parsed! (Received: $unionValue)") | class NoCameraDeviceError : CameraError("device", "no-device", "No device was set! Use `getAvailableCameraDevices()` to select a suitable Camera device.") | ||||||
| class UnsupportedOSError(unionName: String, unionValue: String, supportedOnOS: String): CameraError("parameter", "unsupported-os", "The given value \"$unionValue\" could not be used for $unionName, as it is only available on Android $supportedOnOS and above!") | class InvalidCameraDeviceError(cause: Throwable) : CameraError("device", "invalid-device", "The given Camera device could not be found for use-case binding!", cause) | ||||||
|  |  | ||||||
| class NoCameraDeviceError: CameraError("device", "no-device", "No device was set! Use `getAvailableCameraDevices()` to select a suitable Camera device.") | class FpsNotContainedInFormatError(fps: Int) : CameraError("format", "invalid-fps", "The given FPS were not valid for the currently selected format. Make sure you select a format which `frameRateRanges` includes $fps FPS!") | ||||||
| class InvalidCameraDeviceError(cause: Throwable): CameraError("device", "invalid-device", "The given Camera device could not be found for use-case binding!", cause) | class HdrNotContainedInFormatError() : CameraError( | ||||||
|  |   "format", "invalid-hdr", | ||||||
|  |   "The currently selected format does not support HDR capture! " + | ||||||
|  |     "Make sure you select a format which `frameRateRanges` includes `supportsPhotoHDR`!" | ||||||
|  | ) | ||||||
|  | class LowLightBoostNotContainedInFormatError() : CameraError( | ||||||
|  |   "format", "invalid-low-light-boost", | ||||||
|  |   "The currently selected format does not support low-light boost (night mode)! " + | ||||||
|  |     "Make sure you select a format which includes `supportsLowLightBoost`." | ||||||
|  | ) | ||||||
|  |  | ||||||
| class FpsNotContainedInFormatError(fps: Int): CameraError("format", "invalid-fps", "The given FPS were not valid for the currently selected format. Make sure you select a format which `frameRateRanges` includes $fps FPS!") | class CameraNotReadyError : CameraError("session", "camera-not-ready", "The Camera is not ready yet! Wait for the onInitialized() callback!") | ||||||
| class HdrNotContainedInFormatError(): CameraError("format", "invalid-hdr", "The currently selected format does not support HDR capture! " + |  | ||||||
|         "Make sure you select a format which `frameRateRanges` includes `supportsPhotoHDR`!") |  | ||||||
| class LowLightBoostNotContainedInFormatError(): CameraError("format", "invalid-low-light-boost", "The currently selected format does not support low-light boost (night mode)! " + |  | ||||||
|         "Make sure you select a format which includes `supportsLowLightBoost`.") |  | ||||||
|  |  | ||||||
| class CameraNotReadyError: CameraError("session", "camera-not-ready", "The Camera is not ready yet! Wait for the onInitialized() callback!") | class InvalidFormatError(format: Int) : CameraError("capture", "invalid-photo-format", "The Photo has an invalid format! Expected ${ImageFormat.YUV_420_888}, actual: $format") | ||||||
|  | class VideoEncoderError(message: String, cause: Throwable? = null) : CameraError("capture", "encoder-error", message, cause) | ||||||
|  | class VideoMuxerError(message: String, cause: Throwable? = null) : CameraError("capture", "muxer-error", message, cause) | ||||||
|  | class RecordingInProgressError(message: String, cause: Throwable? = null) : CameraError("capture", "recording-in-progress", message, cause) | ||||||
|  | class FileIOError(message: String, cause: Throwable? = null) : CameraError("capture", "file-io-error", message, cause) | ||||||
|  | class InvalidCameraError(message: String, cause: Throwable? = null) : CameraError("capture", "not-bound-error", message, cause) | ||||||
|  |  | ||||||
| class InvalidFormatError(format: Int): CameraError("capture", "invalid-photo-format", "The Photo has an invalid format! Expected ${ImageFormat.YUV_420_888}, actual: $format") | class CameraManagerUnavailableError : CameraError("system", "no-camera-manager", "The Camera manager instance was unavailable for the current Application!") | ||||||
| class VideoEncoderError(message: String, cause: Throwable? = null): CameraError("capture", "encoder-error", message, cause) | class ViewNotFoundError(viewId: Int) : CameraError("system", "view-not-found", "The given view (ID $viewId) was not found in the view manager.") | ||||||
| class VideoMuxerError(message: String, cause: Throwable? = null): CameraError("capture", "muxer-error", message, cause) |  | ||||||
| class RecordingInProgressError(message: String, cause: Throwable? = null): CameraError("capture", "recording-in-progress", message, cause) |  | ||||||
| class FileIOError(message: String, cause: Throwable? = null): CameraError("capture", "file-io-error", message, cause) |  | ||||||
| class InvalidCameraError(message: String, cause: Throwable? = null): CameraError("capture", "not-bound-error", message, cause) |  | ||||||
|  |  | ||||||
| class CameraManagerUnavailableError: CameraError("system", "no-camera-manager", "The Camera manager instance was unavailable for the current Application!") | class UnknownCameraError(cause: Throwable) : CameraError("unknown", "unknown", cause.message ?: "An unknown camera error occured.", cause) | ||||||
| class ViewNotFoundError(viewId: Int): CameraError("system", "view-not-found", "The given view (ID $viewId) was not found in the view manager.") |  | ||||||
|  |  | ||||||
| class UnknownCameraError(cause: Throwable): CameraError("unknown", "unknown", cause.message ?: "An unknown camera error occured.", cause) |  | ||||||
|   | |||||||
| @@ -2,14 +2,12 @@ package com.mrousavy.camera.utils | |||||||
|  |  | ||||||
| import android.hardware.camera2.CameraCharacteristics | import android.hardware.camera2.CameraCharacteristics | ||||||
| import android.util.Size | import android.util.Size | ||||||
| import com.mrousavy.camera.parsers.bigger |  | ||||||
| import com.mrousavy.camera.parsers.parseLensFacing |  | ||||||
| import com.facebook.react.bridge.Arguments | import com.facebook.react.bridge.Arguments | ||||||
| import com.facebook.react.bridge.ReadableArray | import com.facebook.react.bridge.ReadableArray | ||||||
|  | import com.mrousavy.camera.parsers.bigger | ||||||
| import kotlin.math.PI | import kotlin.math.PI | ||||||
| import kotlin.math.atan | import kotlin.math.atan | ||||||
|  |  | ||||||
|  |  | ||||||
| // 35mm is 135 film format, a standard in which focal lengths are usually measured | // 35mm is 135 film format, a standard in which focal lengths are usually measured | ||||||
| val Size35mm = Size(36, 24) | val Size35mm = Size(36, 24) | ||||||
|  |  | ||||||
| @@ -38,7 +36,7 @@ fun CameraCharacteristics.getDeviceTypes(): ReadableArray { | |||||||
|   val deviceTypes = Arguments.createArray() |   val deviceTypes = Arguments.createArray() | ||||||
|  |  | ||||||
|   val containsTelephoto = focalLengths.any { l -> (l * cropFactor) > 35 } // TODO: Telephoto lenses are > 85mm, but we don't have anything between that range.. |   val containsTelephoto = focalLengths.any { l -> (l * cropFactor) > 35 } // TODO: Telephoto lenses are > 85mm, but we don't have anything between that range.. | ||||||
|     //val containsNormalLens = focalLengths.any { l -> (l * cropFactor) > 35 && (l * cropFactor) <= 55 } |   // val containsNormalLens = focalLengths.any { l -> (l * cropFactor) > 35 && (l * cropFactor) <= 55 } | ||||||
|   val containsWideAngle = focalLengths.any { l -> (l * cropFactor) >= 24 && (l * cropFactor) <= 35 } |   val containsWideAngle = focalLengths.any { l -> (l * cropFactor) >= 24 && (l * cropFactor) <= 35 } | ||||||
|   val containsUltraWideAngle = focalLengths.any { l -> (l * cropFactor) < 24 } |   val containsUltraWideAngle = focalLengths.any { l -> (l * cropFactor) < 24 } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,6 @@ import androidx.camera.camera2.interop.Camera2CameraInfo | |||||||
| import androidx.camera.core.CameraSelector | import androidx.camera.core.CameraSelector | ||||||
| import java.lang.IllegalArgumentException | import java.lang.IllegalArgumentException | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Create a new [CameraSelector] which selects the camera with the given [cameraId] |  * Create a new [CameraSelector] which selects the camera with the given [cameraId] | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ class DeviceFormat(map: ReadableMap) { | |||||||
| } | } | ||||||
|  |  | ||||||
| fun rangeFactory(minFrameRate: Any?, maxFrameRate: Any?): Range<Int> { | fun rangeFactory(minFrameRate: Any?, maxFrameRate: Any?): Range<Int> { | ||||||
|     return when(minFrameRate) { |   return when (minFrameRate) { | ||||||
|     is Int -> Range(minFrameRate, maxFrameRate as Int) |     is Int -> Range(minFrameRate, maxFrameRate as Int) | ||||||
|     is Double -> Range(minFrameRate.toInt(), (maxFrameRate as Double).toInt()) |     is Double -> Range(minFrameRate.toInt(), (maxFrameRate as Double).toInt()) | ||||||
|     else -> throw IllegalArgumentException() |     else -> throw IllegalArgumentException() | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ import androidx.exifinterface.media.ExifInterface | |||||||
| import com.facebook.react.bridge.Arguments | import com.facebook.react.bridge.Arguments | ||||||
| import com.facebook.react.bridge.WritableMap | import com.facebook.react.bridge.WritableMap | ||||||
|  |  | ||||||
|  |  | ||||||
| fun ExifInterface.buildMetadataMap(): WritableMap { | fun ExifInterface.buildMetadataMap(): WritableMap { | ||||||
|   val metadataMap = Arguments.createMap() |   val metadataMap = Arguments.createMap() | ||||||
|   metadataMap.putInt("Orientation", this.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) |   metadataMap.putInt("Orientation", this.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)) | ||||||
|   | |||||||
| @@ -4,14 +4,14 @@ import androidx.camera.core.ImageCapture | |||||||
| import androidx.camera.core.ImageCaptureException | import androidx.camera.core.ImageCaptureException | ||||||
| import androidx.camera.core.ImageProxy | import androidx.camera.core.ImageProxy | ||||||
| import java.util.concurrent.Executor | import java.util.concurrent.Executor | ||||||
| import java.util.concurrent.Executors |  | ||||||
| import kotlin.coroutines.resume | import kotlin.coroutines.resume | ||||||
| import kotlin.coroutines.resumeWithException | import kotlin.coroutines.resumeWithException | ||||||
| import kotlin.coroutines.suspendCoroutine | import kotlin.coroutines.suspendCoroutine | ||||||
|  |  | ||||||
|  |  | ||||||
| suspend inline fun ImageCapture.takePicture(options: ImageCapture.OutputFileOptions, executor: Executor) = suspendCoroutine<ImageCapture.OutputFileResults> { cont -> | suspend inline fun ImageCapture.takePicture(options: ImageCapture.OutputFileOptions, executor: Executor) = suspendCoroutine<ImageCapture.OutputFileResults> { cont -> | ||||||
|     this.takePicture(options, executor, object: ImageCapture.OnImageSavedCallback { |   this.takePicture( | ||||||
|  |     options, executor, | ||||||
|  |     object : ImageCapture.OnImageSavedCallback { | ||||||
|       override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { |       override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { | ||||||
|         cont.resume(outputFileResults) |         cont.resume(outputFileResults) | ||||||
|       } |       } | ||||||
| @@ -19,11 +19,14 @@ suspend inline fun ImageCapture.takePicture(options: ImageCapture.OutputFileOpti | |||||||
|       override fun onError(exception: ImageCaptureException) { |       override fun onError(exception: ImageCaptureException) { | ||||||
|         cont.resumeWithException(exception) |         cont.resumeWithException(exception) | ||||||
|       } |       } | ||||||
|     }) |     } | ||||||
|  |   ) | ||||||
| } | } | ||||||
|  |  | ||||||
| suspend inline fun ImageCapture.takePicture(executor: Executor) = suspendCoroutine<ImageProxy> { cont -> | suspend inline fun ImageCapture.takePicture(executor: Executor) = suspendCoroutine<ImageProxy> { cont -> | ||||||
|     this.takePicture(executor, object: ImageCapture.OnImageCapturedCallback() { |   this.takePicture( | ||||||
|  |     executor, | ||||||
|  |     object : ImageCapture.OnImageCapturedCallback() { | ||||||
|       override fun onCaptureSuccess(image: ImageProxy) { |       override fun onCaptureSuccess(image: ImageProxy) { | ||||||
|         super.onCaptureSuccess(image) |         super.onCaptureSuccess(image) | ||||||
|         cont.resume(image) |         cont.resume(image) | ||||||
| @@ -33,5 +36,6 @@ suspend inline fun ImageCapture.takePicture(executor: Executor) = suspendCorouti | |||||||
|         super.onError(exception) |         super.onError(exception) | ||||||
|         cont.resumeWithException(exception) |         cont.resumeWithException(exception) | ||||||
|       } |       } | ||||||
|     }) |     } | ||||||
|  |   ) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,18 +1,16 @@ | |||||||
| package com.mrousavy.camera.utils | package com.mrousavy.camera.utils | ||||||
|  |  | ||||||
| import android.annotation.SuppressLint | import android.annotation.SuppressLint | ||||||
| import android.graphics.BitmapFactory |  | ||||||
| import android.graphics.ImageFormat | import android.graphics.ImageFormat | ||||||
| import androidx.camera.core.ImageProxy | import androidx.camera.core.ImageProxy | ||||||
| import com.mrousavy.camera.InvalidFormatError | import com.mrousavy.camera.InvalidFormatError | ||||||
| import java.io.File | import java.io.File | ||||||
| import java.io.FileOutputStream | import java.io.FileOutputStream | ||||||
| import java.nio.ByteBuffer | import java.nio.ByteBuffer | ||||||
| import java.util.stream.Stream.concat |  | ||||||
|  |  | ||||||
| // TODO: Fix this flip() function (this outputs a black image) | // TODO: Fix this flip() function (this outputs a black image) | ||||||
| fun flip(imageBytes: ByteArray, imageWidth: Int): ByteArray { | fun flip(imageBytes: ByteArray, imageWidth: Int): ByteArray { | ||||||
|     //separate out the sub arrays |   // separate out the sub arrays | ||||||
|   var holder = ByteArray(imageBytes.size) |   var holder = ByteArray(imageBytes.size) | ||||||
|   var subArray = ByteArray(imageWidth) |   var subArray = ByteArray(imageWidth) | ||||||
|   var subCount = 0 |   var subCount = 0 | ||||||
| @@ -35,7 +33,6 @@ fun flip(imageBytes: ByteArray, imageWidth: Int): ByteArray { | |||||||
|   return holder + subArray |   return holder + subArray | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @SuppressLint("UnsafeExperimentalUsageError") | @SuppressLint("UnsafeExperimentalUsageError") | ||||||
| fun ImageProxy.save(file: File, flipHorizontally: Boolean) { | fun ImageProxy.save(file: File, flipHorizontally: Boolean) { | ||||||
|   when (format) { |   when (format) { | ||||||
|   | |||||||
| @@ -9,7 +9,10 @@ import kotlin.coroutines.suspendCoroutine | |||||||
| suspend fun getCameraProvider(context: Context) = suspendCoroutine<ProcessCameraProvider> { cont -> | suspend fun getCameraProvider(context: Context) = suspendCoroutine<ProcessCameraProvider> { cont -> | ||||||
|   val cameraProviderFuture = ProcessCameraProvider.getInstance(context) |   val cameraProviderFuture = ProcessCameraProvider.getInstance(context) | ||||||
|  |  | ||||||
|     cameraProviderFuture.addListener({ |   cameraProviderFuture.addListener( | ||||||
|  |     { | ||||||
|       cont.resume(cameraProviderFuture.get()) |       cont.resume(cameraProviderFuture.get()) | ||||||
|     }, ContextCompat.getMainExecutor(context)) |     }, | ||||||
|  |     ContextCompat.getMainExecutor(context) | ||||||
|  |   ) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ package com.mrousavy.camera.utils | |||||||
| import android.util.Size | import android.util.Size | ||||||
| import android.view.Surface | import android.view.Surface | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Rotate by a given Surface Rotation |  * Rotate by a given Surface Rotation | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package com.mrousavy.camera.utils | package com.mrousavy.camera.utils | ||||||
|  |  | ||||||
|  | import com.facebook.react.bridge.Promise | ||||||
| import com.mrousavy.camera.CameraError | import com.mrousavy.camera.CameraError | ||||||
| import com.mrousavy.camera.UnknownCameraError | import com.mrousavy.camera.UnknownCameraError | ||||||
| import com.facebook.react.bridge.Promise |  | ||||||
|  |  | ||||||
| inline fun withPromise(promise: Promise, closure: () -> Any?) { | inline fun withPromise(promise: Promise, closure: () -> Any?) { | ||||||
|   try { |   try { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user