Migrate to viewBinding

This commit is contained in:
Matéo Duparc 2021-06-11 20:23:54 +02:00
parent 1719c192a8
commit 71d9447467
Signed by: hardcoresushi
GPG Key ID: 007F84120107191E
15 changed files with 265 additions and 207 deletions

View File

@ -1,6 +1,5 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 29 compileSdkVersion 29
@ -27,6 +26,10 @@ android {
variant.resValue "string", "versionName", variant.versionName variant.resValue "string", "versionName", variant.versionName
} }
buildFeatures {
viewBinding true
}
buildTypes { buildTypes {
release { release {
minifyEnabled true minifyEnabled true

View File

@ -26,9 +26,9 @@ import androidx.camera.core.*
import androidx.camera.extensions.HdrImageCaptureExtender import androidx.camera.extensions.HdrImageCaptureExtender
import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_camera.*
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.databinding.ActivityCameraBinding
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
@ -46,13 +46,14 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US) private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
private val random = Random() private val random = Random()
} }
private var timerDuration = 0 private var timerDuration = 0
set(value) { set(value) {
field = value field = value
if (value > 0){ if (value > 0){
image_timer.setImageResource(R.drawable.icon_timer_on) binding.imageTimer.setImageResource(R.drawable.icon_timer_on)
} else { } else {
image_timer.setImageResource(R.drawable.icon_timer_off) binding.imageTimer.setImageResource(R.drawable.icon_timer_off)
} }
} }
private var usf_keep_open = false private var usf_keep_open = false
@ -68,10 +69,13 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
private var resolutions: Array<Size>? = null private var resolutions: Array<Size>? = null
private var currentResolutionIndex: Int = 0 private var currentResolutionIndex: Int = 0
private var isBackCamera = true private var isBackCamera = true
private lateinit var binding: ActivityCameraBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
setContentView(R.layout.activity_camera) binding = ActivityCameraBinding.inflate(layoutInflater)
setContentView(binding.root)
gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1)) gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1))
outputDirectory = intent.getStringExtra("path")!! outputDirectory = intent.getStringExtra("path")!!
@ -87,7 +91,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
cameraExecutor = Executors.newSingleThreadExecutor() cameraExecutor = Executors.newSingleThreadExecutor()
image_ratio.setOnClickListener { binding.imageRatio.setOnClickListener {
resolutions?.let { resolutions?.let {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.setTitle(R.string.choose_resolution) .setTitle(R.string.choose_resolution)
@ -100,7 +104,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
.show() .show()
} }
} }
image_timer.setOnClickListener { binding.imageTimer.setOnClickListener {
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null) val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text) val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
dialogEditText.inputType = InputType.TYPE_CLASS_NUMBER dialogEditText.inputType = InputType.TYPE_CLASS_NUMBER
@ -125,12 +129,12 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
dialog.show() dialog.show()
} }
image_close.setOnClickListener { binding.imageClose.setOnClickListener {
isFinishingIntentionally = true isFinishingIntentionally = true
finish() finish()
} }
image_flash.setOnClickListener { binding.imageFlash.setOnClickListener {
image_flash.setImageResource(when (imageCapture?.flashMode) { binding.imageFlash.setImageResource(when (imageCapture?.flashMode) {
ImageCapture.FLASH_MODE_AUTO -> { ImageCapture.FLASH_MODE_AUTO -> {
imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON imageCapture?.flashMode = ImageCapture.FLASH_MODE_ON
R.drawable.icon_flash_on R.drawable.icon_flash_on
@ -145,18 +149,18 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
} }
}) })
} }
image_camera_switch.setOnClickListener { binding.imageCameraSwitch.setOnClickListener {
isBackCamera = if (isBackCamera) { isBackCamera = if (isBackCamera) {
image_camera_switch.setImageResource(R.drawable.icon_camera_front) binding.imageCameraSwitch.setImageResource(R.drawable.icon_camera_front)
false false
} else { } else {
image_camera_switch.setImageResource(R.drawable.icon_camera_back) binding.imageCameraSwitch.setImageResource(R.drawable.icon_camera_back)
true true
} }
setupCamera() setupCamera()
} }
take_photo_button.onClick = ::onClickTakePhoto binding.takePhotoButton.onClick = ::onClickTakePhoto
orientedIcons = listOf(image_ratio, image_timer, image_close, image_flash, image_camera_switch) orientedIcons = listOf(binding.imageRatio, binding.imageTimer, binding.imageClose, binding.imageFlash, binding.imageCameraSwitch)
sensorOrientationListener = SensorOrientationListener(this) sensorOrientationListener = SensorOrientationListener(this)
val scaleGestureDetector = ScaleGestureDetector(this, object : ScaleGestureDetector.SimpleOnScaleGestureListener(){ val scaleGestureDetector = ScaleGestureDetector(this, object : ScaleGestureDetector.SimpleOnScaleGestureListener(){
@ -166,12 +170,12 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
return true return true
} }
}) })
camera_preview.setOnTouchListener { view, event -> binding.cameraPreview.setOnTouchListener { view, event ->
view.performClick() view.performClick()
when (event.action) { when (event.action) {
MotionEvent.ACTION_DOWN -> true MotionEvent.ACTION_DOWN -> true
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
val factory = camera_preview.meteringPointFactory val factory = binding.cameraPreview.meteringPointFactory
val point = factory.createPoint(event.x, event.y) val point = factory.createPoint(event.x, event.y)
val action = FocusMeteringAction.Builder(point).build() val action = FocusMeteringAction.Builder(point).build()
imageCapture?.camera?.cameraControl?.startFocusAndMetering(action) imageCapture?.camera?.cameraControl?.startFocusAndMetering(action)
@ -209,7 +213,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
//resolution.width and resolution.height seem to be inverted //resolution.width and resolution.height seem to be inverted
val width = resolution.height val width = resolution.height
val height = resolution.width val height = resolution.width
camera_preview.layoutParams = if (metrics.widthPixels < width){ binding.cameraPreview.layoutParams = if (metrics.widthPixels < width){
RelativeLayout.LayoutParams( RelativeLayout.LayoutParams(
metrics.widthPixels, metrics.widthPixels,
(height * (metrics.widthPixels.toFloat() / width)).toInt() (height * (metrics.widthPixels.toFloat() / width)).toInt()
@ -217,7 +221,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
} else { } else {
RelativeLayout.LayoutParams(width, height) RelativeLayout.LayoutParams(width, height)
} }
(camera_preview.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.CENTER_IN_PARENT) (binding.cameraPreview.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.CENTER_IN_PARENT)
} }
private fun setupCamera(resolution: Size? = null){ private fun setupCamera(resolution: Size? = null){
@ -227,7 +231,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
val preview = Preview.Builder() val preview = Preview.Builder()
.build() .build()
.also { .also {
it.setSurfaceProvider(camera_preview.surfaceProvider) it.setSurfaceProvider(binding.cameraPreview.surfaceProvider)
} }
val builder = ImageCapture.Builder() val builder = ImageCapture.Builder()
.setFlashMode(ImageCapture.FLASH_MODE_AUTO) .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
@ -263,7 +267,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
val outputOptions = ImageCapture.OutputFileOptions.Builder(outputBuff).build() val outputOptions = ImageCapture.OutputFileOptions.Builder(outputBuff).build()
imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
take_photo_button.onPhotoTaken() binding.takePhotoButton.onPhotoTaken()
if (gocryptfsVolume.importFile(ByteArrayInputStream(outputBuff.toByteArray()), PathUtils.pathJoin(outputDirectory, fileName))){ if (gocryptfsVolume.importFile(ByteArrayInputStream(outputBuff.toByteArray()), PathUtils.pathJoin(outputDirectory, fileName))){
Toast.makeText(applicationContext, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show() Toast.makeText(applicationContext, getString(R.string.picture_save_success, fileName), Toast.LENGTH_SHORT).show()
} else { } else {
@ -279,7 +283,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
} }
} }
override fun onError(exception: ImageCaptureException) { override fun onError(exception: ImageCaptureException) {
take_photo_button.onPhotoTaken() binding.takePhotoButton.onPhotoTaken()
Toast.makeText(applicationContext, exception.message, Toast.LENGTH_SHORT).show() Toast.makeText(applicationContext, exception.message, Toast.LENGTH_SHORT).show()
} }
}) })
@ -291,15 +295,15 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+".jpg" fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+".jpg"
} while (gocryptfsVolume.pathExists(fileName)) } while (gocryptfsVolume.pathExists(fileName))
if (timerDuration > 0){ if (timerDuration > 0){
text_timer.visibility = View.VISIBLE binding.textTimer.visibility = View.VISIBLE
Thread{ Thread{
for (i in timerDuration downTo 1){ for (i in timerDuration downTo 1){
runOnUiThread { text_timer.text = i.toString() } runOnUiThread { binding.textTimer.text = i.toString() }
Thread.sleep(1000) Thread.sleep(1000)
} }
runOnUiThread { runOnUiThread {
takePhoto() takePhoto()
text_timer.visibility = View.GONE binding.textTimer.visibility = View.GONE
} }
}.start() }.start()
} else { } else {

View File

@ -8,10 +8,8 @@ import android.text.TextWatcher
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_change_password.*
import kotlinx.android.synthetic.main.checkboxes_section.*
import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
import sushi.hardcore.droidfs.databinding.ActivityChangePasswordBinding
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.util.WidgetUtil import sushi.hardcore.droidfs.util.WidgetUtil
import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.util.Wiper
@ -21,28 +19,31 @@ import java.util.*
class ChangePasswordActivity : VolumeActionActivity() { class ChangePasswordActivity : VolumeActionActivity() {
private lateinit var savedVolumesAdapter: SavedVolumesAdapter private lateinit var savedVolumesAdapter: SavedVolumesAdapter
private lateinit var binding: ActivityChangePasswordBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_change_password) binding = ActivityChangePasswordBinding.inflate(layoutInflater)
setContentView(binding.root)
setupLayout() setupLayout()
setupFingerprintStuff() setupFingerprintStuff()
savedVolumesAdapter = SavedVolumesAdapter(this, volumeDatabase) savedVolumesAdapter = SavedVolumesAdapter(this, volumeDatabase)
if (savedVolumesAdapter.count > 0){ if (savedVolumesAdapter.count > 0){
saved_path_listview.adapter = savedVolumesAdapter binding.savedPathListview.adapter = savedVolumesAdapter
saved_path_listview.onItemClickListener = OnItemClickListener { _, _, position, _ -> binding.savedPathListview.onItemClickListener = OnItemClickListener { _, _, position, _ ->
val volume = savedVolumesAdapter.getItem(position) val volume = savedVolumesAdapter.getItem(position)
currentVolumeName = volume.name currentVolumeName = volume.name
if (volume.isHidden){ if (volume.isHidden){
switch_hidden_volume.isChecked = true switchHiddenVolume.isChecked = true
edit_volume_name.setText(currentVolumeName) editVolumeName.setText(currentVolumeName)
} else { } else {
switch_hidden_volume.isChecked = false switchHiddenVolume.isChecked = false
edit_volume_path.setText(currentVolumeName) editVolumePath.setText(currentVolumeName)
} }
onClickSwitchHiddenVolume() onClickSwitchHiddenVolume()
} }
} else { } else {
WidgetUtil.hideWithPadding(saved_path_listview) WidgetUtil.hideWithPadding(binding.savedPathListview)
} }
val textWatcher = object: TextWatcher{ val textWatcher = object: TextWatcher{
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
@ -51,30 +52,34 @@ class ChangePasswordActivity : VolumeActionActivity() {
} }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (volumeDatabase.isVolumeSaved(s.toString())){ if (volumeDatabase.isVolumeSaved(s.toString())){
checkbox_remember_path.isEnabled = false checkboxRememberPath.isEnabled = false
checkbox_remember_path.isChecked = false checkboxRememberPath.isChecked = false
if (volumeDatabase.isHashSaved(s.toString())){ binding.editOldPassword.apply {
edit_old_password.text = null if (volumeDatabase.isHashSaved(s.toString())){
edit_old_password.hint = getString(R.string.hash_saved_hint) text = null
edit_old_password.isEnabled = false hint = getString(R.string.hash_saved_hint)
} else { isEnabled = false
edit_old_password.hint = null } else {
edit_old_password.isEnabled = true hint = null
isEnabled = true
}
} }
} else { } else {
checkbox_remember_path.isEnabled = true checkboxRememberPath.isEnabled = true
edit_old_password.hint = null binding.editOldPassword.apply {
edit_old_password.isEnabled = true hint = null
isEnabled = true
}
} }
} }
} }
edit_volume_path.addTextChangedListener(textWatcher) editVolumePath.addTextChangedListener(textWatcher)
edit_volume_name.addTextChangedListener(textWatcher) editVolumeName.addTextChangedListener(textWatcher)
edit_new_password_confirm.setOnEditorActionListener { _, _, _ -> binding.editNewPasswordConfirm.setOnEditorActionListener { _, _, _ ->
checkVolumePathThenChangePassword() checkVolumePathThenChangePassword()
true true
} }
button_change_password.setOnClickListener { binding.buttonChangePassword.setOnClickListener {
checkVolumePathThenChangePassword() checkVolumePathThenChangePassword()
} }
} }
@ -83,7 +88,7 @@ class ChangePasswordActivity : VolumeActionActivity() {
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){ if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
val path = PathUtils.getFullPathFromTreeUri(uri, this) val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null){ if (path != null){
edit_volume_path.setText(path) editVolumePath.setText(path)
} else { } else {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.setTitle(R.string.error) .setTitle(R.string.error)
@ -122,16 +127,16 @@ class ChangePasswordActivity : VolumeActionActivity() {
} }
private fun changePassword(givenHash: ByteArray? = null){ private fun changePassword(givenHash: ByteArray? = null){
val newPassword = edit_new_password.text.toString().toCharArray() val newPassword = binding.editNewPassword.text.toString().toCharArray()
val newPasswordConfirm = edit_new_password_confirm.text.toString().toCharArray() val newPasswordConfirm = binding.editNewPasswordConfirm.text.toString().toCharArray()
if (!newPassword.contentEquals(newPasswordConfirm)) { if (!newPassword.contentEquals(newPasswordConfirm)) {
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
} else { } else {
object : LoadingTask(this, R.string.loading_msg_change_password) { object : LoadingTask(this, R.string.loading_msg_change_password) {
override fun doTask(activity: AppCompatActivity) { override fun doTask(activity: AppCompatActivity) {
val oldPassword = edit_old_password.text.toString().toCharArray() val oldPassword = binding.editOldPassword.text.toString().toCharArray()
var returnedHash: ByteArray? = null var returnedHash: ByteArray? = null
if (checkbox_save_password.isChecked) { if (checkboxSavePassword.isChecked) {
returnedHash = ByteArray(GocryptfsVolume.KeyLen) returnedHash = ByteArray(GocryptfsVolume.KeyLen)
} }
var changePasswordImmediately = true var changePasswordImmediately = true
@ -162,14 +167,14 @@ class ChangePasswordActivity : VolumeActionActivity() {
} }
if (changePasswordImmediately) { if (changePasswordImmediately) {
if (GocryptfsVolume.changePassword(currentVolumePath, oldPassword, givenHash, newPassword, returnedHash)) { if (GocryptfsVolume.changePassword(currentVolumePath, oldPassword, givenHash, newPassword, returnedHash)) {
val volume = Volume(currentVolumeName, switch_hidden_volume.isChecked) val volume = Volume(currentVolumeName, switchHiddenVolume.isChecked)
if (volumeDatabase.isHashSaved(currentVolumeName)) { if (volumeDatabase.isHashSaved(currentVolumeName)) {
volumeDatabase.removeHash(volume) volumeDatabase.removeHash(volume)
} }
if (checkbox_remember_path.isChecked) { if (checkboxRememberPath.isChecked) {
volumeDatabase.saveVolume(volume) volumeDatabase.saveVolume(volume)
} }
if (checkbox_save_password.isChecked && returnedHash != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if (checkboxSavePassword.isChecked && returnedHash != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
stopTask { stopTask {
savePasswordHash(returnedHash) { savePasswordHash(returnedHash) {
onPasswordChanged() onPasswordChanged()
@ -209,8 +214,8 @@ class ChangePasswordActivity : VolumeActionActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
Wiper.wipeEditText(edit_old_password) Wiper.wipeEditText(binding.editOldPassword)
Wiper.wipeEditText(edit_new_password) Wiper.wipeEditText(binding.editNewPassword)
Wiper.wipeEditText(edit_new_password_confirm) Wiper.wipeEditText(binding.editNewPasswordConfirm)
} }
} }

View File

@ -6,9 +6,7 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_create.* import sushi.hardcore.droidfs.databinding.ActivityCreateBinding
import kotlinx.android.synthetic.main.checkboxes_section.*
import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.explorers.ExplorerActivity import sushi.hardcore.droidfs.explorers.ExplorerActivity
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.util.Wiper
@ -19,23 +17,26 @@ import java.util.*
class CreateActivity : VolumeActionActivity() { class CreateActivity : VolumeActionActivity() {
private var sessionID = -1 private var sessionID = -1
private var isStartingExplorer = false private var isStartingExplorer = false
private lateinit var binding: ActivityCreateBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create) binding = ActivityCreateBinding.inflate(layoutInflater)
setContentView(binding.root)
setupLayout() setupLayout()
setupFingerprintStuff() setupFingerprintStuff()
edit_password_confirm.setOnEditorActionListener { _, _, _ -> binding.editPasswordConfirm.setOnEditorActionListener { _, _, _ ->
createVolume() createVolume()
true true
} }
button_create.setOnClickListener { binding.buttonCreate.setOnClickListener {
createVolume() createVolume()
} }
} }
override fun onClickSwitchHiddenVolume() { override fun onClickSwitchHiddenVolume() {
super.onClickSwitchHiddenVolume() super.onClickSwitchHiddenVolume()
if (switch_hidden_volume.isChecked){ if (switchHiddenVolume.isChecked){
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.setTitle(R.string.warning) .setTitle(R.string.warning)
.setMessage(R.string.hidden_volume_warning) .setMessage(R.string.hidden_volume_warning)
@ -48,7 +49,7 @@ class CreateActivity : VolumeActionActivity() {
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){ if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
val path = PathUtils.getFullPathFromTreeUri(uri, this) val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null){ if (path != null){
edit_volume_path.setText(path) editVolumePath.setText(path)
} else { } else {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.setTitle(R.string.error) .setTitle(R.string.error)
@ -67,8 +68,8 @@ class CreateActivity : VolumeActionActivity() {
fun createVolume() { fun createVolume() {
loadVolumePath { loadVolumePath {
val password = edit_password.text.toString().toCharArray() val password = binding.editPassword.text.toString().toCharArray()
val passwordConfirm = edit_password_confirm.text.toString().toCharArray() val passwordConfirm = binding.editPasswordConfirm.text.toString().toCharArray()
if (!password.contentEquals(passwordConfirm)) { if (!password.contentEquals(passwordConfirm)) {
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
} else { } else {
@ -113,18 +114,18 @@ class CreateActivity : VolumeActionActivity() {
if (goodDirectory) { if (goodDirectory) {
if (GocryptfsVolume.createVolume(currentVolumePath, password, false, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) { if (GocryptfsVolume.createVolume(currentVolumePath, password, false, GocryptfsVolume.ScryptDefaultLogN, ConstValues.creator)) {
var returnedHash: ByteArray? = null var returnedHash: ByteArray? = null
if (checkbox_save_password.isChecked){ if (checkboxSavePassword.isChecked){
returnedHash = ByteArray(GocryptfsVolume.KeyLen) returnedHash = ByteArray(GocryptfsVolume.KeyLen)
} }
sessionID = GocryptfsVolume.init(currentVolumePath, password, null, returnedHash) sessionID = GocryptfsVolume.init(currentVolumePath, password, null, returnedHash)
if (sessionID != -1) { if (sessionID != -1) {
if (checkbox_remember_path.isChecked) { if (checkboxRememberPath.isChecked) {
if (volumeDatabase.isVolumeSaved(currentVolumeName)) { //cleaning old saved path if (volumeDatabase.isVolumeSaved(currentVolumeName)) { //cleaning old saved path
volumeDatabase.removeVolume(Volume(currentVolumeName)) volumeDatabase.removeVolume(Volume(currentVolumeName))
} }
volumeDatabase.saveVolume(Volume(currentVolumeName, switch_hidden_volume.isChecked)) volumeDatabase.saveVolume(Volume(currentVolumeName, switchHiddenVolume.isChecked))
} }
if (checkbox_save_password.isChecked && returnedHash != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if (checkboxSavePassword.isChecked && returnedHash != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
stopTask { stopTask {
savePasswordHash(returnedHash) { savePasswordHash(returnedHash) {
startExplorer() startExplorer()
@ -183,7 +184,7 @@ class CreateActivity : VolumeActionActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
Wiper.wipeEditText(edit_password) Wiper.wipeEditText(binding.editPassword)
Wiper.wipeEditText(edit_password_confirm) Wiper.wipeEditText(binding.editPasswordConfirm)
} }
} }

View File

@ -4,15 +4,16 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import kotlinx.android.synthetic.main.activity_main.* import sushi.hardcore.droidfs.databinding.ActivityMainBinding
import kotlinx.android.synthetic.main.toolbar.*
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
class MainActivity : BaseActivity() { class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) val binding = ActivityMainBinding.inflate(layoutInflater)
setSupportActionBar(toolbar) setContentView(binding.root)
setSupportActionBar(binding.toolbar.toolbar)
if (!isRecreating) { if (!isRecreating) {
if (sharedPrefs.getBoolean("applicationFirstOpening", true)){ if (sharedPrefs.getBoolean("applicationFirstOpening", true)){
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
@ -29,13 +30,13 @@ class MainActivity : BaseActivity() {
.show() .show()
} }
} }
button_open.setOnClickListener { binding.buttonOpen.setOnClickListener {
startActivity(OpenActivity::class.java) startActivity(OpenActivity::class.java)
} }
button_create.setOnClickListener { binding.buttonCreate.setOnClickListener {
startActivity(CreateActivity::class.java) startActivity(CreateActivity::class.java)
} }
button_change_password.setOnClickListener { binding.buttonChangePassword.setOnClickListener {
startActivity(ChangePasswordActivity::class.java) startActivity(ChangePasswordActivity::class.java)
} }
} }

View File

@ -9,11 +9,9 @@ import android.text.TextWatcher
import android.view.MenuItem import android.view.MenuItem
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_open.*
import kotlinx.android.synthetic.main.checkboxes_section.*
import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.databinding.ActivityOpenBinding
import sushi.hardcore.droidfs.explorers.ExplorerActivity import sushi.hardcore.droidfs.explorers.ExplorerActivity
import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop
import sushi.hardcore.droidfs.explorers.ExplorerActivityPick import sushi.hardcore.droidfs.explorers.ExplorerActivityPick
@ -29,24 +27,26 @@ class OpenActivity : VolumeActionActivity() {
private var sessionID = -1 private var sessionID = -1
private var isStartingActivity = false private var isStartingActivity = false
private var isFinishingIntentionally = false private var isFinishingIntentionally = false
private lateinit var binding: ActivityOpenBinding
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_open) binding = ActivityOpenBinding.inflate(layoutInflater)
setContentView(binding.root)
setupLayout() setupLayout()
setupFingerprintStuff() setupFingerprintStuff()
savedVolumesAdapter = SavedVolumesAdapter(this, volumeDatabase) savedVolumesAdapter = SavedVolumesAdapter(this, volumeDatabase)
if (savedVolumesAdapter.count > 0){ if (savedVolumesAdapter.count > 0){
saved_path_listview.adapter = savedVolumesAdapter binding.savedPathListview.adapter = savedVolumesAdapter
saved_path_listview.onItemClickListener = OnItemClickListener { _, _, position, _ -> binding.savedPathListview.onItemClickListener = OnItemClickListener { _, _, position, _ ->
val volume = savedVolumesAdapter.getItem(position) val volume = savedVolumesAdapter.getItem(position)
currentVolumeName = volume.name currentVolumeName = volume.name
if (volume.isHidden){ if (volume.isHidden){
switch_hidden_volume.isChecked = true switchHiddenVolume.isChecked = true
edit_volume_name.setText(currentVolumeName) editVolumeName.setText(currentVolumeName)
} else { } else {
switch_hidden_volume.isChecked = false switchHiddenVolume.isChecked = false
edit_volume_path.setText(currentVolumeName) editVolumePath.setText(currentVolumeName)
} }
onClickSwitchHiddenVolume() onClickSwitchHiddenVolume()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
@ -63,7 +63,7 @@ class OpenActivity : VolumeActionActivity() {
} }
} }
} else { } else {
WidgetUtil.hideWithPadding(saved_path_listview) WidgetUtil.hideWithPadding(binding.savedPathListview)
} }
val textWatcher = object: TextWatcher { val textWatcher = object: TextWatcher {
override fun afterTextChanged(s: Editable?) { override fun afterTextChanged(s: Editable?) {
@ -72,27 +72,27 @@ class OpenActivity : VolumeActionActivity() {
} }
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (volumeDatabase.isVolumeSaved(s.toString())){ if (volumeDatabase.isVolumeSaved(s.toString())){
checkbox_remember_path.isEnabled = false checkboxRememberPath.isEnabled = false
checkbox_remember_path.isChecked = false checkboxRememberPath.isChecked = false
if (volumeDatabase.isHashSaved(s.toString())){ if (volumeDatabase.isHashSaved(s.toString())){
checkbox_save_password.isEnabled = false checkboxSavePassword.isEnabled = false
checkbox_save_password.isChecked = false checkboxSavePassword.isChecked = false
} else { } else {
checkbox_save_password.isEnabled = true checkboxSavePassword.isEnabled = true
} }
} else { } else {
checkbox_remember_path.isEnabled = true checkboxRememberPath.isEnabled = true
checkbox_save_password.isEnabled = true checkboxSavePassword.isEnabled = true
} }
} }
} }
edit_volume_path.addTextChangedListener(textWatcher) editVolumePath.addTextChangedListener(textWatcher)
edit_volume_name.addTextChangedListener(textWatcher) editVolumeName.addTextChangedListener(textWatcher)
edit_password.setOnEditorActionListener { _, _, _ -> binding.editPassword.setOnEditorActionListener { _, _, _ ->
checkVolumePathThenOpen() checkVolumePathThenOpen()
true true
} }
button_open.setOnClickListener { binding.buttonOpen.setOnClickListener {
checkVolumePathThenOpen() checkVolumePathThenOpen()
} }
} }
@ -115,7 +115,7 @@ class OpenActivity : VolumeActionActivity() {
override fun onDirectoryPicked(uri: Uri) { override fun onDirectoryPicked(uri: Uri) {
val path = PathUtils.getFullPathFromTreeUri(uri, this) val path = PathUtils.getFullPathFromTreeUri(uri, this)
if (path != null){ if (path != null){
edit_volume_path.setText(path) editVolumePath.setText(path)
} else { } else {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.setTitle(R.string.error) .setTitle(R.string.error)
@ -162,17 +162,17 @@ class OpenActivity : VolumeActionActivity() {
private fun openVolume(){ private fun openVolume(){
object : LoadingTask(this, R.string.loading_msg_open){ object : LoadingTask(this, R.string.loading_msg_open){
override fun doTask(activity: AppCompatActivity) { override fun doTask(activity: AppCompatActivity) {
val password = edit_password.text.toString().toCharArray() val password = binding.editPassword.text.toString().toCharArray()
var returnedHash: ByteArray? = null var returnedHash: ByteArray? = null
if (checkbox_save_password.isChecked){ if (checkboxSavePassword.isChecked){
returnedHash = ByteArray(GocryptfsVolume.KeyLen) returnedHash = ByteArray(GocryptfsVolume.KeyLen)
} }
sessionID = GocryptfsVolume.init(currentVolumePath, password, null, returnedHash) sessionID = GocryptfsVolume.init(currentVolumePath, password, null, returnedHash)
if (sessionID != -1) { if (sessionID != -1) {
if (checkbox_remember_path.isChecked) { if (checkboxRememberPath.isChecked) {
volumeDatabase.saveVolume(Volume(currentVolumeName, switch_hidden_volume.isChecked)) volumeDatabase.saveVolume(Volume(currentVolumeName, switchHiddenVolume.isChecked))
} }
if (checkbox_save_password.isChecked && returnedHash != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){ if (checkboxSavePassword.isChecked && returnedHash != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
stopTask { stopTask {
savePasswordHash(returnedHash) { success -> savePasswordHash(returnedHash) { success ->
if (success){ if (success){
@ -261,7 +261,7 @@ class OpenActivity : VolumeActionActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
Wiper.wipeEditText(edit_password) Wiper.wipeEditText(binding.editPassword)
if (intent.action == "pick" && !isFinishingIntentionally){ if (intent.action == "pick" && !isFinishingIntentionally){
val sessionID = intent.getIntExtra("sessionID", -1) val sessionID = intent.getIntExtra("sessionID", -1)
if (sessionID != -1){ if (sessionID != -1){

View File

@ -6,7 +6,7 @@ import androidx.core.content.ContextCompat
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.jaredrummler.android.colorpicker.ColorPreferenceCompat import com.jaredrummler.android.colorpicker.ColorPreferenceCompat
import kotlinx.android.synthetic.main.toolbar.* import sushi.hardcore.droidfs.databinding.ActivitySettingsBinding
import sushi.hardcore.droidfs.widgets.SimpleActionPreference import sushi.hardcore.droidfs.widgets.SimpleActionPreference
import sushi.hardcore.droidfs.widgets.ThemeColor import sushi.hardcore.droidfs.widgets.ThemeColor
@ -14,8 +14,9 @@ class SettingsActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings) val binding = ActivitySettingsBinding.inflate(layoutInflater)
setSupportActionBar(toolbar) setContentView(binding.root)
setSupportActionBar(binding.toolbar.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
val screen = intent.extras?.getString("screen") ?: "main" val screen = intent.extras?.getString("screen") ?: "main"
val fragment = if (screen == "UnsafeFeaturesSettingsFragment") { val fragment = if (screen == "UnsafeFeaturesSettingsFragment") {

View File

@ -10,24 +10,31 @@ import android.os.Build
import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyPermanentlyInvalidatedException import android.security.keystore.KeyPermanentlyInvalidatedException
import android.security.keystore.KeyProperties import android.security.keystore.KeyProperties
import android.widget.LinearLayout import android.widget.*
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.widget.SwitchCompat
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.checkboxes_section.*
import kotlinx.android.synthetic.main.toolbar.*
import kotlinx.android.synthetic.main.volume_path_section.*
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.util.WidgetUtil import sushi.hardcore.droidfs.util.WidgetUtil
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import sushi.hardcore.droidfs.widgets.ColoredImageButton
import java.security.KeyStore import java.security.KeyStore
import javax.crypto.* import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec import javax.crypto.spec.GCMParameterSpec
abstract class VolumeActionActivity : BaseActivity() { abstract class VolumeActionActivity : BaseActivity() {
companion object {
private const val STORAGE_PERMISSIONS_REQUEST = 0
private const val ANDROID_KEY_STORE = "AndroidKeyStore"
private const val KEY_ALIAS = "Hash Key"
private const val KEY_SIZE = 256
private const val GCM_TAG_LEN = 128
}
protected lateinit var currentVolumeName: String protected lateinit var currentVolumeName: String
protected lateinit var currentVolumePath: String protected lateinit var currentVolumePath: String
protected lateinit var volumeDatabase: VolumeDatabase protected lateinit var volumeDatabase: VolumeDatabase
@ -50,18 +57,18 @@ abstract class VolumeActionActivity : BaseActivity() {
private lateinit var dataToProcess: ByteArray private lateinit var dataToProcess: ByteArray
private lateinit var originalHiddenVolumeSectionLayoutParams: LinearLayout.LayoutParams private lateinit var originalHiddenVolumeSectionLayoutParams: LinearLayout.LayoutParams
private lateinit var originalNormalVolumeSectionLayoutParams: LinearLayout.LayoutParams private lateinit var originalNormalVolumeSectionLayoutParams: LinearLayout.LayoutParams
companion object { protected lateinit var switchHiddenVolume: SwitchCompat
private const val STORAGE_PERMISSIONS_REQUEST = 0 protected lateinit var checkboxRememberPath: CheckBox
private const val ANDROID_KEY_STORE = "AndroidKeyStore" protected lateinit var checkboxSavePassword: CheckBox
private const val KEY_ALIAS = "Hash Key" protected lateinit var editVolumeName: EditText
private const val KEY_SIZE = 256 protected lateinit var editVolumePath: EditText
private const val GCM_TAG_LEN = 128 private lateinit var hiddenVolumeSection: LinearLayout
} private lateinit var normalVolumeSection: LinearLayout
protected fun setupLayout() { protected fun setupLayout() {
setSupportActionBar(toolbar) setSupportActionBar(findViewById(R.id.toolbar))
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
button_pick_directory.setOnClickListener { findViewById<ColoredImageButton>(R.id.button_pick_directory).setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) + if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) +
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
@ -73,20 +80,27 @@ abstract class VolumeActionActivity : BaseActivity() {
safePickDirectory() safePickDirectory()
} }
} }
switch_hidden_volume.setOnClickListener { switchHiddenVolume = findViewById(R.id.switch_hidden_volume)
checkboxRememberPath = findViewById(R.id.checkbox_remember_path)
checkboxSavePassword = findViewById(R.id.checkbox_save_password)
editVolumeName = findViewById(R.id.edit_volume_name)
editVolumePath = findViewById(R.id.edit_volume_path)
hiddenVolumeSection = findViewById(R.id.hidden_volume_section)
normalVolumeSection = findViewById(R.id.normal_volume_section)
switchHiddenVolume.setOnClickListener {
onClickSwitchHiddenVolume() onClickSwitchHiddenVolume()
} }
checkbox_remember_path.setOnClickListener { checkboxRememberPath.setOnClickListener {
if (!checkbox_remember_path.isChecked) { if (!checkboxRememberPath.isChecked) {
checkbox_save_password.isChecked = false checkboxSavePassword.isChecked = false
} }
} }
checkbox_save_password.setOnClickListener { checkboxSavePassword.setOnClickListener {
if (checkbox_save_password.isChecked) { if (checkboxSavePassword.isChecked) {
if (biometricCanAuthenticateCode == 0) { if (biometricCanAuthenticateCode == 0) {
checkbox_remember_path.isChecked = checkbox_remember_path.isEnabled checkboxRememberPath.isChecked = checkboxRememberPath.isEnabled
} else { } else {
checkbox_save_password.isChecked = false checkboxSavePassword.isChecked = false
printAuthenticateImpossibleError() printAuthenticateImpossibleError()
} }
} }
@ -94,12 +108,12 @@ abstract class VolumeActionActivity : BaseActivity() {
} }
protected open fun onClickSwitchHiddenVolume() { protected open fun onClickSwitchHiddenVolume() {
if (switch_hidden_volume.isChecked){ if (switchHiddenVolume.isChecked){
WidgetUtil.show(hidden_volume_section, originalHiddenVolumeSectionLayoutParams) WidgetUtil.show(hiddenVolumeSection, originalHiddenVolumeSectionLayoutParams)
WidgetUtil.hide(normal_volume_section) WidgetUtil.hide(normalVolumeSection)
} else { } else {
WidgetUtil.show(normal_volume_section, originalNormalVolumeSectionLayoutParams) WidgetUtil.show(normalVolumeSection, originalNormalVolumeSectionLayoutParams)
WidgetUtil.hide(hidden_volume_section) WidgetUtil.hide(hiddenVolumeSection)
} }
} }
@ -138,9 +152,9 @@ abstract class VolumeActionActivity : BaseActivity() {
} }
protected fun setupFingerprintStuff(){ protected fun setupFingerprintStuff(){
originalHiddenVolumeSectionLayoutParams = hidden_volume_section.layoutParams as LinearLayout.LayoutParams originalHiddenVolumeSectionLayoutParams = hiddenVolumeSection.layoutParams as LinearLayout.LayoutParams
originalNormalVolumeSectionLayoutParams = normal_volume_section.layoutParams as LinearLayout.LayoutParams originalNormalVolumeSectionLayoutParams = normalVolumeSection.layoutParams as LinearLayout.LayoutParams
WidgetUtil.hide(hidden_volume_section) WidgetUtil.hide(hiddenVolumeSection)
volumeDatabase = VolumeDatabase(this) volumeDatabase = VolumeDatabase(this)
usf_fingerprint = sharedPrefs.getBoolean("usf_fingerprint", false) usf_fingerprint = sharedPrefs.getBoolean("usf_fingerprint", false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && usf_fingerprint) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && usf_fingerprint) {
@ -173,7 +187,7 @@ abstract class VolumeActionActivity : BaseActivity() {
when (actionMode) { when (actionMode) {
Cipher.ENCRYPT_MODE -> { Cipher.ENCRYPT_MODE -> {
val cipherText = cipherObject.doFinal(dataToProcess) val cipherText = cipherObject.doFinal(dataToProcess)
success = volumeDatabase.addHash(Volume(currentVolumeName, switch_hidden_volume.isChecked, cipherText, cipherObject.iv)) success = volumeDatabase.addHash(Volume(currentVolumeName, switchHiddenVolume.isChecked, cipherText, cipherObject.iv))
} }
Cipher.DECRYPT_MODE -> { Cipher.DECRYPT_MODE -> {
try { try {
@ -212,7 +226,7 @@ abstract class VolumeActionActivity : BaseActivity() {
biometricPrompt = BiometricPrompt(this, executor, callback) biometricPrompt = BiometricPrompt(this, executor, callback)
} }
} else { } else {
WidgetUtil.hideWithPadding(checkbox_save_password) WidgetUtil.hideWithPadding(checkboxSavePassword)
} }
} }
@ -334,17 +348,17 @@ abstract class VolumeActionActivity : BaseActivity() {
} }
protected fun loadVolumePath(callback: () -> Unit){ protected fun loadVolumePath(callback: () -> Unit){
currentVolumeName = if (switch_hidden_volume.isChecked){ currentVolumeName = if (switchHiddenVolume.isChecked){
edit_volume_name.text.toString() editVolumeName.text.toString()
} else { } else {
edit_volume_path.text.toString() editVolumePath.text.toString()
} }
if (currentVolumeName.isEmpty()) { if (currentVolumeName.isEmpty()) {
Toast.makeText(this, if (switch_hidden_volume.isChecked) {R.string.enter_volume_name} else {R.string.enter_volume_path}, Toast.LENGTH_SHORT).show() Toast.makeText(this, if (switchHiddenVolume.isChecked) {R.string.enter_volume_name} else {R.string.enter_volume_path}, Toast.LENGTH_SHORT).show()
} else if (switch_hidden_volume.isChecked && currentVolumeName.contains("/")){ } else if (switchHiddenVolume.isChecked && currentVolumeName.contains("/")){
Toast.makeText(this, R.string.error_slash_in_name, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.error_slash_in_name, Toast.LENGTH_SHORT).show()
} else { } else {
currentVolumePath = if (switch_hidden_volume.isChecked) { currentVolumePath = if (switchHiddenVolume.isChecked) {
PathUtils.pathJoin(filesDir.path, currentVolumeName) PathUtils.pathJoin(filesDir.path, currentVolumeName)
} else { } else {
currentVolumeName currentVolumeName

View File

@ -14,12 +14,12 @@ import android.view.WindowManager
import android.widget.AdapterView.OnItemClickListener import android.widget.AdapterView.OnItemClickListener
import android.widget.AdapterView.OnItemLongClickListener import android.widget.AdapterView.OnItemLongClickListener
import android.widget.EditText import android.widget.EditText
import android.widget.ListView
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.activity_explorer_base.* import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import kotlinx.android.synthetic.main.explorer_info_bar.*
import kotlinx.android.synthetic.main.toolbar.*
import sushi.hardcore.droidfs.BaseActivity import sushi.hardcore.droidfs.BaseActivity
import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.ConstValues.Companion.isAudio import sushi.hardcore.droidfs.ConstValues.Companion.isAudio
@ -62,6 +62,14 @@ open class BaseExplorerActivity : BaseActivity() {
protected var isStartingActivity = false protected var isStartingActivity = false
private var usf_open = false private var usf_open = false
protected var usf_keep_open = false protected var usf_keep_open = false
private lateinit var toolbar: androidx.appcompat.widget.Toolbar
private lateinit var titleText: TextView
private lateinit var listExplorer: ListView
private lateinit var refresher: SwipeRefreshLayout
private lateinit var textDirEmpty: TextView
private lateinit var currentPathText: TextView
private lateinit var totalSizeText: TextView
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
usf_open = sharedPrefs.getBoolean("usf_open", false) usf_open = sharedPrefs.getBoolean("usf_open", false)
@ -74,16 +82,25 @@ open class BaseExplorerActivity : BaseActivity() {
foldersFirst = sharedPrefs.getBoolean("folders_first", true) foldersFirst = sharedPrefs.getBoolean("folders_first", true)
currentSortOrderIndex = resources.getStringArray(R.array.sort_orders_values).indexOf(sharedPrefs.getString(ConstValues.sort_order_key, "name")) currentSortOrderIndex = resources.getStringArray(R.array.sort_orders_values).indexOf(sharedPrefs.getString(ConstValues.sort_order_key, "name"))
init() init()
toolbar = findViewById(R.id.toolbar)
titleText = findViewById(R.id.title_text)
listExplorer = findViewById(R.id.list_explorer)
refresher = findViewById(R.id.refresher)
textDirEmpty = findViewById(R.id.text_dir_empty)
currentPathText = findViewById(R.id.current_path_text)
totalSizeText = findViewById(R.id.total_size_text)
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
title = "" title = ""
title_text.text = getString(R.string.volume, volumeName) titleText.text = getString(R.string.volume, volumeName)
explorerAdapter = ExplorerElementAdapter(this) explorerAdapter = ExplorerElementAdapter(this)
explorerViewModel= ViewModelProvider(this).get(ExplorerViewModel::class.java) explorerViewModel= ViewModelProvider(this).get(ExplorerViewModel::class.java)
currentDirectoryPath = explorerViewModel.currentDirectoryPath currentDirectoryPath = explorerViewModel.currentDirectoryPath
setCurrentPath(currentDirectoryPath) setCurrentPath(currentDirectoryPath)
list_explorer.adapter = explorerAdapter listExplorer.apply {
list_explorer.onItemClickListener = OnItemClickListener { _, _, position, _ -> onExplorerItemClick(position) } adapter = explorerAdapter
list_explorer.onItemLongClickListener = OnItemLongClickListener { _, _, position, _ -> onExplorerItemLongClick(position); true } onItemClickListener = OnItemClickListener { _, _, position, _ -> onExplorerItemClick(position) }
onItemLongClickListener = OnItemLongClickListener { _, _, position, _ -> onExplorerItemLongClick(position); true }
}
refresher.setOnRefreshListener { refresher.setOnRefreshListener {
setCurrentPath(currentDirectoryPath) setCurrentPath(currentDirectoryPath)
refresher.isRefreshing = false refresher.isRefreshing = false
@ -198,14 +215,14 @@ open class BaseExplorerActivity : BaseActivity() {
protected fun setCurrentPath(path: String) { protected fun setCurrentPath(path: String) {
explorerElements = gocryptfsVolume.listDir(path) explorerElements = gocryptfsVolume.listDir(path)
text_dir_empty.visibility = if (explorerElements.size == 0) View.VISIBLE else View.INVISIBLE textDirEmpty.visibility = if (explorerElements.size == 0) View.VISIBLE else View.INVISIBLE
sortExplorerElements() sortExplorerElements()
if (path.isNotEmpty()) { //not root if (path.isNotEmpty()) { //not root
explorerElements.add(0, ExplorerElement("..", (-1).toShort(), -1, -1, currentDirectoryPath)) explorerElements.add(0, ExplorerElement("..", (-1).toShort(), -1, -1, currentDirectoryPath))
} }
explorerAdapter.setExplorerElements(explorerElements) explorerAdapter.setExplorerElements(explorerElements)
currentDirectoryPath = path currentDirectoryPath = path
current_path_text.text = getString(R.string.location, currentDirectoryPath) currentPathText.text = getString(R.string.location, currentDirectoryPath)
Thread{ Thread{
var totalSize: Long = 0 var totalSize: Long = 0
for (element in explorerElements){ for (element in explorerElements){
@ -223,7 +240,7 @@ open class BaseExplorerActivity : BaseActivity() {
} }
} }
runOnUiThread { runOnUiThread {
total_size_text.text = getString(R.string.total_size, PathUtils.formatSize(totalSize)) totalSizeText.text = getString(R.string.total_size, PathUtils.formatSize(totalSize))
explorerAdapter.notifyDataSetChanged() explorerAdapter.notifyDataSetChanged()
} }
}.start() }.start()

View File

@ -8,13 +8,13 @@ import android.view.WindowManager
import android.widget.EditText import android.widget.EditText
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import kotlinx.android.synthetic.main.activity_explorer.*
import sushi.hardcore.droidfs.CameraActivity import sushi.hardcore.droidfs.CameraActivity
import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.OpenActivity import sushi.hardcore.droidfs.OpenActivity
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
import sushi.hardcore.droidfs.content_providers.ExternalProvider import sushi.hardcore.droidfs.content_providers.ExternalProvider
import sushi.hardcore.droidfs.databinding.ActivityExplorerBinding
import sushi.hardcore.droidfs.file_operations.OperationFile import sushi.hardcore.droidfs.file_operations.OperationFile
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
@ -24,10 +24,12 @@ class ExplorerActivity : BaseExplorerActivity() {
companion object { companion object {
private enum class ItemsActions {NONE, COPY, MOVE} private enum class ItemsActions {NONE, COPY, MOVE}
} }
private var usf_decrypt = false private var usf_decrypt = false
private var usf_share = false private var usf_share = false
private var currentItemAction = ItemsActions.NONE private var currentItemAction = ItemsActions.NONE
private val itemsToProcess = ArrayList<OperationFile>() private val itemsToProcess = ArrayList<OperationFile>()
private lateinit var binding: ActivityExplorerBinding
private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) { if (result.resultCode == Activity.RESULT_OK) {
result.data?.let { resultIntent -> result.data?.let { resultIntent ->
@ -145,8 +147,9 @@ class ExplorerActivity : BaseExplorerActivity() {
} }
override fun init() { override fun init() {
setContentView(R.layout.activity_explorer) binding = ActivityExplorerBinding.inflate(layoutInflater)
fab.setOnClickListener { setContentView(binding.root)
binding.fab.setOnClickListener {
if (currentItemAction != ItemsActions.NONE){ if (currentItemAction != ItemsActions.NONE){
openDialogCreateFolder() openDialogCreateFolder()
} else { } else {

View File

@ -4,14 +4,17 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import kotlinx.android.synthetic.main.activity_explorer_drop.*
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.databinding.ActivityExplorerDropBinding
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
class ExplorerActivityDrop : BaseExplorerActivity() { class ExplorerActivityDrop : BaseExplorerActivity() {
private lateinit var binding: ActivityExplorerDropBinding
override fun init() { override fun init() {
setContentView(R.layout.activity_explorer_drop) binding = ActivityExplorerDropBinding.inflate(layoutInflater)
fab.setOnClickListener { setContentView(binding.root)
binding.fab.setOnClickListener {
openDialogCreateFolder() openDialogCreateFolder()
} }
} }

View File

@ -1,13 +1,15 @@
package sushi.hardcore.droidfs.file_viewers package sushi.hardcore.droidfs.file_viewers
import com.google.android.exoplayer2.SimpleExoPlayer import com.google.android.exoplayer2.SimpleExoPlayer
import kotlinx.android.synthetic.main.activity_audio_player.* import sushi.hardcore.droidfs.databinding.ActivityAudioPlayerBinding
import sushi.hardcore.droidfs.R
import java.io.File import java.io.File
class AudioPlayer: MediaPlayer(){ class AudioPlayer: MediaPlayer(){
private lateinit var binding: ActivityAudioPlayerBinding
override fun viewFile() { override fun viewFile() {
setContentView(R.layout.activity_audio_player) binding = ActivityAudioPlayerBinding.inflate(layoutInflater)
setContentView(binding.root)
super.viewFile() super.viewFile()
refreshFileName() refreshFileName()
} }
@ -17,7 +19,7 @@ class AudioPlayer: MediaPlayer(){
} }
override fun bindPlayer(player: SimpleExoPlayer) { override fun bindPlayer(player: SimpleExoPlayer) {
audio_controller.player = player binding.audioController.player = player
} }
override fun onPlaylistIndexChanged() { override fun onPlaylistIndexChanged() {
@ -27,7 +29,7 @@ class AudioPlayer: MediaPlayer(){
private fun refreshFileName() { private fun refreshFileName() {
val filename = File(filePath).name val filename = File(filePath).name
val pos = filename.lastIndexOf('.') val pos = filename.lastIndexOf('.')
music_title.text = if (pos != -1){ binding.musicTitle.text = if (pos != -1){
filename.substring(0,pos) filename.substring(0,pos)
} else { } else {
filename filename

View File

@ -13,9 +13,9 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.RequestBuilder import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
import kotlinx.android.synthetic.main.activity_image_viewer.*
import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.databinding.ActivityImageViewerBinding
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import sushi.hardcore.droidfs.widgets.ZoomableImageView import sushi.hardcore.droidfs.widgets.ZoomableImageView
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@ -29,6 +29,7 @@ class ImageViewer: FileViewerActivity() {
private const val hideDelay: Long = 3000 private const val hideDelay: Long = 3000
private const val MIN_SWIPE_DISTANCE = 150 private const val MIN_SWIPE_DISTANCE = 150
} }
private lateinit var fileName: String private lateinit var fileName: String
private lateinit var glideImage: RequestBuilder<Drawable> private lateinit var glideImage: RequestBuilder<Drawable>
private var x1 = 0F private var x1 = 0F
@ -38,28 +39,30 @@ class ImageViewer: FileViewerActivity() {
private var rotatedBitmap: Bitmap? = null private var rotatedBitmap: Bitmap? = null
private val handler = Handler() private val handler = Handler()
private val hideUI = Runnable { private val hideUI = Runnable {
action_buttons.visibility = View.GONE binding.actionButtons.visibility = View.GONE
action_bar.visibility = View.GONE binding.actionBar.visibility = View.GONE
} }
private val slideshowNext = Runnable { private val slideshowNext = Runnable {
if (slideshowActive){ if (slideshowActive){
image_viewer.resetZoomFactor() binding.imageViewer.resetZoomFactor()
swipeImage(-1F, true) swipeImage(-1F, true)
} }
} }
private lateinit var binding: ActivityImageViewerBinding
override fun getFileType(): String { override fun getFileType(): String {
return "image" return "image"
} }
override fun viewFile() { override fun viewFile() {
setContentView(R.layout.activity_image_viewer) binding = ActivityImageViewerBinding.inflate(layoutInflater)
image_viewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener { setContentView(binding.root)
binding.imageViewer.setOnInteractionListener(object : ZoomableImageView.OnInteractionListener {
override fun onSingleTap(event: MotionEvent?) { override fun onSingleTap(event: MotionEvent?) {
handler.removeCallbacks(hideUI) handler.removeCallbacks(hideUI)
if (action_buttons.visibility == View.GONE) { if (binding.actionButtons.visibility == View.GONE) {
action_buttons.visibility = View.VISIBLE binding.actionButtons.visibility = View.VISIBLE
action_bar.visibility = View.VISIBLE binding.actionBar.visibility = View.VISIBLE
handler.postDelayed(hideUI, hideDelay) handler.postDelayed(hideUI, hideDelay)
} else { } else {
hideUI.run() hideUI.run()
@ -67,7 +70,7 @@ class ImageViewer: FileViewerActivity() {
} }
override fun onTouch(event: MotionEvent?) { override fun onTouch(event: MotionEvent?) {
if (!image_viewer.isZoomed) { if (!binding.imageViewer.isZoomed) {
when (event?.action) { when (event?.action) {
MotionEvent.ACTION_DOWN -> { MotionEvent.ACTION_DOWN -> {
x1 = event.x x1 = event.x
@ -83,7 +86,7 @@ class ImageViewer: FileViewerActivity() {
} }
} }
}) })
image_delete.setOnClickListener { binding.imageDelete.setOnClickListener {
ColoredAlertDialogBuilder(this) ColoredAlertDialogBuilder(this)
.keepFullScreen() .keepFullScreen()
.setTitle(R.string.warning) .setTitle(R.string.warning)
@ -110,7 +113,7 @@ class ImageViewer: FileViewerActivity() {
.setMessage(getString(R.string.single_delete_confirm, fileName)) .setMessage(getString(R.string.single_delete_confirm, fileName))
.show() .show()
} }
image_button_slideshow.setOnClickListener { binding.imageButtonSlideshow.setOnClickListener {
if (!slideshowActive){ if (!slideshowActive){
slideshowActive = true slideshowActive = true
handler.postDelayed(slideshowNext, ConstValues.slideshow_delay) handler.postDelayed(slideshowNext, ConstValues.slideshow_delay)
@ -121,23 +124,23 @@ class ImageViewer: FileViewerActivity() {
stopSlideshow() stopSlideshow()
} }
} }
image_previous.setOnClickListener { binding.imagePrevious.setOnClickListener {
askSaveRotation { askSaveRotation {
image_viewer.resetZoomFactor() binding.imageViewer.resetZoomFactor()
swipeImage(1F) swipeImage(1F)
} }
} }
image_next.setOnClickListener { binding.imageNext.setOnClickListener {
askSaveRotation { askSaveRotation {
image_viewer.resetZoomFactor() binding.imageViewer.resetZoomFactor()
swipeImage(-1F) swipeImage(-1F)
} }
} }
image_rotate_right.setOnClickListener { binding.imageRotateRight.setOnClickListener {
rotationAngle += 90 rotationAngle += 90
rotateImage() rotateImage()
} }
image_rotate_left.setOnClickListener { binding.imageRotateLeft.setOnClickListener {
rotationAngle -= 90 rotationAngle -= 90
rotateImage() rotateImage()
} }
@ -148,9 +151,9 @@ class ImageViewer: FileViewerActivity() {
private fun loadImage(){ private fun loadImage(){
loadWholeFile(filePath)?.let { loadWholeFile(filePath)?.let {
glideImage = Glide.with(this).load(it) glideImage = Glide.with(this).load(it)
glideImage.into(image_viewer) glideImage.into(binding.imageViewer)
fileName = File(filePath).name fileName = File(filePath).name
text_filename.text = fileName binding.textFilename.text = fileName
rotationAngle = 0F rotationAngle = 0F
} }
} }
@ -201,8 +204,8 @@ class ImageViewer: FileViewerActivity() {
} }
private fun rotateImage(){ private fun rotateImage(){
image_viewer.restoreZoomNormal() binding.imageViewer.restoreZoomNormal()
glideImage.transform(RotateTransformation(this)).into(image_viewer) glideImage.transform(RotateTransformation(this)).into(binding.imageViewer)
} }
private fun askSaveRotation(callback: () -> Unit){ private fun askSaveRotation(callback: () -> Unit){
@ -250,6 +253,6 @@ class ImageViewer: FileViewerActivity() {
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)
image_viewer.restoreZoomNormal() binding.imageViewer.restoreZoomNormal()
} }
} }

View File

@ -2,22 +2,23 @@ package sushi.hardcore.droidfs.file_viewers
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import com.google.android.exoplayer2.SimpleExoPlayer import com.google.android.exoplayer2.SimpleExoPlayer
import kotlinx.android.synthetic.main.activity_video_player.* import sushi.hardcore.droidfs.databinding.ActivityVideoPlayerBinding
import sushi.hardcore.droidfs.R
class VideoPlayer: MediaPlayer() { class VideoPlayer: MediaPlayer() {
private var firstPlay = true private var firstPlay = true
private val autoFit by lazy { private val autoFit by lazy {
sharedPrefs.getBoolean("autoFit", false) sharedPrefs.getBoolean("autoFit", false)
} }
private lateinit var binding: ActivityVideoPlayerBinding
override fun viewFile() { override fun viewFile() {
setContentView(R.layout.activity_video_player) binding = ActivityVideoPlayerBinding.inflate(layoutInflater)
setContentView(binding.root)
super.viewFile() super.viewFile()
} }
override fun bindPlayer(player: SimpleExoPlayer) { override fun bindPlayer(player: SimpleExoPlayer) {
video_player.player = player binding.videoPlayer.player = player
} }
override fun getFileType(): String { override fun getFileType(): String {
@ -26,7 +27,7 @@ class VideoPlayer: MediaPlayer() {
override fun onPlayerReady() { override fun onPlayerReady() {
if (firstPlay && autoFit) { if (firstPlay && autoFit) {
requestedOrientation = if (video_player.width < video_player.height) ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE requestedOrientation = if (binding.videoPlayer.width < binding.videoPlayer.height) ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
firstPlay = false firstPlay = false
} }
} }

View File

@ -7,7 +7,7 @@
android:orientation="vertical" android:orientation="vertical"
tools:context="sushi.hardcore.droidfs.MainActivity"> tools:context="sushi.hardcore.droidfs.MainActivity">
<include layout="@layout/toolbar"/> <include android:id="@+id/toolbar" layout="@layout/toolbar"/>
<sushi.hardcore.droidfs.widgets.ColoredImageView <sushi.hardcore.droidfs.widgets.ColoredImageView
android:id="@+id/image_logo" android:id="@+id/image_logo"