forked from hardcoresushi/DroidFS
Switching to CameraX
This commit is contained in:
parent
b23cb7b8ce
commit
eefca5ee0a
@ -47,7 +47,7 @@ dependencies {
|
|||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation "androidx.core:core-ktx:1.3.2"
|
implementation "androidx.core:core-ktx:1.3.2"
|
||||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.0.3"
|
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||||
|
|
||||||
implementation "androidx.sqlite:sqlite-ktx:2.1.0"
|
implementation "androidx.sqlite:sqlite-ktx:2.1.0"
|
||||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||||
@ -56,6 +56,12 @@ dependencies {
|
|||||||
implementation "com.github.bumptech.glide:glide:4.11.0"
|
implementation "com.github.bumptech.glide:glide:4.11.0"
|
||||||
implementation "com.google.android.exoplayer:exoplayer-core:2.11.7"
|
implementation "com.google.android.exoplayer:exoplayer-core:2.11.7"
|
||||||
implementation "com.google.android.exoplayer:exoplayer-ui:2.11.7"
|
implementation "com.google.android.exoplayer:exoplayer-ui:2.11.7"
|
||||||
implementation "com.otaliastudios:cameraview:2.6.4"
|
|
||||||
implementation "androidx.biometric:biometric:1.0.1"
|
implementation "androidx.biometric:biometric:1.0.1"
|
||||||
|
|
||||||
|
def camerax_version = "1.0.0-rc01"
|
||||||
|
implementation "androidx.camera:camera-camera2:$camerax_version"
|
||||||
|
implementation "androidx.camera:camera-lifecycle:$camerax_version"
|
||||||
|
implementation "androidx.camera:camera-view:1.0.0-alpha20"
|
||||||
|
implementation "androidx.camera:camera-extensions:1.0.0-alpha20"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
@ -25,4 +25,3 @@
|
|||||||
*;
|
*;
|
||||||
}
|
}
|
||||||
-keep class sushi.hardcore.droidfs.explorers.ExplorerElement
|
-keep class sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||||
-keep class com.otaliastudios.cameraview.markers.DefaultAutoFocusMarker
|
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
android:name="android.hardware.camera.any"
|
android:name="android.hardware.camera.any"
|
||||||
|
@ -3,8 +3,15 @@ package sushi.hardcore.droidfs
|
|||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.hardware.camera2.CameraCharacteristics
|
||||||
|
import android.hardware.camera2.CameraManager
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.InputType
|
import android.text.InputType
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.util.Size
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.ScaleGestureDetector
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.view.animation.Animation
|
import android.view.animation.Animation
|
||||||
@ -12,35 +19,34 @@ import android.view.animation.LinearInterpolator
|
|||||||
import android.view.animation.RotateAnimation
|
import android.view.animation.RotateAnimation
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import android.widget.RelativeLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.camera.camera2.interop.Camera2CameraInfo
|
||||||
|
import androidx.camera.core.*
|
||||||
|
import androidx.camera.extensions.HdrImageCaptureExtender
|
||||||
|
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.otaliastudios.cameraview.CameraListener
|
|
||||||
import com.otaliastudios.cameraview.PictureResult
|
|
||||||
import com.otaliastudios.cameraview.controls.Facing
|
|
||||||
import com.otaliastudios.cameraview.controls.Flash
|
|
||||||
import com.otaliastudios.cameraview.controls.Grid
|
|
||||||
import com.otaliastudios.cameraview.controls.Hdr
|
|
||||||
import kotlinx.android.synthetic.main.activity_camera.*
|
import kotlinx.android.synthetic.main.activity_camera.*
|
||||||
|
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
|
||||||
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
|
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
|
||||||
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
import sushi.hardcore.droidfs.util.GocryptfsVolume
|
||||||
import sushi.hardcore.droidfs.util.MiscUtils
|
|
||||||
import sushi.hardcore.droidfs.util.PathUtils
|
import sushi.hardcore.droidfs.util.PathUtils
|
||||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.ExecutorService
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
||||||
companion object {
|
companion object {
|
||||||
private val flashModes = listOf(Flash.AUTO, Flash.ON, Flash.OFF)
|
private const val CAMERA_PERMISSION_REQUEST_CODE = 1
|
||||||
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)
|
|
||||||
private const val fileNameRandomMin = 100000
|
private const val fileNameRandomMin = 100000
|
||||||
private const val fileNameRandomMax = 999999
|
private const val fileNameRandomMax = 999999
|
||||||
private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss")
|
private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss")
|
||||||
private val random = Random()
|
private val random = Random()
|
||||||
}
|
}
|
||||||
private var currentFlashModeIndex = 0
|
|
||||||
private var timerDuration = 0
|
private var timerDuration = 0
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
@ -57,22 +63,140 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
private lateinit var outputDirectory: String
|
private lateinit var outputDirectory: String
|
||||||
private lateinit var fileName: String
|
private lateinit var fileName: String
|
||||||
private var isFinishingIntentionally = false
|
private var isFinishingIntentionally = false
|
||||||
private lateinit var context: Context
|
private lateinit var cameraExecutor: ExecutorService
|
||||||
|
private var imageCapture: ImageCapture? = null
|
||||||
|
private var resolutions: Array<Size>? = null
|
||||||
|
private var currentResolutionIndex: Int = 0
|
||||||
|
private var isBackCamera = true
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_camera)
|
setContentView(R.layout.activity_camera)
|
||||||
gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1))
|
gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1))
|
||||||
outputDirectory = intent.getStringExtra("path")!!
|
outputDirectory = intent.getStringExtra("path")!!
|
||||||
context = this
|
|
||||||
camera.setLifecycleOwner(this)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
camera.addCameraListener(object: CameraListener(){
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){
|
||||||
override fun onPictureTaken(result: PictureResult) {
|
setupCamera()
|
||||||
take_photo_button.onPhotoTaken()
|
} else {
|
||||||
val inputStream = ByteArrayInputStream(result.data)
|
requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_REQUEST_CODE)
|
||||||
if (gocryptfsVolume.importFile(inputStream, PathUtils.pathJoin(outputDirectory, fileName))){
|
}
|
||||||
Toast.makeText(context, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show()
|
} else {
|
||||||
|
setupCamera()
|
||||||
|
}
|
||||||
|
|
||||||
|
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||||
|
|
||||||
|
take_photo_button.onClick = ::onClickTakePhoto
|
||||||
|
orientedIcons = listOf(image_ratio, image_timer, image_close, image_flash, image_camera_switch)
|
||||||
|
sensorOrientationListener = SensorOrientationListener(this)
|
||||||
|
|
||||||
|
val scaleGestureDetector = ScaleGestureDetector(this, object : ScaleGestureDetector.SimpleOnScaleGestureListener(){
|
||||||
|
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
||||||
|
val currentZoomRatio = imageCapture?.camera?.cameraInfo?.zoomState?.value?.zoomRatio ?: 0F
|
||||||
|
imageCapture?.camera?.cameraControl?.setZoomRatio(currentZoomRatio*detector.scaleFactor)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
camera_preview.setOnTouchListener { _, motionEvent: MotionEvent ->
|
||||||
|
when (motionEvent.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> true
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
val factory = camera_preview.meteringPointFactory
|
||||||
|
val point = factory.createPoint(motionEvent.x, motionEvent.y)
|
||||||
|
val action = FocusMeteringAction.Builder(point).build()
|
||||||
|
imageCapture?.camera?.cameraControl?.startFocusAndMetering(action)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_MOVE -> scaleGestureDetector.onTouchEvent(motionEvent)
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||||
|
when (requestCode) {
|
||||||
|
CAMERA_PERMISSION_REQUEST_CODE -> if (grantResults.size == 1) {
|
||||||
|
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
ColoredAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.error)
|
||||||
|
.setMessage(R.string.camera_perm_needed)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
isFinishingIntentionally = true
|
||||||
|
finish()
|
||||||
|
}.show()
|
||||||
} else {
|
} else {
|
||||||
ColoredAlertDialogBuilder(context)
|
setupCamera()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun adaptPreviewSize(resolution: Size){
|
||||||
|
val metrics = DisplayMetrics()
|
||||||
|
windowManager.defaultDisplay.getMetrics(metrics)
|
||||||
|
//resolution.width and resolution.height seem to be inverted
|
||||||
|
val width = resolution.height
|
||||||
|
val height = resolution.width
|
||||||
|
camera_preview.layoutParams = if (metrics.widthPixels < width){
|
||||||
|
RelativeLayout.LayoutParams(
|
||||||
|
metrics.widthPixels,
|
||||||
|
(height * (metrics.widthPixels.toFloat() / width)).toInt()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
RelativeLayout.LayoutParams(width, height)
|
||||||
|
}
|
||||||
|
(camera_preview.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.CENTER_IN_PARENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupCamera(resolution: Size? = null){
|
||||||
|
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||||
|
cameraProviderFuture.addListener({
|
||||||
|
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
|
||||||
|
val preview = Preview.Builder()
|
||||||
|
.build()
|
||||||
|
.also {
|
||||||
|
it.setSurfaceProvider(camera_preview.surfaceProvider)
|
||||||
|
}
|
||||||
|
val builder = ImageCapture.Builder()
|
||||||
|
.setFlashMode(ImageCapture.FLASH_MODE_AUTO)
|
||||||
|
resolution?.let {
|
||||||
|
builder.setTargetResolution(it)
|
||||||
|
}
|
||||||
|
val hdrImageCapture = HdrImageCaptureExtender.create(builder)
|
||||||
|
val cameraSelector = if (isBackCamera){ CameraSelector.DEFAULT_BACK_CAMERA } else { CameraSelector.DEFAULT_FRONT_CAMERA }
|
||||||
|
|
||||||
|
if (hdrImageCapture.isExtensionAvailable(cameraSelector)){
|
||||||
|
hdrImageCapture.enableExtension(cameraSelector)
|
||||||
|
}
|
||||||
|
|
||||||
|
imageCapture = builder.build()
|
||||||
|
|
||||||
|
cameraProvider.unbindAll()
|
||||||
|
val camera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture)
|
||||||
|
|
||||||
|
adaptPreviewSize(imageCapture!!.attachedSurfaceResolution!!)
|
||||||
|
|
||||||
|
val info = Camera2CameraInfo.from(camera.cameraInfo)
|
||||||
|
val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||||
|
val characteristics = cameraManager.getCameraCharacteristics(info.cameraId)
|
||||||
|
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)?.let { streamConfigurationMap ->
|
||||||
|
resolutions = streamConfigurationMap.getOutputSizes(imageCapture!!.imageFormat)
|
||||||
|
}
|
||||||
|
}, ContextCompat.getMainExecutor(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun takePhoto() {
|
||||||
|
val imageCapture = imageCapture ?: return
|
||||||
|
val outputBuff = ByteArrayOutputStream()
|
||||||
|
val outputOptions = ImageCapture.OutputFileOptions.Builder(outputBuff).build()
|
||||||
|
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
|
||||||
|
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||||
|
take_photo_button.onPhotoTaken()
|
||||||
|
if (gocryptfsVolume.importFile(ByteArrayInputStream(outputBuff.toByteArray()), PathUtils.pathJoin(outputDirectory, fileName))){
|
||||||
|
Toast.makeText(applicationContext, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show()
|
||||||
|
} else {
|
||||||
|
ColoredAlertDialogBuilder(applicationContext)
|
||||||
.setTitle(R.string.error)
|
.setTitle(R.string.error)
|
||||||
.setMessage(R.string.picture_save_failed)
|
.setMessage(R.string.picture_save_failed)
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
@ -83,10 +207,11 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override fun onError(exception: ImageCaptureException) {
|
||||||
|
take_photo_button.onPhotoTaken()
|
||||||
|
Toast.makeText(applicationContext, exception.message, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
take_photo_button.onClick = ::onClickTakePhoto
|
|
||||||
orientedIcons = listOf(image_hdr, image_timer, image_grid, image_close, image_flash, image_camera_switch)
|
|
||||||
sensorOrientationListener = SensorOrientationListener(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onClickTakePhoto() {
|
private fun onClickTakePhoto() {
|
||||||
@ -102,49 +227,41 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
}
|
}
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
camera.takePicture()
|
takePhoto()
|
||||||
text_timer.visibility = View.GONE
|
text_timer.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
} else {
|
} else {
|
||||||
camera.takePicture()
|
takePhoto()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickFlash(view: View) {
|
fun onClickFlash(view: View) {
|
||||||
currentFlashModeIndex = MiscUtils.incrementIndex(currentFlashModeIndex, flashModes)
|
image_flash.setImageResource(when (imageCapture?.flashMode) {
|
||||||
camera.flash = flashModes[currentFlashModeIndex]
|
ImageCapture.FLASH_MODE_AUTO -> {
|
||||||
image_flash.setImageResource(when (camera.flash) {
|
imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
|
||||||
Flash.AUTO -> R.drawable.icon_flash_auto
|
R.drawable.icon_flash_on
|
||||||
Flash.ON -> R.drawable.icon_flash_on
|
}
|
||||||
else -> R.drawable.icon_flash_off
|
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
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickCameraSwitch(view: View) {
|
fun onClickCameraSwitch(view: View) {
|
||||||
camera.toggleFacing()
|
isBackCamera = if (isBackCamera) {
|
||||||
if (camera.facing == Facing.FRONT){
|
|
||||||
image_camera_switch.setImageResource(R.drawable.icon_camera_back)
|
|
||||||
} else {
|
|
||||||
image_camera_switch.setImageResource(R.drawable.icon_camera_front)
|
image_camera_switch.setImageResource(R.drawable.icon_camera_front)
|
||||||
Thread {
|
false
|
||||||
Thread.sleep(25)
|
} else {
|
||||||
camera.flash = flashModes[currentFlashModeIndex] //refresh flash mode after switching camera
|
image_camera_switch.setImageResource(R.drawable.icon_camera_back)
|
||||||
}.start()
|
true
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
setupCamera()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickTimer(view: View) {
|
fun onClickTimer(view: View) {
|
||||||
@ -173,16 +290,18 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
dialog.show()
|
dialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickGrid(view: View) {
|
fun onClickRatio(view: View) {
|
||||||
ColoredAlertDialogBuilder(this)
|
resolutions?.let {
|
||||||
.setTitle(getString(R.string.choose_grid))
|
ColoredAlertDialogBuilder(this)
|
||||||
.setSingleChoiceItems(gridTitles.map { getString(it) }.toTypedArray(), gridValues.indexOf(camera.grid)){ dialog, which ->
|
.setTitle(R.string.choose_resolution)
|
||||||
camera.grid = gridValues[which]
|
.setSingleChoiceItems(DialogSingleChoiceAdapter(this, it.map { size -> size.toString() }.toTypedArray()), currentResolutionIndex) { dialog, which ->
|
||||||
image_grid.setImageResource(if (camera.grid == Grid.OFF){ R.drawable.icon_grid_off } else { R.drawable.icon_grid_on })
|
setupCamera(resolutions!![which])
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
currentResolutionIndex = which
|
||||||
.setNegativeButton(R.string.cancel, null)
|
}
|
||||||
.show()
|
.setNegativeButton(R.string.cancel, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickClose(view: View) {
|
fun onClickClose(view: View) {
|
||||||
@ -192,6 +311,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
|
cameraExecutor.shutdown()
|
||||||
if (!isFinishingIntentionally) {
|
if (!isFinishingIntentionally) {
|
||||||
gocryptfsVolume.close()
|
gocryptfsVolume.close()
|
||||||
RestrictedFileProvider.wipeAll(this)
|
RestrictedFileProvider.wipeAll(this)
|
||||||
|
@ -419,7 +419,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
|||||||
setCurrentPath(currentDirectoryPath)
|
setCurrentPath(currentDirectoryPath)
|
||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show()
|
.show()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM8,20L4,20v-4h4v4zM8,14L4,14v-4h4v4zM8,8L4,8L4,4h4v4zM14,20h-4v-4h4v4zM14,14h-4v-4h4v4zM14,8h-4L10,4h4v4zM20,20h-4v-4h4v4zM20,14h-4v-4h4v4zM20,8h-4L16,4h4v4z"/>
|
<path android:fillColor="@android:color/white" android:pathData="M19,12h-2v3h-3v2h5v-5zM7,9h3L10,7L5,7v5h2L7,9zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.99h18v14.02z"/>
|
||||||
</vector>
|
</vector>
|
@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M8,4v1.45l2,2L10,4h4v4h-3.45l2,2L14,10v1.45l2,2L16,10h4v4h-3.45l2,2L20,16v1.45l2,2L22,4c0,-1.1 -0.9,-2 -2,-2L4.55,2l2,2L8,4zM16,4h4v4h-4L16,4zM1.27,1.27L0,2.55l2,2L2,20c0,1.1 0.9,2 2,2h15.46l2,2 1.27,-1.27L1.27,1.27zM10,12.55L11.45,14L10,14v-1.45zM4,6.55L5.45,8L4,8L4,6.55zM8,20L4,20v-4h4v4zM8,14L4,14v-4h3.45l0.55,0.55L8,14zM14,20h-4v-4h3.45l0.55,0.54L14,20zM16,20v-1.46L17.46,20L16,20z"/>
|
|
||||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M17.5,15v-2h1.1l0.9,2L21,15l-0.9,-2.1c0.5,-0.2 0.9,-0.8 0.9,-1.4v-1c0,-0.8 -0.7,-1.5 -1.5,-1.5L16,9v4.9l1.1,1.1h0.4zM17.5,10.5h2v1h-2v-1zM13,10.5v0.4l1.5,1.5v-1.9c0,-0.8 -0.7,-1.5 -1.5,-1.5h-1.9l1.5,1.5h0.4zM9.5,9.5l-7,-7 -1.1,1L6.9,9h-0.4v2h-2L4.5,9L3,9v6h1.5v-2.5h2L6.5,15L8,15v-4.9l1.5,1.5L9.5,15h3.4l7.6,7.6 1.1,-1.1 -12.1,-12z"/>
|
|
||||||
</vector>
|
|
@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M21,11.5v-1c0,-0.8 -0.7,-1.5 -1.5,-1.5L16,9v6h1.5v-2h1.1l0.9,2L21,15l-0.9,-2.1c0.5,-0.3 0.9,-0.8 0.9,-1.4zM19.5,11.5h-2v-1h2v1zM6.5,11h-2L4.5,9L3,9v6h1.5v-2.5h2L6.5,15L8,15L8,9L6.5,9v2zM13,9L9.5,9v6L13,15c0.8,0 1.5,-0.7 1.5,-1.5v-3c0,-0.8 -0.7,-1.5 -1.5,-1.5zM13,13.5h-2v-3h2v3z"/>
|
|
||||||
</vector>
|
|
@ -6,17 +6,11 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
tools:context=".CameraActivity">
|
tools:context=".CameraActivity">
|
||||||
|
|
||||||
<com.otaliastudios.cameraview.CameraView
|
<androidx.camera.view.PreviewView
|
||||||
android:id="@+id/camera"
|
android:id="@+id/camera_preview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="0dp"
|
||||||
app:cameraGesturePinch="zoom"
|
android:layout_centerInParent="true"/>
|
||||||
app:cameraGestureTap="autoFocus"
|
|
||||||
app:cameraAutoFocusMarker="@string/cameraview_default_autofocus_marker"
|
|
||||||
app:cameraHdr="on"
|
|
||||||
app:cameraPictureFormat="jpeg"
|
|
||||||
app:cameraPlaySounds="false"
|
|
||||||
app:cameraAudio="off"/>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -24,11 +18,11 @@
|
|||||||
android:layout_marginTop="20dp">
|
android:layout_marginTop="20dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/image_hdr"
|
android:id="@+id/image_ratio"
|
||||||
android:layout_width="30dp"
|
android:layout_width="30dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:onClick="onClickHDR"
|
android:onClick="onClickRatio"
|
||||||
android:src="@drawable/icon_hdr_on"
|
android:src="@drawable/icon_aspect_ratio"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/image_timer"
|
app:layout_constraintEnd_toStartOf="@id/image_timer"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@ -41,19 +35,8 @@
|
|||||||
android:onClick="onClickTimer"
|
android:onClick="onClickTimer"
|
||||||
android:src="@drawable/icon_timer_off"
|
android:src="@drawable/icon_timer_off"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/image_grid"
|
app:layout_constraintEnd_toStartOf="@id/image_close"
|
||||||
app:layout_constraintStart_toEndOf="@id/image_hdr"
|
app:layout_constraintStart_toEndOf="@id/image_ratio"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/image_grid"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:onClick="onClickGrid"
|
|
||||||
android:src="@drawable/icon_grid_off"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/image_close"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/image_timer"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@ -64,7 +47,7 @@
|
|||||||
android:src="@drawable/icon_close"
|
android:src="@drawable/icon_close"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/image_grid"
|
app:layout_constraintStart_toEndOf="@id/image_timer"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -162,10 +162,6 @@
|
|||||||
<string name="move_success_msg">The selected items have been successfully moved.</string>
|
<string name="move_success_msg">The selected items have been successfully moved.</string>
|
||||||
<string name="move_success">Move successful !</string>
|
<string name="move_success">Move successful !</string>
|
||||||
<string name="enter_timer_duration">Enter the timer duration (in s)</string>
|
<string name="enter_timer_duration">Enter the timer duration (in s)</string>
|
||||||
<string name="grid_none">None</string>
|
|
||||||
<string name="grid_3x3">3x3</string>
|
|
||||||
<string name="grid_4x4">4x4</string>
|
|
||||||
<string name="choose_grid">Choose grid</string>
|
|
||||||
<string name="timer_empty_error_msg">Please enter a numeric value</string>
|
<string name="timer_empty_error_msg">Please enter a numeric value</string>
|
||||||
<string name="path_from_uri_null_error_msg">Failed to retrieve the selected path.</string>
|
<string name="path_from_uri_null_error_msg">Failed to retrieve the selected path.</string>
|
||||||
<string name="create_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another location.</string>
|
<string name="create_cant_write_error_msg">DroidFS doesn\'t have write access to this path. Please try another location.</string>
|
||||||
@ -193,4 +189,6 @@
|
|||||||
<string name="hidden_volume">Hidden Volume</string>
|
<string name="hidden_volume">Hidden Volume</string>
|
||||||
<string name="error_slash_in_name">Volume name cannot contain slashes</string>
|
<string name="error_slash_in_name">Volume name cannot contain slashes</string>
|
||||||
<string name="hidden_volume_warning">Hidden volumes are stored in the app\'s internal storage. Other apps can\'t see these volumes without root access. However, if you uninstall DroidFS or clear data of the app, all your hidden volumes will be LOST. Be sure to make backups !</string>
|
<string name="hidden_volume_warning">Hidden volumes are stored in the app\'s internal storage. Other apps can\'t see these volumes without root access. However, if you uninstall DroidFS or clear data of the app, all your hidden volumes will be LOST. Be sure to make backups !</string>
|
||||||
|
<string name="camera_perm_needed">Camera permission is needed to take photo.</string>
|
||||||
|
<string name="choose_resolution">Choose a resolution</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -6,7 +6,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user