2020-08-05 14:06:54 +02:00
|
|
|
package sushi.hardcore.droidfs
|
|
|
|
|
2020-08-12 16:14:26 +02:00
|
|
|
import android.Manifest
|
|
|
|
import android.content.pm.PackageManager
|
2020-08-05 14:06:54 +02:00
|
|
|
import android.os.Bundle
|
2020-08-09 15:27:31 +02:00
|
|
|
import android.text.InputType
|
2020-08-05 14:06:54 +02:00
|
|
|
import android.view.View
|
2020-08-09 15:27:31 +02:00
|
|
|
import android.view.WindowManager
|
2020-09-04 04:00:19 +02:00
|
|
|
import android.view.animation.Animation
|
|
|
|
import android.view.animation.LinearInterpolator
|
|
|
|
import android.view.animation.RotateAnimation
|
2020-08-09 15:27:31 +02:00
|
|
|
import android.widget.EditText
|
2020-09-04 04:00:19 +02:00
|
|
|
import android.widget.ImageView
|
2020-08-05 14:06:54 +02:00
|
|
|
import android.widget.Toast
|
2020-08-12 16:14:26 +02:00
|
|
|
import androidx.core.content.ContextCompat
|
2020-08-05 14:06:54 +02:00
|
|
|
import com.otaliastudios.cameraview.CameraListener
|
|
|
|
import com.otaliastudios.cameraview.PictureResult
|
|
|
|
import com.otaliastudios.cameraview.controls.Facing
|
|
|
|
import com.otaliastudios.cameraview.controls.Flash
|
2020-08-11 20:40:14 +02:00
|
|
|
import com.otaliastudios.cameraview.controls.Grid
|
|
|
|
import com.otaliastudios.cameraview.controls.Hdr
|
2020-08-05 14:06:54 +02:00
|
|
|
import kotlinx.android.synthetic.main.activity_camera.*
|
2020-08-09 17:01:47 +02:00
|
|
|
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
|
2020-08-05 14:06:54 +02:00
|
|
|
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
|
|
|
import sushi.hardcore.droidfs.util.MiscUtils
|
|
|
|
import sushi.hardcore.droidfs.util.PathUtils
|
|
|
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
|
|
|
import java.io.ByteArrayInputStream
|
|
|
|
import java.text.SimpleDateFormat
|
|
|
|
import java.util.*
|
|
|
|
|
2020-09-04 04:00:19 +02:00
|
|
|
class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
2020-08-05 14:06:54 +02:00
|
|
|
companion object {
|
|
|
|
private val flashModes = listOf(Flash.AUTO, Flash.ON, Flash.OFF)
|
2020-08-11 20:40:14 +02:00
|
|
|
private val gridTitles = listOf(R.string.grid_none, R.string.grid_3x3, R.string.grid_4x4)
|
|
|
|
private val gridValues = listOf(Grid.OFF, Grid.DRAW_3X3, Grid.DRAW_4X4)
|
2020-08-05 14:06:54 +02:00
|
|
|
private const val fileNameRandomMin = 100000
|
|
|
|
private const val fileNameRandomMax = 999999
|
|
|
|
private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss")
|
|
|
|
private val random = Random()
|
|
|
|
}
|
|
|
|
private var currentFlashModeIndex = 0
|
2020-08-09 15:27:31 +02:00
|
|
|
private var timerDuration = 0
|
|
|
|
set(value) {
|
|
|
|
field = value
|
|
|
|
if (value > 0){
|
2020-08-12 15:14:38 +02:00
|
|
|
image_timer.setImageResource(R.drawable.icon_timer_on)
|
2020-08-09 15:27:31 +02:00
|
|
|
} else {
|
2020-08-12 15:14:38 +02:00
|
|
|
image_timer.setImageResource(R.drawable.icon_timer_off)
|
2020-08-09 15:27:31 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-04 04:00:19 +02:00
|
|
|
private lateinit var sensorOrientationListener: SensorOrientationListener
|
|
|
|
private var previousOrientation: Float = 0f
|
|
|
|
private lateinit var orientedIcons: List<ImageView>
|
2020-08-05 14:06:54 +02:00
|
|
|
private lateinit var gocryptfsVolume: GocryptfsVolume
|
|
|
|
private lateinit var outputDirectory: String
|
|
|
|
private lateinit var fileName: String
|
2020-08-09 17:01:47 +02:00
|
|
|
private var isFinishingIntentionally = false
|
2020-08-05 14:06:54 +02:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
setContentView(R.layout.activity_camera)
|
|
|
|
gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1))
|
|
|
|
outputDirectory = intent.getStringExtra("path")!!
|
|
|
|
camera.setLifecycleOwner(this)
|
|
|
|
camera.addCameraListener(object: CameraListener(){
|
|
|
|
override fun onPictureTaken(result: PictureResult) {
|
|
|
|
take_photo_button.onPhotoTaken()
|
|
|
|
val inputStream = ByteArrayInputStream(result.data)
|
|
|
|
if (gocryptfsVolume.importFile(inputStream, PathUtils.path_join(outputDirectory, fileName))){
|
|
|
|
Toast.makeText(applicationContext, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show()
|
|
|
|
} else {
|
|
|
|
ColoredAlertDialogBuilder(applicationContext)
|
|
|
|
.setTitle(R.string.error)
|
|
|
|
.setMessage(R.string.picture_save_failed)
|
|
|
|
.setCancelable(false)
|
|
|
|
.setPositiveButton(R.string.ok) { _, _ -> finish() }
|
|
|
|
.show()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
take_photo_button.onClick = ::onClickTakePhoto
|
2020-09-04 04:00:19 +02:00
|
|
|
orientedIcons = listOf(image_hdr, image_timer, image_grid, image_close, image_flash, image_camera_switch)
|
|
|
|
sensorOrientationListener = SensorOrientationListener(this)
|
2020-08-05 14:06:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private fun onClickTakePhoto() {
|
|
|
|
val baseName = "IMG_"+dateFormat.format(Date())+"_"
|
|
|
|
do {
|
|
|
|
fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+".jpg"
|
|
|
|
} while (gocryptfsVolume.pathExists(fileName))
|
2020-08-09 15:27:31 +02:00
|
|
|
if (timerDuration > 0){
|
|
|
|
text_timer.visibility = View.VISIBLE
|
|
|
|
Thread{
|
|
|
|
for (i in timerDuration downTo 1){
|
|
|
|
runOnUiThread { text_timer.text = i.toString() }
|
|
|
|
Thread.sleep(1000)
|
|
|
|
}
|
|
|
|
runOnUiThread {
|
2020-08-25 15:54:14 +02:00
|
|
|
camera.takePicture()
|
2020-08-09 15:27:31 +02:00
|
|
|
text_timer.visibility = View.GONE
|
|
|
|
}
|
|
|
|
}.start()
|
|
|
|
} else {
|
2020-08-25 15:54:14 +02:00
|
|
|
camera.takePicture()
|
2020-08-09 15:27:31 +02:00
|
|
|
}
|
2020-08-05 14:06:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fun onClickFlash(view: View) {
|
|
|
|
currentFlashModeIndex = MiscUtils.incrementIndex(currentFlashModeIndex, flashModes)
|
|
|
|
camera.flash = flashModes[currentFlashModeIndex]
|
|
|
|
image_flash.setImageResource(when (camera.flash) {
|
|
|
|
Flash.AUTO -> R.drawable.icon_flash_auto
|
|
|
|
Flash.ON -> R.drawable.icon_flash_on
|
|
|
|
else -> R.drawable.icon_flash_off
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fun onClickCameraSwitch(view: View) {
|
|
|
|
camera.toggleFacing()
|
|
|
|
if (camera.facing == Facing.FRONT){
|
|
|
|
image_camera_switch.setImageResource(R.drawable.icon_camera_back)
|
|
|
|
} else {
|
|
|
|
image_camera_switch.setImageResource(R.drawable.icon_camera_front)
|
|
|
|
Thread {
|
|
|
|
Thread.sleep(25)
|
|
|
|
camera.flash = flashModes[currentFlashModeIndex] //refresh flash mode after switching camera
|
|
|
|
}.start()
|
|
|
|
}
|
|
|
|
}
|
2020-08-09 15:27:31 +02:00
|
|
|
|
2020-08-11 20:40:14 +02:00
|
|
|
fun onClickHDR(view: View) {
|
|
|
|
camera.hdr = when (camera.hdr){
|
|
|
|
Hdr.ON -> {
|
|
|
|
image_hdr.setImageResource(R.drawable.icon_hdr_off)
|
|
|
|
Hdr.OFF
|
|
|
|
}
|
|
|
|
Hdr.OFF -> {
|
|
|
|
image_hdr.setImageResource(R.drawable.icon_hdr_on)
|
|
|
|
Hdr.ON
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 15:27:31 +02:00
|
|
|
fun onClickTimer(view: View) {
|
|
|
|
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
|
|
|
|
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
|
|
|
|
dialogEditText.inputType = InputType.TYPE_CLASS_NUMBER
|
|
|
|
val dialog = ColoredAlertDialogBuilder(this)
|
|
|
|
.setView(dialogEditTextView)
|
2020-08-11 20:40:14 +02:00
|
|
|
.setTitle(getString(R.string.enter_timer_duration))
|
2020-08-09 15:27:31 +02:00
|
|
|
.setPositiveButton(R.string.ok) { _, _ ->
|
2020-08-12 15:14:38 +02:00
|
|
|
val enteredValue = dialogEditText.text.toString()
|
|
|
|
if (enteredValue.isEmpty()){
|
|
|
|
Toast.makeText(this, getString(R.string.timer_empty_error_msg), Toast.LENGTH_SHORT).show()
|
|
|
|
} else {
|
|
|
|
timerDuration = enteredValue.toInt()
|
|
|
|
}
|
2020-08-09 15:27:31 +02:00
|
|
|
}
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.create()
|
|
|
|
dialogEditText.setOnEditorActionListener { _, _, _ ->
|
|
|
|
timerDuration = dialogEditText.text.toString().toInt()
|
|
|
|
dialog.dismiss()
|
|
|
|
true
|
|
|
|
}
|
|
|
|
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
|
|
|
|
dialog.show()
|
|
|
|
}
|
2020-08-09 17:01:47 +02:00
|
|
|
|
2020-08-11 20:40:14 +02:00
|
|
|
fun onClickGrid(view: View) {
|
|
|
|
ColoredAlertDialogBuilder(this)
|
|
|
|
.setTitle(getString(R.string.choose_grid))
|
|
|
|
.setSingleChoiceItems(gridTitles.map { getString(it) as CharSequence }.toTypedArray(), gridValues.indexOf(camera.grid)){ dialog, which ->
|
|
|
|
camera.grid = gridValues[which]
|
2020-08-12 15:14:38 +02:00
|
|
|
image_grid.setImageResource(if (camera.grid == Grid.OFF){ R.drawable.icon_grid_off } else { R.drawable.icon_grid_on })
|
2020-08-11 20:40:14 +02:00
|
|
|
dialog.dismiss()
|
|
|
|
}
|
|
|
|
.setNegativeButton(R.string.cancel, null)
|
|
|
|
.show()
|
|
|
|
}
|
|
|
|
|
2020-08-25 15:54:14 +02:00
|
|
|
fun onClickClose(view: View) {
|
|
|
|
isFinishingIntentionally = true
|
|
|
|
finish()
|
2020-08-12 15:14:38 +02:00
|
|
|
}
|
|
|
|
|
2020-08-09 17:01:47 +02:00
|
|
|
override fun onDestroy() {
|
|
|
|
super.onDestroy()
|
|
|
|
if (!isFinishingIntentionally) {
|
|
|
|
gocryptfsVolume.close()
|
|
|
|
RestrictedFileProvider.wipeAll(this)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-12 16:14:26 +02:00
|
|
|
override fun onStop() {
|
|
|
|
super.onStop()
|
|
|
|
if (!isFinishing){
|
|
|
|
finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 17:01:47 +02:00
|
|
|
override fun onPause() {
|
|
|
|
super.onPause()
|
2020-09-04 04:00:19 +02:00
|
|
|
sensorOrientationListener.remove(this)
|
2020-08-12 16:14:26 +02:00
|
|
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){ //if not asking for permission
|
|
|
|
finish()
|
|
|
|
}
|
2020-08-09 17:01:47 +02:00
|
|
|
}
|
|
|
|
|
2020-09-04 04:00:19 +02:00
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
sensorOrientationListener.addListener(this)
|
|
|
|
}
|
|
|
|
|
2020-08-09 17:01:47 +02:00
|
|
|
override fun onBackPressed() {
|
|
|
|
super.onBackPressed()
|
|
|
|
isFinishingIntentionally = true
|
|
|
|
}
|
2020-09-04 04:00:19 +02:00
|
|
|
|
|
|
|
override fun onOrientationChange(newOrientation: Int) {
|
|
|
|
val reversedOrientation = when (newOrientation){
|
|
|
|
90 -> 270
|
|
|
|
270 -> 90
|
|
|
|
else -> newOrientation
|
|
|
|
}.toFloat()
|
|
|
|
val rotateAnimation = RotateAnimation(previousOrientation, when {
|
|
|
|
reversedOrientation - previousOrientation > 180 -> reversedOrientation - 360
|
|
|
|
reversedOrientation - previousOrientation < -180 -> reversedOrientation + 360
|
|
|
|
else -> reversedOrientation
|
|
|
|
}, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
|
|
|
|
rotateAnimation.duration = 300
|
|
|
|
rotateAnimation.interpolator = LinearInterpolator()
|
|
|
|
rotateAnimation.fillAfter = true
|
|
|
|
orientedIcons.map { it.startAnimation(rotateAnimation) }
|
|
|
|
previousOrientation = reversedOrientation
|
|
|
|
}
|
2020-08-05 14:06:54 +02:00
|
|
|
}
|