Fix flash and timer for video recording

This commit is contained in:
Matéo Duparc 2021-12-20 15:30:51 +01:00
parent 8b4adfbe21
commit b65ee230be
Signed by: hardcoresushi
GPG Key ID: 007F84120107191E
1 changed files with 102 additions and 73 deletions

View File

@ -84,6 +84,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
private var isBackCamera = true private var isBackCamera = true
private var isInVideoMode = false private var isInVideoMode = false
private var isRecording = false private var isRecording = false
private var isWaitingForTimer = false
private lateinit var binding: ActivityCameraBinding private lateinit var binding: ActivityCameraBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -185,24 +186,39 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
dialog.show() dialog.show()
} }
binding.imageFlash.setOnClickListener { binding.imageFlash.setOnClickListener {
binding.imageFlash.setImageResource(when (imageCapture?.flashMode) { binding.imageFlash.setImageResource(if (isInVideoMode) {
ImageCapture.FLASH_MODE_AUTO -> { when (imageCapture?.flashMode) {
imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON ImageCapture.FLASH_MODE_ON -> {
R.drawable.icon_flash_on camera?.cameraControl?.enableTorch(false)
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
R.drawable.icon_flash_off
}
else -> {
camera?.cameraControl?.enableTorch(true)
imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
R.drawable.icon_flash_on
}
} }
ImageCapture.FLASH_MODE_ON -> { } else {
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF when (imageCapture?.flashMode) {
R.drawable.icon_flash_off ImageCapture.FLASH_MODE_AUTO -> {
} imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
else -> { R.drawable.icon_flash_on
imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO }
R.drawable.icon_flash_auto ImageCapture.FLASH_MODE_ON -> {
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
R.drawable.icon_flash_off
}
else -> {
imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
R.drawable.icon_flash_auto
}
} }
}) })
} }
binding.imageModeSwitch.setOnClickListener { binding.imageModeSwitch.setOnClickListener {
isInVideoMode = !isInVideoMode isInVideoMode = !isInVideoMode
if (isInVideoMode) { binding.imageFlash.setImageResource(if (isInVideoMode) {
binding.recordVideoButton.visibility = View.VISIBLE binding.recordVideoButton.visibility = View.VISIBLE
binding.takePhotoButton.visibility = View.GONE binding.takePhotoButton.visibility = View.GONE
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@ -211,10 +227,14 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), AUDIO_PERMISSION_REQUEST_CODE) requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), AUDIO_PERMISSION_REQUEST_CODE)
} }
} }
imageCapture?.flashMode = ImageCapture.FLASH_MODE_OFF
R.drawable.icon_flash_off
} else { } else {
binding.recordVideoButton.visibility = View.GONE binding.recordVideoButton.visibility = View.GONE
binding.takePhotoButton.visibility = View.VISIBLE binding.takePhotoButton.visibility = View.VISIBLE
} imageCapture?.flashMode = ImageCapture.FLASH_MODE_AUTO
R.drawable.icon_flash_auto
})
} }
binding.imageCameraSwitch.setOnClickListener { binding.imageCameraSwitch.setOnClickListener {
isBackCamera = if (isBackCamera) { isBackCamera = if (isBackCamera) {
@ -337,34 +357,6 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
} }
} }
private fun takePhoto(outputPath: String) {
val imageCapture = imageCapture ?: return
val outputBuff = ByteArrayOutputStream()
val outputOptions = ImageCapture.OutputFileOptions.Builder(outputBuff).build()
imageCapture.takePicture(outputOptions, executor, object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
binding.takePhotoButton.onPhotoTaken()
if (gocryptfsVolume.importFile(ByteArrayInputStream(outputBuff.toByteArray()), outputPath)){
Toast.makeText(applicationContext, getString(R.string.picture_save_success, outputPath), Toast.LENGTH_SHORT).show()
} else {
CustomAlertDialogBuilder(this@CameraActivity, themeValue)
.setTitle(R.string.error)
.setMessage(R.string.picture_save_failed)
.setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ ->
isFinishingIntentionally = true
finish()
}
.show()
}
}
override fun onError(exception: ImageCaptureException) {
binding.takePhotoButton.onPhotoTaken()
Toast.makeText(applicationContext, exception.message, Toast.LENGTH_SHORT).show()
}
})
}
private fun getOutputPath(isVideo: Boolean): String { private fun getOutputPath(isVideo: Boolean): String {
val baseName = if (isVideo) {"VID"} else {"IMG"}+'_'+dateFormat.format(Date())+'_' val baseName = if (isVideo) {"VID"} else {"IMG"}+'_'+dateFormat.format(Date())+'_'
var fileName: String var fileName: String
@ -374,57 +366,94 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
return PathUtils.pathJoin(outputDirectory, fileName) return PathUtils.pathJoin(outputDirectory, fileName)
} }
private fun onClickTakePhoto() { private fun startTimerThen(action: () -> Unit) {
val path = getOutputPath(false)
if (timerDuration > 0){ if (timerDuration > 0){
binding.textTimer.visibility = View.VISIBLE binding.textTimer.visibility = View.VISIBLE
isWaitingForTimer = true
Thread{ Thread{
for (i in timerDuration downTo 1){ for (i in timerDuration downTo 1){
runOnUiThread { binding.textTimer.text = i.toString() } runOnUiThread { binding.textTimer.text = i.toString() }
Thread.sleep(1000) Thread.sleep(1000)
} }
runOnUiThread { runOnUiThread {
takePhoto(path) action()
binding.textTimer.visibility = View.GONE binding.textTimer.visibility = View.GONE
} }
isWaitingForTimer = false
}.start() }.start()
} else { } else {
takePhoto(path) action()
}
}
private fun onClickTakePhoto() {
if (!isWaitingForTimer) {
val outputPath = getOutputPath(false)
startTimerThen {
imageCapture?.let { imageCapture ->
val outputBuff = ByteArrayOutputStream()
val outputOptions = ImageCapture.OutputFileOptions.Builder(outputBuff).build()
imageCapture.takePicture(outputOptions, executor, object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
binding.takePhotoButton.onPhotoTaken()
if (gocryptfsVolume.importFile(ByteArrayInputStream(outputBuff.toByteArray()), outputPath)) {
Toast.makeText(applicationContext, getString(R.string.picture_save_success, outputPath), Toast.LENGTH_SHORT).show()
} else {
CustomAlertDialogBuilder(this@CameraActivity, themeValue)
.setTitle(R.string.error)
.setMessage(R.string.picture_save_failed)
.setCancelable(false)
.setPositiveButton(R.string.ok) { _, _ ->
isFinishingIntentionally = true
finish()
}
.show()
}
}
override fun onError(exception: ImageCaptureException) {
binding.takePhotoButton.onPhotoTaken()
Toast.makeText(applicationContext, exception.message, Toast.LENGTH_SHORT).show()
}
})
}
}
} }
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
private fun onClickRecordVideo() { private fun onClickRecordVideo() {
isRecording = if (isRecording) { if (isRecording) {
videoCapture?.stopRecording() videoCapture?.stopRecording()
false isRecording = false
} else { } else if (!isWaitingForTimer) {
val path = getOutputPath(true) val path = getOutputPath(true)
val handleId = gocryptfsVolume.openWriteMode(path) startTimerThen {
videoCapture?.startRecording(VideoCapture.OutputFileOptions(object : SeekableWriter { val handleId = gocryptfsVolume.openWriteMode(path)
var offset = 0L videoCapture?.startRecording(VideoCapture.OutputFileOptions(object : SeekableWriter {
override fun write(byteArray: ByteArray) { var offset = 0L
offset += gocryptfsVolume.writeFile(handleId, offset, byteArray, byteArray.size) override fun write(byteArray: ByteArray) {
} offset += gocryptfsVolume.writeFile(handleId, offset, byteArray, byteArray.size)
override fun seek(offset: Long) { }
this.offset = offset override fun seek(offset: Long) {
} this.offset = offset
override fun close() { }
gocryptfsVolume.closeFile(handleId) override fun close() {
} gocryptfsVolume.closeFile(handleId)
}), executor, object : VideoCapture.OnVideoSavedCallback { }
override fun onVideoSaved() { }), executor, object : VideoCapture.OnVideoSavedCallback {
Toast.makeText(applicationContext, getString(R.string.video_save_success, path), Toast.LENGTH_SHORT).show() override fun onVideoSaved() {
binding.recordVideoButton.setImageResource(R.drawable.record_video_button) Toast.makeText(applicationContext, getString(R.string.video_save_success, path), Toast.LENGTH_SHORT).show()
} binding.recordVideoButton.setImageResource(R.drawable.record_video_button)
override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) { }
Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show() override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
cause?.printStackTrace() Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show()
binding.recordVideoButton.setImageResource(R.drawable.record_video_button) cause?.printStackTrace()
} binding.recordVideoButton.setImageResource(R.drawable.record_video_button)
}) }
binding.recordVideoButton.setImageResource(R.drawable.stop_recording_video_button) })
true binding.recordVideoButton.setImageResource(R.drawable.stop_recording_video_button)
isRecording = true
}
} }
} }