From 1a1d3ea570781ed12472bb7378bf4b93e26b78f6 Mon Sep 17 00:00:00 2001 From: Hardcore Sushi Date: Tue, 7 Mar 2023 23:25:17 +0100 Subject: [PATCH] Multi volume openings --- app/build.gradle | 6 +- app/src/main/AndroidManifest.xml | 3 +- .../sushi/hardcore/droidfs/BaseActivity.kt | 3 +- .../sushi/hardcore/droidfs/CameraActivity.kt | 48 ++------ .../sushi/hardcore/droidfs/MainActivity.kt | 86 ++++++++------ .../java/sushi/hardcore/droidfs/VolumeData.kt | 11 ++ .../sushi/hardcore/droidfs/VolumeManager.kt | 42 +++++++ .../hardcore/droidfs/VolumeManagerApp.kt | 49 ++++++++ .../sushi/hardcore/droidfs/VolumeOpener.kt | 94 ++++++++------- .../droidfs/adapters/VolumeAdapter.kt | 11 +- .../droidfs/add_volume/AddVolumeActivity.kt | 32 +---- .../add_volume/CreateVolumeFragment.kt | 21 ++-- .../droidfs/add_volume/SelectPathFragment.kt | 7 +- .../RestrictedFileProvider.kt | 2 +- .../droidfs/explorers/BaseExplorerActivity.kt | 110 +++++++----------- .../droidfs/explorers/ExplorerActivity.kt | 38 +++--- .../droidfs/explorers/ExplorerActivityPick.kt | 38 ++---- .../droidfs/explorers/ExplorerRouter.kt | 6 +- .../file_viewers/FileViewerActivity.kt | 25 +--- .../droidfs/file_viewers/TextEditor.kt | 8 +- .../droidfs/filesystems/CryfsVolume.kt | 8 +- .../droidfs/filesystems/GocryptfsVolume.kt | 33 +++--- app/src/main/native/gocryptfs_jni.c | 46 ++++---- app/src/main/res/drawable/icon_decrypt.xml | 4 - app/src/main/res/drawable/icon_lock.xml | 5 + app/src/main/res/drawable/icon_lock_open.xml | 5 + app/src/main/res/layout/adapter_volume.xml | 45 ++++--- app/src/main/res/menu/explorer.xml | 9 +- app/src/main/res/menu/explorer_drop.xml | 6 + app/src/main/res/menu/explorer_pick.xml | 6 + app/src/main/res/menu/main_activity.xml | 7 ++ app/src/main/res/values-ar/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values/strings.xml | 5 +- .../res/xml/unsafe_features_preferences.xml | 4 +- build.gradle | 2 +- 38 files changed, 436 insertions(+), 393 deletions(-) create mode 100644 app/src/main/java/sushi/hardcore/droidfs/VolumeManager.kt create mode 100644 app/src/main/java/sushi/hardcore/droidfs/VolumeManagerApp.kt delete mode 100644 app/src/main/res/drawable/icon_decrypt.xml create mode 100644 app/src/main/res/drawable/icon_lock.xml create mode 100644 app/src/main/res/drawable/icon_lock_open.xml diff --git a/app/build.gradle b/app/build.gradle index 967a430..c07640c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -88,9 +88,11 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation 'androidx.core:core-ktx:1.9.0' - implementation "androidx.appcompat:appcompat:1.6.0" + implementation "androidx.appcompat:appcompat:1.6.1" implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" + def lifecycle_version = "2.5.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" implementation "androidx.sqlite:sqlite-ktx:2.3.0" implementation "androidx.preference:preference-ktx:1.2.0" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef92d1b..d865cae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,7 +30,8 @@ android:label="@string/app_name" android:requestLegacyExternalStorage="true" android:supportsRtl="true" - android:theme="@style/BaseTheme"> + android:theme="@style/BaseTheme" + android:name=".VolumeManagerApp"> diff --git a/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt index 0d3b94b..760f4d4 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt @@ -4,7 +4,6 @@ import android.content.SharedPreferences import android.os.Bundle import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity -import androidx.preference.PreferenceManager open class BaseActivity: AppCompatActivity() { protected lateinit var sharedPrefs: SharedPreferences @@ -13,7 +12,7 @@ open class BaseActivity: AppCompatActivity() { private var shouldCheckTheme = true override fun onCreate(savedInstanceState: Bundle?) { - sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this) + sharedPrefs = (application as VolumeManagerApp).sharedPreferences themeValue = sharedPrefs.getString(Constants.THEME_VALUE_KEY, Constants.DEFAULT_THEME_VALUE)!! if (shouldCheckTheme && applyCustomTheme) { when (themeValue) { diff --git a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt index fe8b4c3..6ae7ec5 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt @@ -17,7 +17,6 @@ import android.view.animation.RotateAnimation import android.widget.ImageView import android.widget.RelativeLayout import android.widget.Toast -import androidx.activity.addCallback import androidx.annotation.RequiresApi import androidx.camera.camera2.interop.Camera2CameraInfo import androidx.camera.core.* @@ -29,7 +28,6 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.databinding.ActivityCameraBinding import sushi.hardcore.droidfs.filesystems.EncryptedVolume import sushi.hardcore.droidfs.util.IntentUtils @@ -63,14 +61,11 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { binding.imageTimer.setImageResource(R.drawable.icon_timer_off) } } - private var usf_keep_open = false private lateinit var sensorOrientationListener: SensorOrientationListener private var previousOrientation: Float = 0f private lateinit var orientedIcons: List private lateinit var encryptedVolume: EncryptedVolume private lateinit var outputDirectory: String - private var isFinishingIntentionally = false - private var isAskingPermissions = false private var permissionsGranted = false private lateinit var executor: Executor private lateinit var cameraProvider: ProcessCameraProvider @@ -92,7 +87,6 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) binding = ActivityCameraBinding.inflate(layoutInflater) setContentView(binding.root) supportActionBar?.hide() @@ -103,7 +97,6 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){ permissionsGranted = true } else { - isAskingPermissions = true requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_REQUEST_CODE) } } else { @@ -220,7 +213,6 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { binding.takePhotoButton.visibility = View.GONE if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { - isAskingPermissions = true requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), AUDIO_PERMISSION_REQUEST_CODE) } } @@ -280,17 +272,11 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { else -> false } } - onBackPressedDispatcher.addCallback(this) { - isFinishingIntentionally = true - isEnabled = false - onBackPressedDispatcher.onBackPressed() - } } @RequiresApi(Build.VERSION_CODES.M) override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) - isAskingPermissions = false if (grantResults.size == 1) { when (requestCode) { CAMERA_PERMISSION_REQUEST_CODE -> if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { @@ -301,10 +287,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { .setTitle(R.string.error) .setMessage(R.string.camera_perm_needed) .setCancelable(false) - .setPositiveButton(R.string.ok) { _, _ -> - isFinishingIntentionally = true - finish() - }.show() + .setPositiveButton(R.string.ok) { _, _ -> finish() }.show() } AUDIO_PERMISSION_REQUEST_CODE -> if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (videoCapture != null) { @@ -431,10 +414,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { .setTitle(R.string.error) .setMessage(R.string.picture_save_failed) .setCancelable(false) - .setPositiveButton(R.string.ok) { _, _ -> - isFinishingIntentionally = true - finish() - } + .setPositiveButton(R.string.ok) { _, _ -> finish() } .show() } } @@ -485,32 +465,18 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { } } - override fun onDestroy() { - super.onDestroy() - if (!isFinishingIntentionally) { - encryptedVolume.close() - RestrictedFileProvider.wipeAll(this) - } - } - - override fun onStop() { - super.onStop() - if (!isFinishing && !usf_keep_open){ - finish() - } - } - override fun onPause() { super.onPause() sensorOrientationListener.remove(this) - if (!isAskingPermissions && !usf_keep_open) { - finish() - } } override fun onResume() { super.onResume() - sensorOrientationListener.addListener(this) + if (encryptedVolume.isClosed()) { + finish() + } else { + sensorOrientationListener.addListener(this) + } } override fun onOrientationChange(newOrientation: Int) { diff --git a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt index faa8f59..67a2776 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt @@ -20,12 +20,10 @@ import kotlinx.coroutines.launch import sushi.hardcore.droidfs.Constants.DEFAULT_VOLUME_KEY import sushi.hardcore.droidfs.adapters.VolumeAdapter import sushi.hardcore.droidfs.add_volume.AddVolumeActivity -import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.databinding.ActivityMainBinding import sushi.hardcore.droidfs.databinding.DialogDeleteVolumeBinding import sushi.hardcore.droidfs.explorers.ExplorerRouter import sushi.hardcore.droidfs.file_operations.FileOperationService -import sushi.hardcore.droidfs.filesystems.EncryptedVolume import sushi.hardcore.droidfs.util.IntentUtils import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder @@ -33,11 +31,15 @@ import sushi.hardcore.droidfs.widgets.EditTextDialog import java.io.File class MainActivity : BaseActivity(), VolumeAdapter.Listener { + companion object { + private const val OPEN_DEFAULT_VOLUME = "openDefault" + } + private lateinit var binding: ActivityMainBinding private lateinit var volumeDatabase: VolumeDatabase + private lateinit var volumeManager: VolumeManager private lateinit var volumeAdapter: VolumeAdapter private lateinit var volumeOpener: VolumeOpener - private var usfKeepOpen: Boolean = false private var addVolume = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if ((explorerRouter.pickMode || explorerRouter.dropMode) && result.resultCode != AddVolumeActivity.RESULT_USER_BACK) { setResult(result.resultCode, result.data) // forward result @@ -54,7 +56,6 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { } private lateinit var fileOperationService: FileOperationService private lateinit var explorerRouter: ExplorerRouter - private var shouldCloseVolume = true // used when launched to pick file from another volume override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -80,10 +81,12 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { .show() } explorerRouter = ExplorerRouter(this, intent) + volumeManager = (application as VolumeManagerApp).volumeManager volumeDatabase = VolumeDatabase(this) volumeAdapter = VolumeAdapter( this, volumeDatabase, + (application as VolumeManagerApp).volumeManager, !explorerRouter.pickMode && !explorerRouter.dropMode, !explorerRouter.dropMode, this, @@ -100,30 +103,31 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { addVolume.launch(Intent(this, AddVolumeActivity::class.java).also { if (explorerRouter.dropMode || explorerRouter.pickMode) { IntentUtils.forwardIntent(intent, it) - shouldCloseVolume = false } }) } - usfKeepOpen = sharedPrefs.getBoolean("usf_keep_open", false) volumeOpener = VolumeOpener(this) - volumeOpener.defaultVolumeName?.let { name -> - try { - openVolume(volumeAdapter.volumes.first { it.name == name }) - } catch (e: NoSuchElementException) { - unsetDefaultVolume() - } - } onBackPressedDispatcher.addCallback(this) { if (volumeAdapter.selectedItems.isNotEmpty()) { unselectAll() } else { - if (explorerRouter.pickMode) { - shouldCloseVolume = false - } isEnabled = false onBackPressedDispatcher.onBackPressed() } } + volumeOpener.defaultVolumeName?.let { name -> + val state = savedInstanceState?.getBoolean(OPEN_DEFAULT_VOLUME) + if (state == true || state == null) { + val volumeData = volumeAdapter.volumes.first { it.name == name } + if (!volumeManager.isOpen(volumeData)) { + try { + openVolume(volumeData) + } catch (e: NoSuchElementException) { + unsetDefaultVolume() + } + } + } + } Intent(this, FileOperationService::class.java).also { bindService(it, object : ServiceConnection { override fun onServiceConnected(className: ComponentName, service: IBinder) { @@ -148,6 +152,11 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { volumeOpener.defaultVolumeName = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null) } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putBoolean(OPEN_DEFAULT_VOLUME, false) + } + override fun onSelectionChanged(size: Int) { title = if (size == 0) { getString(R.string.app_name) @@ -179,6 +188,11 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { invalidateOptionsMenu() } + private fun removeVolume(volume: VolumeData) { + volumeManager.getVolumeId(volume)?.let { volumeManager.closeVolume(it) } + volumeDatabase.removeVolume(volume.name) + } + private fun removeVolumes(volumes: List, i: Int = 0, doDeleteVolumeContent: Boolean? = null) { if (i < volumes.size) { if (volumes[i].isHidden) { @@ -196,12 +210,12 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { .setTitle(R.string.warning) .setView(dialogBinding.root) .setPositiveButton(R.string.forget_only) { _, _ -> - volumeDatabase.removeVolume(volumes[i].name) + removeVolume(volumes[i]) removeVolumes(volumes, i + 1, if (dialogBinding.checkboxApplyToAll.isChecked) false else null) } .setNegativeButton(R.string.delete_volume) { _, _ -> PathUtils.recursiveRemoveDirectory(File(volumes[i].getFullPath(filesDir.path))) - volumeDatabase.removeVolume(volumes[i].name) + removeVolume(volumes[i]) removeVolumes(volumes, i + 1, if (dialogBinding.checkboxApplyToAll.isChecked) true else null) } .setOnCancelListener { @@ -213,11 +227,11 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { if (doDeleteVolumeContent) { PathUtils.recursiveRemoveDirectory(File(volumes[i].getFullPath(filesDir.path))) } - volumeDatabase.removeVolume(volumes[i].name) + removeVolume(volumes[i]) removeVolumes(volumes, i + 1, doDeleteVolumeContent) } } else { - volumeDatabase.removeVolume(volumes[i].name) + removeVolume(volumes[i]) removeVolumes(volumes, i + 1, doDeleteVolumeContent) } } else { @@ -241,9 +255,6 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { return when (item.itemId) { android.R.id.home -> { if (explorerRouter.pickMode || explorerRouter.dropMode) { - if (explorerRouter.pickMode) { - shouldCloseVolume = false - } finish() } else { unselectAll() @@ -255,6 +266,15 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { invalidateOptionsMenu() true } + R.id.lock -> { + volumeAdapter.selectedItems.forEach { + volumeManager.getVolumeId(volumeAdapter.volumes[it])?.let { id -> + volumeManager.closeVolume(id) + } + } + unselectAll() + true + } R.id.remove -> { val selectedVolumes = volumeAdapter.selectedItems.map { i -> volumeAdapter.volumes[i] } removeVolumes(selectedVolumes) @@ -325,6 +345,9 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { menu.findItem(R.id.settings).isVisible = !explorerRouter.pickMode && !explorerRouter.dropMode val isSelecting = volumeAdapter.selectedItems.isNotEmpty() menu.findItem(R.id.select_all).isVisible = isSelecting + menu.findItem(R.id.lock).isVisible = isSelecting && volumeAdapter.selectedItems.any { + i -> volumeManager.isOpen(volumeAdapter.volumes[i]) + } menu.findItem(R.id.remove).isVisible = isSelecting menu.findItem(R.id.delete_password_hash).isVisible = isSelecting && @@ -456,11 +479,8 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { volumeAdapter.refresh() } - override fun onVolumeOpened(encryptedVolume: EncryptedVolume, volumeShortName: String) { - startActivity(explorerRouter.getExplorerIntent(encryptedVolume, volumeShortName)) - if (explorerRouter.pickMode) { - shouldCloseVolume = false - } + override fun onVolumeOpened(id: Int) { + startActivity(explorerRouter.getExplorerIntent(id, volume.shortName)) if (explorerRouter.dropMode || explorerRouter.pickMode) { finish() } @@ -468,18 +488,8 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { }) } - override fun onResume() { - super.onResume() - shouldCloseVolume = true - } - override fun onStop() { super.onStop() volumeOpener.wipeSensitive() - if (explorerRouter.pickMode && !usfKeepOpen && shouldCloseVolume) { - IntentUtils.getParcelableExtra(intent, "volume")?.close() - RestrictedFileProvider.wipeAll(this) - finish() - } } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/VolumeData.kt b/app/src/main/java/sushi/hardcore/droidfs/VolumeData.kt index 3f22476..acbd548 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/VolumeData.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/VolumeData.kt @@ -44,6 +44,17 @@ class VolumeData(val name: String, val isHidden: Boolean = false, val type: Byte } } + override fun equals(other: Any?): Boolean { + if (other !is VolumeData) { + return false + } + return other.name == name && other.isHidden == isHidden + } + + override fun hashCode(): Int { + return name.hashCode()+isHidden.hashCode() + } + companion object { const val VOLUMES_DIRECTORY = "volumes" diff --git a/app/src/main/java/sushi/hardcore/droidfs/VolumeManager.kt b/app/src/main/java/sushi/hardcore/droidfs/VolumeManager.kt new file mode 100644 index 0000000..bfb7957 --- /dev/null +++ b/app/src/main/java/sushi/hardcore/droidfs/VolumeManager.kt @@ -0,0 +1,42 @@ +package sushi.hardcore.droidfs + +import sushi.hardcore.droidfs.filesystems.EncryptedVolume + +class VolumeManager { + private var id = 0 + private val volumes = HashMap() + private val volumesData = HashMap() + + fun insert(volume: EncryptedVolume, data: VolumeData): Int { + volumes[id] = volume + volumesData[data] = id + return id++ + } + + fun isOpen(volume: VolumeData): Boolean { + return volumesData.containsKey(volume) + } + + fun getVolumeId(volume: VolumeData): Int? { + return volumesData[volume] + } + + fun getVolume(id: Int): EncryptedVolume? { + return volumes[id] + } + + fun closeVolume(id: Int) { + volumes.remove(id)?.let { volume -> + volume.close() + volumesData.filter { it.value == id }.forEach { + volumesData.remove(it.key) + } + } + } + + fun closeAll() { + volumes.forEach { it.value.close() } + volumes.clear() + volumesData.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/VolumeManagerApp.kt b/app/src/main/java/sushi/hardcore/droidfs/VolumeManagerApp.kt new file mode 100644 index 0000000..96b1bad --- /dev/null +++ b/app/src/main/java/sushi/hardcore/droidfs/VolumeManagerApp.kt @@ -0,0 +1,49 @@ +package sushi.hardcore.droidfs + +import android.app.Application +import android.content.SharedPreferences +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ProcessLifecycleOwner +import androidx.preference.PreferenceManager +import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider + +class VolumeManagerApp : Application(), DefaultLifecycleObserver { + companion object { + private const val USF_KEEP_OPEN_KEY = "usf_keep_open" + } + + lateinit var sharedPreferences: SharedPreferences + private val sharedPreferencesListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + if (key == USF_KEEP_OPEN_KEY) { + reloadUsfKeepOpen() + } + } + private var usfKeepOpen = false + var isStartingExternalApp = false + val volumeManager = VolumeManager() + + override fun onCreate() { + super.onCreate() + ProcessLifecycleOwner.get().lifecycle.addObserver(this) + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this).apply { + registerOnSharedPreferenceChangeListener(sharedPreferencesListener) + } + reloadUsfKeepOpen() + } + + private fun reloadUsfKeepOpen() { + usfKeepOpen = sharedPreferences.getBoolean(USF_KEEP_OPEN_KEY, false) + } + + override fun onResume(owner: LifecycleOwner) { + isStartingExternalApp = false + } + + override fun onStop(owner: LifecycleOwner) { + if (!isStartingExternalApp && !usfKeepOpen) { + volumeManager.closeAll() + RestrictedFileProvider.wipeAll(applicationContext) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/VolumeOpener.kt b/app/src/main/java/sushi/hardcore/droidfs/VolumeOpener.kt index 77d9d49..678b268 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/VolumeOpener.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/VolumeOpener.kt @@ -22,7 +22,7 @@ class VolumeOpener( ) { interface VolumeOpenerCallbacks { fun onHashStorageReset() {} - fun onVolumeOpened(encryptedVolume: EncryptedVolume, volumeShortName: String) + fun onVolumeOpened(id: Int) } private val volumeDatabase = VolumeDatabase(activity) @@ -31,6 +31,7 @@ class VolumeOpener( var themeValue = sharedPrefs.getString(Constants.THEME_VALUE_KEY, Constants.DEFAULT_THEME_VALUE)!! var defaultVolumeName: String? = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null) private var dialogBinding: DialogOpenVolumeBinding? = null + private val volumeManager = (activity.application as VolumeManagerApp).volumeManager init { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -40,54 +41,59 @@ class VolumeOpener( @SuppressLint("NewApi") // fingerprintProtector is non-null only when SDK_INT >= 23 fun openVolume(volume: VolumeData, isVolumeSaved: Boolean, callbacks: VolumeOpenerCallbacks) { - if (volume.type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE && BuildConfig.GOCRYPTFS_DISABLED) { - Toast.makeText(activity, R.string.gocryptfs_disabled, Toast.LENGTH_SHORT).show() - return - } else if (volume.type == EncryptedVolume.CRYFS_VOLUME_TYPE && BuildConfig.CRYFS_DISABLED) { - Toast.makeText(activity, R.string.cryfs_disabled, Toast.LENGTH_SHORT).show() - return - } - var askForPassword = true - fingerprintProtector?.let { fingerprintProtector -> - volume.encryptedHash?.let { encryptedHash -> - volume.iv?.let { iv -> - askForPassword = false - fingerprintProtector.listener = object : FingerprintProtector.Listener { - override fun onHashStorageReset() { - callbacks.onHashStorageReset() - } - override fun onPasswordHashDecrypted(hash: ByteArray) { - object : LoadingTask(activity, themeValue, R.string.loading_msg_open) { - override suspend fun doTask(): EncryptedVolume? { - val encryptedVolume = EncryptedVolume.init(volume, activity.filesDir.path, null, hash, null) - Arrays.fill(hash, 0) - return encryptedVolume + val volumeId = volumeManager.getVolumeId(volume) + if (volumeId == null) { + if (volume.type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE && BuildConfig.GOCRYPTFS_DISABLED) { + Toast.makeText(activity, R.string.gocryptfs_disabled, Toast.LENGTH_SHORT).show() + return + } else if (volume.type == EncryptedVolume.CRYFS_VOLUME_TYPE && BuildConfig.CRYFS_DISABLED) { + Toast.makeText(activity, R.string.cryfs_disabled, Toast.LENGTH_SHORT).show() + return + } + var askForPassword = true + fingerprintProtector?.let { fingerprintProtector -> + volume.encryptedHash?.let { encryptedHash -> + volume.iv?.let { iv -> + askForPassword = false + fingerprintProtector.listener = object : FingerprintProtector.Listener { + override fun onHashStorageReset() { + callbacks.onHashStorageReset() + } + override fun onPasswordHashDecrypted(hash: ByteArray) { + object : LoadingTask(activity, themeValue, R.string.loading_msg_open) { + override suspend fun doTask(): EncryptedVolume? { + val encryptedVolume = EncryptedVolume.init(volume, activity.filesDir.path, null, hash, null) + Arrays.fill(hash, 0) + return encryptedVolume + } + }.startTask(activity.lifecycleScope) { encryptedVolume -> + if (encryptedVolume == null) { + CustomAlertDialogBuilder(activity, themeValue) + .setTitle(R.string.open_volume_failed) + .setMessage(R.string.open_failed_hash_msg) + .setPositiveButton(R.string.ok, null) + .show() + } else { + callbacks.onVolumeOpened(volumeManager.insert(encryptedVolume, volume)) + } } - }.startTask(activity.lifecycleScope) { encryptedVolume -> - if (encryptedVolume == null) { - CustomAlertDialogBuilder(activity, themeValue) - .setTitle(R.string.open_volume_failed) - .setMessage(R.string.open_failed_hash_msg) - .setPositiveButton(R.string.ok, null) - .show() - } else { - callbacks.onVolumeOpened(encryptedVolume, volume.shortName) + } + override fun onPasswordHashSaved() {} + override fun onFailed(pending: Boolean) { + if (!pending) { + askForPassword(volume, isVolumeSaved, callbacks) } } } - override fun onPasswordHashSaved() {} - override fun onFailed(pending: Boolean) { - if (!pending) { - askForPassword(volume, isVolumeSaved, callbacks) - } - } + fingerprintProtector.loadPasswordHash(volume.shortName, encryptedHash, iv) } - fingerprintProtector.loadPasswordHash(volume.shortName, encryptedHash, iv) } } - } - if (askForPassword) { - askForPassword(volume, isVolumeSaved, callbacks) + if (askForPassword) { + askForPassword(volume, isVolumeSaved, callbacks) + } + } else { + callbacks.onVolumeOpened(volumeId) } } @@ -188,7 +194,7 @@ class VolumeOpener( override fun onPasswordHashDecrypted(hash: ByteArray) {} override fun onPasswordHashSaved() { Arrays.fill(returnedHash.value!!, 0) - callbacks.onVolumeOpened(encryptedVolume, volume.shortName) + callbacks.onVolumeOpened(volumeManager.insert(encryptedVolume, volume)) } private var isClosed = false override fun onFailed(pending: Boolean) { @@ -201,7 +207,7 @@ class VolumeOpener( } fingerprintProtector.savePasswordHash(volume, returnedHash.value!!) } else { - callbacks.onVolumeOpened(encryptedVolume, volume.shortName) + callbacks.onVolumeOpened(volumeManager.insert(encryptedVolume, volume)) } } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/adapters/VolumeAdapter.kt b/app/src/main/java/sushi/hardcore/droidfs/adapters/VolumeAdapter.kt index c8ce808..356bcb0 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/adapters/VolumeAdapter.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/adapters/VolumeAdapter.kt @@ -8,15 +8,18 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.VolumeData import sushi.hardcore.droidfs.VolumeDatabase +import sushi.hardcore.droidfs.VolumeManager import sushi.hardcore.droidfs.filesystems.EncryptedVolume class VolumeAdapter( private val context: Context, private val volumeDatabase: VolumeDatabase, + private val volumeManager: VolumeManager, private val allowSelection: Boolean, private val showReadOnly: Boolean, private val listener: Listener, @@ -80,16 +83,12 @@ class VolumeAdapter( fun bind(position: Int) { val volume = volumes[position] itemView.findViewById(R.id.text_volume_name).text = volume.shortName - itemView.findViewById(R.id.image_icon).setImageResource(R.drawable.icon_volume) itemView.findViewById(R.id.text_path).text = if (volume.isHidden) context.getString(R.string.hidden_volume) else volume.name - itemView.findViewById(R.id.icon_fingerprint).visibility = if (volume.encryptedHash == null) { - View.GONE - } else { - View.VISIBLE - } + itemView.findViewById(R.id.icon_unlocked).isVisible = volumeManager.isOpen(volume) + itemView.findViewById(R.id.icon_fingerprint).isVisible = volume.encryptedHash != null itemView.findViewById(R.id.text_info).text = context.getString( if (volume.canWrite(context.filesDir.path)) { R.string.volume_type diff --git a/app/src/main/java/sushi/hardcore/droidfs/add_volume/AddVolumeActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/add_volume/AddVolumeActivity.kt index 4e8360b..1c14777 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/add_volume/AddVolumeActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/add_volume/AddVolumeActivity.kt @@ -4,11 +4,8 @@ import android.os.Bundle import android.view.MenuItem import androidx.activity.addCallback import sushi.hardcore.droidfs.* -import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.databinding.ActivityAddVolumeBinding import sushi.hardcore.droidfs.explorers.ExplorerRouter -import sushi.hardcore.droidfs.filesystems.EncryptedVolume -import sushi.hardcore.droidfs.util.IntentUtils class AddVolumeActivity: BaseActivity() { @@ -19,15 +16,12 @@ class AddVolumeActivity: BaseActivity() { private lateinit var binding: ActivityAddVolumeBinding private lateinit var explorerRouter: ExplorerRouter private lateinit var volumeOpener: VolumeOpener - private var usfKeepOpen = false - var shouldCloseVolume = true // used when launched to pick file from another volume override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityAddVolumeBinding.inflate(layoutInflater) setContentView(binding.root) supportActionBar?.setDisplayHomeAsUpEnabled(true) - usfKeepOpen = sharedPrefs.getBoolean("usf_keep_open", false) explorerRouter = ExplorerRouter(this, intent) volumeOpener = VolumeOpener(this) if (savedInstanceState == null) { @@ -41,7 +35,6 @@ class AddVolumeActivity: BaseActivity() { } onBackPressedDispatcher.addCallback(this) { setResult(RESULT_USER_BACK) - shouldCloseVolume = false isEnabled = false onBackPressedDispatcher.onBackPressed() } @@ -53,7 +46,6 @@ class AddVolumeActivity: BaseActivity() { supportFragmentManager.popBackStack() else { setResult(RESULT_USER_BACK) - shouldCloseVolume = false finish() } } @@ -70,21 +62,19 @@ class AddVolumeActivity: BaseActivity() { ) } - fun startExplorer(encryptedVolume: EncryptedVolume, volumeShortName: String) { - startActivity(explorerRouter.getExplorerIntent(encryptedVolume, volumeShortName)) - shouldCloseVolume = false + fun startExplorer(volumeId: Int, volumeShortName: String) { + startActivity(explorerRouter.getExplorerIntent(volumeId, volumeShortName)) finish() } fun onVolumeSelected(volume: VolumeData, rememberVolume: Boolean) { if (rememberVolume) { setResult(RESULT_USER_BACK) - shouldCloseVolume = false finish() } else { volumeOpener.openVolume(volume, false, object : VolumeOpener.VolumeOpenerCallbacks { - override fun onVolumeOpened(encryptedVolume: EncryptedVolume, volumeShortName: String) { - startExplorer(encryptedVolume, volumeShortName) + override fun onVolumeOpened(id: Int) { + startExplorer(id, volume.shortName) } }) } @@ -106,18 +96,4 @@ class AddVolumeActivity: BaseActivity() { .addToBackStack(null) .commit() } - - override fun onStart() { - super.onStart() - shouldCloseVolume = true - } - - override fun onStop() { - super.onStop() - if (explorerRouter.pickMode && !usfKeepOpen && shouldCloseVolume) { - IntentUtils.getParcelableExtra(intent, "volume")?.close() - RestrictedFileProvider.wipeAll(this) - finish() - } - } } \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt b/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt index 57d9994..2f3714d 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt @@ -158,11 +158,7 @@ class CreateVolumeFragment: Fragment() { } else { null } - val encryptedVolume = if (rememberVolume) { - null - } else { - ObjRef(null) - } + val encryptedVolume = ObjRef(null) object: LoadingTask(requireActivity() as AppCompatActivity, themeValue, R.string.loading_msg_create) { private fun generateResult(success: Boolean, volumeType: Byte): Byte { return if (success) { @@ -223,6 +219,9 @@ class CreateVolumeFragment: Fragment() { isVolumeSaved = saveVolume(volume) } } + val volumeId = encryptedVolume.value?.let { + (activity?.application as VolumeManagerApp).volumeManager.insert(it, volume) + } @SuppressLint("NewApi") // if fingerprintProtector is null checkboxSavePassword is hidden if (isVolumeSaved && binding.checkboxSavePassword.isChecked && returnedHash != null) { fingerprintProtector!!.let { @@ -235,31 +234,31 @@ class CreateVolumeFragment: Fragment() { override fun onPasswordHashDecrypted(hash: ByteArray) {} // shouldn't happen here override fun onPasswordHashSaved() { Arrays.fill(returnedHash.value!!, 0) - onVolumeCreated(encryptedVolume?.value, volume.shortName) + onVolumeCreated(volumeId, volume.shortName) } override fun onFailed(pending: Boolean) { if (!pending) { Arrays.fill(returnedHash.value!!, 0) - onVolumeCreated(encryptedVolume?.value, volume.shortName) + onVolumeCreated(volumeId, volume.shortName) } } } it.savePasswordHash(volume, returnedHash.value!!) } } else { - onVolumeCreated(encryptedVolume?.value, volume.shortName) + onVolumeCreated(volumeId, volume.shortName) } } } } } - private fun onVolumeCreated(encryptedVolume: EncryptedVolume?, volumeShortName: String) { + private fun onVolumeCreated(id: Int?, volumeShortName: String) { (activity as AddVolumeActivity).apply { - if (rememberVolume || encryptedVolume == null) { + if (rememberVolume || id == null) { finish() } else { - startExplorer(encryptedVolume, volumeShortName) + startExplorer(id, volumeShortName) } } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/add_volume/SelectPathFragment.kt b/app/src/main/java/sushi/hardcore/droidfs/add_volume/SelectPathFragment.kt index bfe1820..df0bd44 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/add_volume/SelectPathFragment.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/add_volume/SelectPathFragment.kt @@ -24,6 +24,7 @@ import sushi.hardcore.droidfs.Constants import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.VolumeData import sushi.hardcore.droidfs.VolumeDatabase +import sushi.hardcore.droidfs.VolumeManagerApp import sushi.hardcore.droidfs.databinding.DialogSdcardErrorBinding import sushi.hardcore.droidfs.databinding.FragmentSelectPathBinding import sushi.hardcore.droidfs.filesystems.EncryptedVolume @@ -62,6 +63,7 @@ class SelectPathFragment: Fragment() { if (uri != null) onDirectoryPicked(uri) } + private lateinit var app: VolumeManagerApp private var themeValue = Constants.DEFAULT_THEME_VALUE private lateinit var volumeDatabase: VolumeDatabase private lateinit var filesDir: String @@ -81,6 +83,7 @@ class SelectPathFragment: Fragment() { } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + app = requireActivity().application as VolumeManagerApp sharedPrefs = PreferenceManager.getDefaultSharedPreferences(requireContext()) originalRememberVolume = sharedPrefs.getBoolean(Constants.REMEMBER_VOLUME_KEY, true) binding.switchRemember.isChecked = originalRememberVolume @@ -105,6 +108,7 @@ class SelectPathFragment: Fragment() { if (Environment.isExternalStorageManager()) { launchPickDirectory() } else { + app.isStartingExternalApp = true startActivity(Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, Uri.parse("package:"+requireContext().packageName))) } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -119,6 +123,7 @@ class SelectPathFragment: Fragment() { ) { launchPickDirectory() } else { + app.isStartingExternalApp = true askStoragePermissions.launch( arrayOf( Manifest.permission.READ_EXTERNAL_STORAGE, @@ -149,7 +154,7 @@ class SelectPathFragment: Fragment() { } private fun launchPickDirectory() { - (activity as AddVolumeActivity).shouldCloseVolume = false + app.isStartingExternalApp = true PathUtils.safePickDirectory(pickDirectory, requireContext(), themeValue) } diff --git a/app/src/main/java/sushi/hardcore/droidfs/content_providers/RestrictedFileProvider.kt b/app/src/main/java/sushi/hardcore/droidfs/content_providers/RestrictedFileProvider.kt index 03dfe7f..5c83108 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/content_providers/RestrictedFileProvider.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/content_providers/RestrictedFileProvider.kt @@ -15,7 +15,7 @@ import sushi.hardcore.droidfs.util.SQLUtil.appendSelectionArgs import sushi.hardcore.droidfs.util.SQLUtil.concatenateWhere import sushi.hardcore.droidfs.util.Wiper import java.io.File -import java.util.* +import java.util.UUID import java.util.regex.Pattern class RestrictedFileProvider: ContentProvider() { diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt index 66e807b..8140946 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt @@ -13,6 +13,7 @@ import android.view.View import android.widget.ImageButton import android.widget.TextView import android.widget.Toast +import androidx.activity.addCallback import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider @@ -22,20 +23,15 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import kotlinx.coroutines.* -import sushi.hardcore.droidfs.BaseActivity -import sushi.hardcore.droidfs.Constants -import sushi.hardcore.droidfs.FileTypes -import sushi.hardcore.droidfs.R +import sushi.hardcore.droidfs.* import sushi.hardcore.droidfs.adapters.ExplorerElementAdapter import sushi.hardcore.droidfs.adapters.OpenAsDialogAdapter import sushi.hardcore.droidfs.content_providers.ExternalProvider -import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.file_operations.FileOperationService import sushi.hardcore.droidfs.file_operations.OperationFile import sushi.hardcore.droidfs.file_viewers.* import sushi.hardcore.droidfs.filesystems.EncryptedVolume import sushi.hardcore.droidfs.filesystems.Stat -import sushi.hardcore.droidfs.util.IntentUtils import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import sushi.hardcore.droidfs.widgets.EditTextDialog @@ -46,6 +42,7 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene private var foldersFirst = true private var mapFolders = true private var currentSortOrderIndex = 0 + private var volumeId = -1 protected lateinit var encryptedVolume: EncryptedVolume private lateinit var volumeName: String private lateinit var explorerViewModel: ExplorerViewModel @@ -58,10 +55,8 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene protected val taskScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) protected lateinit var explorerElements: MutableList protected lateinit var explorerAdapter: ExplorerElementAdapter - private var isCreating = true - protected var isStartingActivity = false + protected lateinit var app: VolumeManagerApp private var usf_open = false - protected var usf_keep_open = false private lateinit var linearLayoutManager: LinearLayoutManager private var isUsingListLayout = true private lateinit var layoutIcon: ImageButton @@ -76,10 +71,11 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + app = application as VolumeManagerApp usf_open = sharedPrefs.getBoolean("usf_open", false) - usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) - volumeName = intent.getStringExtra("volume_name") ?: "" - encryptedVolume = IntentUtils.getParcelableExtra(intent, "volume")!! + volumeName = intent.getStringExtra("volumeName") ?: "" + volumeId = intent.getIntExtra("volumeId", -1) + encryptedVolume = app.volumeManager.getVolume(volumeId)!! sortOrderEntries = resources.getStringArray(R.array.sort_orders_entries) sortOrderValues = resources.getStringArray(R.array.sort_orders_values) foldersFirst = sharedPrefs.getBoolean("folders_first", true) @@ -118,6 +114,19 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene isUsingListLayout = sharedPrefs.getBoolean("useListLayout", true) layoutIcon = findViewById(R.id.layout_icon) setRecyclerViewLayout() + onBackPressedDispatcher.addCallback(this) { + if (explorerAdapter.selectedItems.isEmpty()) { + val parentPath = PathUtils.getParentPath(currentDirectoryPath) + if (parentPath == currentDirectoryPath) { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + } else { + setCurrentPath(PathUtils.getParentPath(currentDirectoryPath)) + } + } else { + unselectAll() + } + } layoutIcon.setOnClickListener { isUsingListLayout = !isUsingListLayout setRecyclerViewLayout() @@ -171,18 +180,17 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene } } - private fun startFileViewer(cls: Class<*>, filePath: String){ + private fun startFileViewer(cls: Class<*>, filePath: String) { val intent = Intent(this, cls).apply { putExtra("path", filePath) putExtra("volume", encryptedVolume) putExtra("sortOrder", sortOrderValues[currentSortOrderIndex]) } - isStartingActivity = true startActivity(intent) } - private fun openWithExternalApp(fullPath: String){ - isStartingActivity = true + private fun openWithExternalApp(fullPath: String) { + app.isStartingExternalApp = true ExternalProvider.open(this, themeValue, encryptedVolume, fullPath) } @@ -332,28 +340,18 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene } } - private fun askCloseVolume() { + private fun askLockVolume() { CustomAlertDialogBuilder(this, themeValue) .setTitle(R.string.warning) - .setMessage(R.string.ask_close_volume) - .setPositiveButton(R.string.ok) { _, _ -> closeVolumeOnUserExit() } + .setMessage(R.string.ask_lock_volume) + .setPositiveButton(R.string.ok) { _, _ -> + app.volumeManager.closeVolume(volumeId) + finish() + } .setNegativeButton(R.string.cancel, null) .show() } - override fun onBackPressed() { - if (explorerAdapter.selectedItems.isEmpty()) { - val parentPath = PathUtils.getParentPath(currentDirectoryPath) - if (parentPath == currentDirectoryPath) { - askCloseVolume() - } else { - setCurrentPath(PathUtils.getParentPath(currentDirectoryPath)) - } - } else { - unselectAll() - } - } - private fun createFolder(folderName: String){ if (folderName.isEmpty()) { Toast.makeText(this, R.string.error_filename_empty, Toast.LENGTH_SHORT).show() @@ -508,9 +506,9 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene val noItemSelected = explorerAdapter.selectedItems.isEmpty() val iconColor = ContextCompat.getColor(this, R.color.neutralIconTint) setMenuIconTint(menu, iconColor, R.id.sort, R.drawable.icon_sort) - setMenuIconTint(menu, iconColor, R.id.decrypt, R.drawable.icon_decrypt) setMenuIconTint(menu, iconColor, R.id.share, R.drawable.icon_share) menu.findItem(R.id.sort).isVisible = noItemSelected + menu.findItem(R.id.lock).isVisible = noItemSelected menu.findItem(R.id.close).isVisible = noItemSelected supportActionBar?.setDisplayHomeAsUpEnabled(!noItemSelected) if (!noItemSelected) { @@ -577,55 +575,33 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene true } R.id.close -> { - askCloseVolume() + finish() + true + } + R.id.lock -> { + askLockVolume() true } else -> super.onOptionsItemSelected(item) } } - protected open fun closeVolumeOnUserExit() { - finish() - } - - protected open fun closeVolumeOnDestroy() { - taskScope.cancel() - if (!encryptedVolume.isClosed()) { - encryptedVolume.close() - } - RestrictedFileProvider.wipeAll(this) //additional security - } - override fun onDestroy() { super.onDestroy() if (!isChangingConfigurations) { //activity won't be recreated - closeVolumeOnDestroy() - } - } - - override fun onPause() { - super.onPause() - if (!isChangingConfigurations){ - if (isStartingActivity){ - isStartingActivity = false - } else if (!usf_keep_open){ - finish() - } + taskScope.cancel() } } override fun onResume() { super.onResume() - if (isCreating){ - isCreating = false + if (app.isStartingExternalApp) { + ExternalProvider.removeFilesAsync(this) + } + if (encryptedVolume.isClosed()) { + finish() } else { - if (encryptedVolume.isClosed()) { - finish() - } else { - isStartingActivity = false - ExternalProvider.removeFilesAsync(this) - setCurrentPath(currentDirectoryPath) - } + setCurrentPath(currentDirectoryPath) } } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt index 193ec4d..da14a3c 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt @@ -6,6 +6,7 @@ import android.net.Uri import android.view.Menu import android.view.MenuItem import android.widget.Toast +import androidx.activity.addCallback import androidx.activity.result.contract.ActivityResultContracts import androidx.documentfile.provider.DocumentFile import com.google.android.material.floatingactionbutton.FloatingActionButton @@ -60,9 +61,7 @@ class ExplorerActivity : BaseExplorerActivity() { } if (operationFiles.size > 0){ checkPathOverwrite(operationFiles, currentDirectoryPath) { items -> - if (items == null) { - remoteEncryptedVolume.close() - } else { + if (items != null) { // stop loading thumbnails while writing files explorerAdapter.loadThumbnails = false taskScope.launch { @@ -78,12 +77,9 @@ class ExplorerActivity : BaseExplorerActivity() { } explorerAdapter.loadThumbnails = true setCurrentPath(currentDirectoryPath) - remoteEncryptedVolume.close() } } } - } else { - remoteEncryptedVolume.close() } } } @@ -169,6 +165,16 @@ class ExplorerActivity : BaseExplorerActivity() { override fun init() { super.init() + onBackPressedDispatcher.addCallback(this) { + if (currentItemAction != ItemsActions.NONE) { + cancelItemAction() + invalidateOptionsMenu() + } else { + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true + } + } findViewById(R.id.fab).setOnClickListener { if (currentItemAction != ItemsActions.NONE){ openDialogCreateFolder() @@ -189,15 +195,14 @@ class ExplorerActivity : BaseExplorerActivity() { val intent = Intent(this, MainActivity::class.java) intent.action = "pick" intent.putExtra("volume", encryptedVolume) - isStartingActivity = true pickFromOtherVolumes.launch(intent) } "importFiles" -> { - isStartingActivity = true + app.isStartingExternalApp = true pickFiles.launch(arrayOf("*/*")) } "importFolder" -> { - isStartingActivity = true + app.isStartingExternalApp = true pickImportDirectory.launch(null) } "createFile" -> { @@ -212,7 +217,6 @@ class ExplorerActivity : BaseExplorerActivity() { val intent = Intent(this, CameraActivity::class.java) intent.putExtra("path", currentDirectoryPath) intent.putExtra("volume", encryptedVolume) - isStartingActivity = true startActivity(intent) } } @@ -257,6 +261,7 @@ class ExplorerActivity : BaseExplorerActivity() { val result = super.onCreateOptionsMenu(menu) if (currentItemAction != ItemsActions.NONE) { menu.findItem(R.id.validate).isVisible = true + menu.findItem(R.id.lock).isVisible = false menu.findItem(R.id.close).isVisible = false supportActionBar?.setDisplayHomeAsUpEnabled(true) } else { @@ -405,13 +410,13 @@ class ExplorerActivity : BaseExplorerActivity() { for (i in explorerAdapter.selectedItems) { paths.add(explorerElements[i].fullPath) } - isStartingActivity = true + app.isStartingExternalApp = true ExternalProvider.share(this, themeValue, encryptedVolume, paths) unselectAll() true } R.id.decrypt -> { - isStartingActivity = true + app.isStartingExternalApp = true pickExportDirectory.launch(null) true } @@ -506,13 +511,4 @@ class ExplorerActivity : BaseExplorerActivity() { itemsToProcess.clear() } } - - override fun onBackPressed() { - if (currentItemAction != ItemsActions.NONE) { - cancelItemAction() - invalidateOptionsMenu() - } else { - super.onBackPressed() - } - } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt index bdcb912..281c552 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt @@ -22,21 +22,18 @@ class ExplorerActivityPick : BaseExplorerActivity() { } override fun onExplorerElementClick(position: Int) { - val wasSelecting = explorerAdapter.selectedItems.isNotEmpty() if (explorerAdapter.selectedItems.isEmpty()) { - if (!wasSelecting) { - val fullPath = PathUtils.pathJoin(currentDirectoryPath, explorerElements[position].name) - when { - explorerElements[position].isDirectory -> { - setCurrentPath(fullPath) - } - explorerElements[position].isParentFolder -> { - setCurrentPath(PathUtils.getParentPath(currentDirectoryPath)) - } - else -> { - resultIntent.putExtra("path", fullPath) - returnActivityResult() - } + val fullPath = PathUtils.pathJoin(currentDirectoryPath, explorerElements[position].name) + when { + explorerElements[position].isDirectory -> { + setCurrentPath(fullPath) + } + explorerElements[position].isParentFolder -> { + setCurrentPath(PathUtils.getParentPath(currentDirectoryPath)) + } + else -> { + resultIntent.putExtra("path", fullPath) + returnActivityResult() } } } @@ -81,17 +78,4 @@ class ExplorerActivityPick : BaseExplorerActivity() { isFinishingIntentionally = true finish() } - - override fun closeVolumeOnDestroy() { - if (!isFinishingIntentionally && !usf_keep_open){ - IntentUtils.getParcelableExtra(intent, "destinationVolume")?.close() - super.closeVolumeOnDestroy() - } - } - - override fun closeVolumeOnUserExit() { - isFinishingIntentionally = true - super.closeVolumeOnUserExit() - super.closeVolumeOnDestroy() - } } \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerRouter.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerRouter.kt index cafc0da..e3114e4 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerRouter.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerRouter.kt @@ -9,7 +9,7 @@ class ExplorerRouter(private val context: Context, private val intent: Intent) { var pickMode = intent.action == "pick" var dropMode = (intent.action == Intent.ACTION_SEND || intent.action == Intent.ACTION_SEND_MULTIPLE) && intent.extras != null - fun getExplorerIntent(encryptedVolume: EncryptedVolume, volumeShortName: String): Intent { + fun getExplorerIntent(volumeId: Int, volumeShortName: String): Intent { var explorerIntent: Intent? = null if (dropMode) { //import via android share menu explorerIntent = Intent(context, ExplorerActivityDrop::class.java) @@ -22,8 +22,8 @@ class ExplorerRouter(private val context: Context, private val intent: Intent) { if (explorerIntent == null) { explorerIntent = Intent(context, ExplorerActivity::class.java) //default opening } - explorerIntent.putExtra("volume", encryptedVolume) - explorerIntent.putExtra("volume_name", volumeShortName) + explorerIntent.putExtra("volumeId", volumeId) + explorerIntent.putExtra("volumeName", volumeShortName) return explorerIntent } } \ No newline at end of file diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt index 2af9f00..6ddef20 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt @@ -2,7 +2,6 @@ package sushi.hardcore.droidfs.file_viewers import android.os.Bundle import android.view.View -import androidx.activity.addCallback import androidx.core.content.ContextCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -14,7 +13,6 @@ import kotlinx.coroutines.withContext import sushi.hardcore.droidfs.BaseActivity import sushi.hardcore.droidfs.FileTypes import sushi.hardcore.droidfs.R -import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider import sushi.hardcore.droidfs.explorers.ExplorerElement import sushi.hardcore.droidfs.filesystems.EncryptedVolume import sushi.hardcore.droidfs.util.IntentUtils @@ -27,8 +25,6 @@ abstract class FileViewerActivity: BaseActivity() { private lateinit var originalParentPath: String private lateinit var windowInsetsController: WindowInsetsControllerCompat private var windowTypeMask = 0 - private var isFinishingIntentionally = false - private var usf_keep_open = false private var foldersFirst = true private var wasMapped = false protected val mappedPlaylist = mutableListOf() @@ -43,17 +39,11 @@ abstract class FileViewerActivity: BaseActivity() { filePath = intent.getStringExtra("path")!! originalParentPath = PathUtils.getParentPath(filePath) encryptedVolume = IntentUtils.getParcelableExtra(intent, "volume")!! - usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false) foldersFirst = sharedPrefs.getBoolean("folders_first", true) windowInsetsController = WindowInsetsControllerCompat(window, window.decorView) windowInsetsController.addOnControllableInsetsChangedListener { _, typeMask -> windowTypeMask = typeMask } - onBackPressedDispatcher.addCallback(this) { - isFinishingIntentionally = true - isEnabled = false - onBackPressedDispatcher.onBackPressed() - } if (fullscreenMode) { fixNavBarColor() hideSystemUi() @@ -156,21 +146,12 @@ abstract class FileViewerActivity: BaseActivity() { } protected fun goBackToExplorer() { - isFinishingIntentionally = true finish() } - override fun onDestroy() { - super.onDestroy() - if (!isFinishingIntentionally) { - encryptedVolume.close() - RestrictedFileProvider.wipeAll(this) - } - } - - override fun onPause() { - super.onPause() - if (!usf_keep_open) { + override fun onResume() { + super.onResume() + if (encryptedVolume.isClosed()) { finish() } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt index fce60ba..6bf1359 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt @@ -7,6 +7,7 @@ import android.view.Menu import android.view.MenuItem import android.widget.EditText import android.widget.Toast +import androidx.activity.addCallback import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import java.io.File @@ -29,6 +30,9 @@ class TextEditor: FileViewerActivity() { loadWholeFile(filePath) { try { loadLayout(String(it)) + onBackPressedDispatcher.addCallback(this) { + checkSaveAndExit() + } } catch (e: OutOfMemoryError){ CustomAlertDialogBuilder(this, themeValue) .setTitle(R.string.error) @@ -124,8 +128,4 @@ class TextEditor: FileViewerActivity() { } return true } - - override fun onBackPressed() { - checkSaveAndExit() - } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt index 9b5f9e2..1fb7e14 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt @@ -67,13 +67,9 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() { } } - fun create(baseDir: String, localStateDir: String, password: ByteArray, returnedHash: ObjRef?, cipher: String?, volume: ObjRef?): Boolean { + fun create(baseDir: String, localStateDir: String, password: ByteArray, returnedHash: ObjRef?, cipher: String?, volume: ObjRef): Boolean { return init(baseDir, localStateDir, password, null, returnedHash, true, cipher)?.also { - if (volume == null) { - it.close() - } else { - volume.value = it - } + volume.value = it } != null } diff --git a/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt index 8fc7241..763e37f 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt @@ -36,7 +36,6 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() { logN: Int, creator: String, returnedHash: ByteArray?, - openAfterCreation: Boolean, ): Int private external fun nativeInit(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): Int external fun changePassword( @@ -53,20 +52,26 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() { plainTextNames: Boolean, xchacha: Int, returnedHash: ByteArray?, - volume: ObjRef? + volume: ObjRef ): Boolean { - val openAfterCreation = volume != null - val result = nativeCreateVolume(root_cipher_dir, password, plainTextNames, xchacha, ScryptDefaultLogN, VOLUME_CREATOR, returnedHash, openAfterCreation) - return if (!openAfterCreation) { - result == 1 - } else if (result == -1) { - Log.e("gocryptfs", "Failed to open volume after creation") - true - } else if (result == -2) { - false - } else { - volume!!.value = GocryptfsVolume(result) - true + return when (val result = nativeCreateVolume( + root_cipher_dir, + password, + plainTextNames, + xchacha, + ScryptDefaultLogN, + VOLUME_CREATOR, + returnedHash, + )) { + -1 -> { + Log.e("gocryptfs", "Failed to open volume after creation") + true + } + -2 -> false + else -> { + volume.value = GocryptfsVolume(result) + true + } } } diff --git a/app/src/main/native/gocryptfs_jni.c b/app/src/main/native/gocryptfs_jni.c index 9fe35c9..3d5a309 100644 --- a/app/src/main/native/gocryptfs_jni.c +++ b/app/src/main/native/gocryptfs_jni.c @@ -1,8 +1,6 @@ #include -#include #include #include -#include #include "libgocryptfs.h" const int KeyLen = 32; @@ -15,38 +13,34 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_00024Companion_nativeCre jint xchacha, jint logN, jstring jcreator, - jbyteArray jreturned_hash, - jboolean open_after_creation) { + jbyteArray jreturned_hash) { const char* root_cipher_dir = (*env)->GetStringUTFChars(env, jroot_cipher_dir, NULL); const char* creator = (*env)->GetStringUTFChars(env, jcreator, NULL); GoString gofilename = {root_cipher_dir, strlen(root_cipher_dir)}, gocreator = {creator, strlen(creator)}; - const size_t password_len = (*env)->GetArrayLength(env, jpassword); + const size_t password_len = (const size_t) (*env)->GetArrayLength(env, jpassword); jbyte* password = (*env)->GetByteArrayElements(env, jpassword, NULL); GoSlice go_password = {password, password_len, password_len}; size_t returned_hash_len; GoSlice go_returned_hash; if (!(*env)->IsSameObject(env, jreturned_hash, NULL)) { - returned_hash_len = (*env)->GetArrayLength(env, jreturned_hash); + returned_hash_len = (size_t) (*env)->GetArrayLength(env, jreturned_hash); go_returned_hash.data = (*env)->GetByteArrayElements(env, jreturned_hash, NULL); - } else if (open_after_creation) { + } else { returned_hash_len = KeyLen; go_returned_hash.data = malloc(KeyLen); - } else { - returned_hash_len = 0; - go_returned_hash.data = NULL; } go_returned_hash.len = returned_hash_len; go_returned_hash.cap = returned_hash_len; - GoUint8 result = gcf_create_volume(gofilename, go_password, plainTextNames, xchacha, logN, gocreator, go_returned_hash); + GoUint8 result = gcf_create_volume(gofilename, go_password, plainTextNames, (GoInt8) xchacha, logN, gocreator, go_returned_hash); (*env)->ReleaseByteArrayElements(env, jpassword, password, 0); (*env)->ReleaseStringUTFChars(env, jcreator, creator); GoInt sessionID = -2; - if (result && open_after_creation) { + if (result) { GoSlice null_slice = {NULL, 0, 0}; sessionID = gcf_init(gofilename, null_slice, go_returned_hash, null_slice); } @@ -55,14 +49,14 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_00024Companion_nativeCre if (!(*env)->IsSameObject(env, jreturned_hash, NULL)) { (*env)->ReleaseByteArrayElements(env, jreturned_hash, go_returned_hash.data, 0); - } else if (open_after_creation) { + } else { for (unsigned int i=0; iIsSameObject(env, jgiven_hash, NULL)){ - password_len = (*env)->GetArrayLength(env, jpassword); + password_len = (size_t) (*env)->GetArrayLength(env, jpassword); password = (*env)->GetByteArrayElements(env, jpassword, NULL); go_password.data = password; go_password.len = password_len; go_password.cap = password_len; } else { - given_hash_len = (*env)->GetArrayLength(env, jgiven_hash); + given_hash_len = (size_t) (*env)->GetArrayLength(env, jgiven_hash); given_hash = (*env)->GetByteArrayElements(env, jgiven_hash, NULL); go_given_hash.data = given_hash; go_given_hash.len = given_hash_len; @@ -98,7 +92,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_00024Companion_nativeIni jbyte* returned_hash; GoSlice go_returned_hash = {NULL, 0, 0}; if (!(*env)->IsSameObject(env, jreturned_hash, NULL)){ - returned_hash_len = (*env)->GetArrayLength(env, jreturned_hash); + returned_hash_len = (size_t) (*env)->GetArrayLength(env, jreturned_hash); returned_hash = (*env)->GetByteArrayElements(env, jreturned_hash, NULL); go_returned_hash.data = returned_hash; go_returned_hash.len = returned_hash_len; @@ -145,20 +139,20 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_00024Companion_changePas jbyte* given_hash; GoSlice go_given_hash = {NULL, 0, 0}; if ((*env)->IsSameObject(env, jgiven_hash, NULL)){ - old_password_len = (*env)->GetArrayLength(env, jold_password); + old_password_len = (size_t) (*env)->GetArrayLength(env, jold_password); old_password = (*env)->GetByteArrayElements(env, jold_password, NULL); go_old_password.data = old_password; go_old_password.len = old_password_len; go_old_password.cap = old_password_len; } else { - given_hash_len = (*env)->GetArrayLength(env, jgiven_hash); + given_hash_len = (size_t) (*env)->GetArrayLength(env, jgiven_hash); given_hash = (*env)->GetByteArrayElements(env, jgiven_hash, NULL); go_given_hash.data = given_hash; go_given_hash.len = given_hash_len; go_given_hash.cap = given_hash_len; } - size_t new_password_len = (*env)->GetArrayLength(env, jnew_password); + size_t new_password_len = (size_t) (*env)->GetArrayLength(env, jnew_password); jbyte* new_password = (*env)->GetByteArrayElements(env, jnew_password, NULL); GoSlice go_new_password = {new_password, new_password_len, new_password_len}; @@ -166,7 +160,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_00024Companion_changePas jbyte* returned_hash; GoSlice go_returned_hash = {NULL, 0, 0}; if (!(*env)->IsSameObject(env, jreturned_hash, NULL)) { - returned_hash_len = (*env)->GetArrayLength(env, jreturned_hash); + returned_hash_len = (size_t) (*env)->GetArrayLength(env, jreturned_hash); returned_hash = (*env)->GetByteArrayElements(env, jreturned_hash, NULL); go_returned_hash.data = returned_hash; go_returned_hash.len = returned_hash_len; @@ -303,7 +297,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1open_1write_1mod const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); GoString go_file_path = {file_path, strlen(file_path)}; - GoInt handleID = gcf_open_write_mode(sessionID, go_file_path, mode); + GoInt handleID = gcf_open_write_mode(sessionID, go_file_path, (GoUint32) mode); (*env)->ReleaseStringUTFChars(env, jfile_path, file_path); @@ -317,7 +311,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1write_1file(JNIE jbyte* buff = (*env)->GetByteArrayElements(env, jbuff, NULL); GoSlice go_buff = {buff+src_offset, length, length}; - int written = gcf_write_file(sessionID, handleID, file_offset, go_buff); + int written = gcf_write_file(sessionID, handleID, (GoUint64) file_offset, go_buff); (*env)->ReleaseByteArrayElements(env, jbuff, buff, 0); @@ -331,7 +325,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1read_1file(JNIEn jbyte* buff = (*env)->GetByteArrayElements(env, jbuff, NULL); GoSlice go_buff = {buff+dst_offset, length, length}; - int read = gcf_read_file(sessionID, handleID, file_offset, go_buff); + int read = gcf_read_file(sessionID, handleID, (GoUint64) file_offset, go_buff); (*env)->ReleaseByteArrayElements(env, jbuff, buff, 0); return read; @@ -345,7 +339,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1truncate(JNIEnv const char* path = (*env)->GetStringUTFChars(env, jpath, NULL); GoString go_path = {path, strlen(path)}; - GoUint8 result = gcf_truncate(sessionID, go_path, offset); + GoUint8 result = gcf_truncate(sessionID, go_path, (GoUint64) offset); (*env)->ReleaseStringUTFChars(env, jpath, path); return result; @@ -377,7 +371,7 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1mkdir(JNIEnv *en const char* dir_path = (*env)->GetStringUTFChars(env, jdir_path, NULL); GoString go_dir_path = {dir_path, strlen(dir_path)}; - GoUint8 result = gcf_mkdir(sessionID, go_dir_path, mode); + GoUint8 result = gcf_mkdir(sessionID, go_dir_path, (GoUint32) mode); (*env)->ReleaseStringUTFChars(env, jdir_path, dir_path); diff --git a/app/src/main/res/drawable/icon_decrypt.xml b/app/src/main/res/drawable/icon_decrypt.xml deleted file mode 100644 index af00ff0..0000000 --- a/app/src/main/res/drawable/icon_decrypt.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_lock.xml b/app/src/main/res/drawable/icon_lock.xml new file mode 100644 index 0000000..6c6b260 --- /dev/null +++ b/app/src/main/res/drawable/icon_lock.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/icon_lock_open.xml b/app/src/main/res/drawable/icon_lock_open.xml new file mode 100644 index 0000000..b200f49 --- /dev/null +++ b/app/src/main/res/drawable/icon_lock_open.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/adapter_volume.xml b/app/src/main/res/layout/adapter_volume.xml index f2b182d..6a658e1 100644 --- a/app/src/main/res/layout/adapter_volume.xml +++ b/app/src/main/res/layout/adapter_volume.xml @@ -8,21 +8,23 @@ + tools:ignore="UselessParent" + android:paddingEnd="4dp"> + android:layout_height="50dp" + android:src="@drawable/icon_volume"/> + android:layout_toStartOf="@id/layout_icons"> - + + + + + + + diff --git a/app/src/main/res/menu/explorer.xml b/app/src/main/res/menu/explorer.xml index 81f0937..1e06910 100644 --- a/app/src/main/res/menu/explorer.xml +++ b/app/src/main/res/menu/explorer.xml @@ -30,9 +30,8 @@ + + + + + + + + إنشاء مجلد مجلد فارغ تحذير ! - هل تريد إغلاق المجلد المشفر ? حسنا إلغاء اسم المجلد: diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 616995a..c29d311 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -11,7 +11,6 @@ Crear carpeta Directorio vacío ¡Advertencia! - ¿Estás seguro de que quieres cerrar este volumen? Aceptar Cancelar Nombre de la carpeta: diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 298e2d2..776d40d 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -11,7 +11,6 @@ Criar pasta Pasta vazia Aviso! - Tem certeza que quer fechar este volume? OK Cancelar Nome da pasta: diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a64866c..ea20ff6 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -10,7 +10,6 @@ Создать папку Пусто Предупреждение! - Закрыть том? Отмена Имя папки: Ошибка diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 91d5f79..1d9b4a7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,7 +11,7 @@ Create folder Directory Empty Warning ! - Are you sure you want to close this volume ? + Are you sure you want to lock this volume ? OK Cancel Folder Name: @@ -253,4 +253,7 @@ Remember volume Open volume Please choose an existing volume + Volume unlocked + Lock volume + Lock diff --git a/app/src/main/res/xml/unsafe_features_preferences.xml b/app/src/main/res/xml/unsafe_features_preferences.xml index b7c45be..38d6e34 100644 --- a/app/src/main/res/xml/unsafe_features_preferences.xml +++ b/app/src/main/res/xml/unsafe_features_preferences.xml @@ -15,7 +15,7 @@ diff --git a/build.gradle b/build.gradle index 5e6d12b..900ee6c 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' + classpath 'com.android.tools.build:gradle:7.4.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } }