Handle simultaneous file operations & Folders reorganisation

This commit is contained in:
Matéo Duparc 2020-12-31 13:15:13 +01:00
parent 0f4d2b057b
commit 0a3cb8903f
Signed by: hardcoresushi
GPG Key ID: 007F84120107191E
17 changed files with 134 additions and 98 deletions

View File

@ -86,10 +86,10 @@
android:name=".file_viewers.TextEditor" android:name=".file_viewers.TextEditor"
android:configChanges="screenSize|orientation" /> android:configChanges="screenSize|orientation" />
<service android:name=".FileOperationService" android:exported="false"/> <service android:name=".file_operations.FileOperationService" android:exported="false"/>
<provider <provider
android:name=".provider.RestrictedFileProvider" android:name=".content_providers.RestrictedFileProvider"
android:authorities="${applicationId}.temporary_provider" android:authorities="${applicationId}.temporary_provider"
android:exported="true" android:exported="true"
android:writePermission="${applicationId}.WRITE_TEMPORARY_STORAGE" /> android:writePermission="${applicationId}.WRITE_TEMPORARY_STORAGE" />

View File

@ -28,8 +28,7 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_camera.* import kotlinx.android.synthetic.main.activity_camera.*
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
import sushi.hardcore.droidfs.provider.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume
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

View File

@ -1,9 +1,9 @@
package sushi.hardcore.droidfs.util package sushi.hardcore.droidfs
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.explorers.ExplorerElement import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.PathUtils
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.InputStream import java.io.InputStream
@ -47,70 +47,100 @@ class GocryptfsVolume(var sessionID: Int) {
} }
fun close() { fun close() {
native_close(sessionID) synchronized(this){
native_close(sessionID)
}
} }
fun isClosed(): Boolean { fun isClosed(): Boolean {
return native_is_closed(sessionID) synchronized(this){
return native_is_closed(sessionID)
}
} }
fun listDir(dir_path: String): MutableList<ExplorerElement> { fun listDir(dir_path: String): MutableList<ExplorerElement> {
return native_list_dir(sessionID, dir_path) synchronized(this){
return native_list_dir(sessionID, dir_path)
}
} }
fun mkdir(dir_path: String): Boolean { fun mkdir(dir_path: String): Boolean {
return native_mkdir(sessionID, dir_path) synchronized(this){
return native_mkdir(sessionID, dir_path)
}
} }
fun rmdir(dir_path: String): Boolean { fun rmdir(dir_path: String): Boolean {
return native_rmdir(sessionID, dir_path) synchronized(this){
return native_rmdir(sessionID, dir_path)
}
} }
fun removeFile(file_path: String): Boolean { fun removeFile(file_path: String): Boolean {
return native_remove_file(sessionID, file_path) synchronized(this){
return native_remove_file(sessionID, file_path)
}
} }
fun pathExists(file_path: String): Boolean { fun pathExists(file_path: String): Boolean {
return native_path_exists(sessionID, file_path) synchronized(this){
return native_path_exists(sessionID, file_path)
}
} }
fun getSize(file_path: String): Long { fun getSize(file_path: String): Long {
return native_get_size(sessionID, file_path) synchronized(this){
return native_get_size(sessionID, file_path)
}
} }
fun closeFile(handleID: Int) { fun closeFile(handleID: Int) {
native_close_file(sessionID, handleID) synchronized(this){
native_close_file(sessionID, handleID)
}
} }
fun openReadMode(file_path: String): Int { fun openReadMode(file_path: String): Int {
return native_open_read_mode(sessionID, file_path) synchronized(this){
return native_open_read_mode(sessionID, file_path)
}
} }
fun openWriteMode(file_path: String): Int { fun openWriteMode(file_path: String): Int {
return native_open_write_mode(sessionID, file_path) synchronized(this){
return native_open_write_mode(sessionID, file_path)
}
} }
fun readFile(handleID: Int, offset: Long, buff: ByteArray): Int { fun readFile(handleID: Int, offset: Long, buff: ByteArray): Int {
return native_read_file(sessionID, handleID, offset, buff) synchronized(this){
return native_read_file(sessionID, handleID, offset, buff)
}
} }
fun writeFile(handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int { fun writeFile(handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int {
return native_write_file(sessionID, handleID, offset, buff, buff_size) synchronized(this){
return native_write_file(sessionID, handleID, offset, buff, buff_size)
}
} }
fun truncate(file_path: String, offset: Long): Boolean { fun truncate(file_path: String, offset: Long): Boolean {
return native_truncate(sessionID, file_path, offset) synchronized(this) {
return native_truncate(sessionID, file_path, offset)
}
} }
fun rename(old_path: String, new_path: String): Boolean { fun rename(old_path: String, new_path: String): Boolean {
return native_rename(sessionID, old_path, new_path) synchronized(this) {
return native_rename(sessionID, old_path, new_path)
}
} }
fun exportFile(handleID: Int, os: OutputStream): Boolean { fun exportFile(handleID: Int, os: OutputStream): Boolean {
var offset: Long = 0 var offset: Long = 0
val ioBuffer = ByteArray(DefaultBS) val ioBuffer = ByteArray(DefaultBS)
var length: Int var length: Int
while (native_read_file(sessionID, handleID, offset, ioBuffer).also { length = it } > 0){ while (readFile(handleID, offset, ioBuffer).also { length = it } > 0){
os.write(ioBuffer, 0, length) os.write(ioBuffer, 0, length)
offset += length.toLong() offset += length.toLong()
} }
@ -145,7 +175,7 @@ class GocryptfsVolume(var sessionID: Int) {
val ioBuffer = ByteArray(DefaultBS) val ioBuffer = ByteArray(DefaultBS)
var length: Int var length: Int
while (inputStream.read(ioBuffer).also { length = it } > 0) { while (inputStream.read(ioBuffer).also { length = it } > 0) {
val written = native_write_file(sessionID, handleID, offset, ioBuffer, length).toLong() val written = writeFile(handleID, offset, ioBuffer, length).toLong()
if (written == length.toLong()) { if (written == length.toLong()) {
offset += written offset += written
} else { } else {
@ -153,7 +183,7 @@ class GocryptfsVolume(var sessionID: Int) {
return false return false
} }
} }
native_close_file(sessionID, handleID) closeFile(handleID)
inputStream.close() inputStream.close()
return true return true
} }

View File

@ -1,10 +1,9 @@
package sushi.hardcore.droidfs.util package sushi.hardcore.droidfs
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
abstract class LoadingTask(val activity: AppCompatActivity, loadingMessageResId: Int) { abstract class LoadingTask(val activity: AppCompatActivity, loadingMessageResId: Int) {

View File

@ -17,7 +17,7 @@ import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
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
import sushi.hardcore.droidfs.provider.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.util.* import sushi.hardcore.droidfs.util.*
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File import java.io.File

View File

@ -1,12 +1,13 @@
package sushi.hardcore.droidfs.util package sushi.hardcore.droidfs.content_providers
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.LoadingTask
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.provider.RestrictedFileProvider
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.File import java.io.File

View File

@ -1,4 +1,4 @@
package sushi.hardcore.droidfs.provider package sushi.hardcore.droidfs.content_providers
import android.content.ContentProvider import android.content.ContentProvider
import android.content.ContentValues import android.content.ContentValues

View File

@ -26,7 +26,7 @@ import sushi.hardcore.droidfs.ConstValues.Companion.isAudio
import sushi.hardcore.droidfs.ConstValues.Companion.isImage import sushi.hardcore.droidfs.ConstValues.Companion.isImage
import sushi.hardcore.droidfs.ConstValues.Companion.isText import sushi.hardcore.droidfs.ConstValues.Companion.isText
import sushi.hardcore.droidfs.ConstValues.Companion.isVideo import sushi.hardcore.droidfs.ConstValues.Companion.isVideo
import sushi.hardcore.droidfs.FileOperationService import sushi.hardcore.droidfs.file_operations.FileOperationService
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
import sushi.hardcore.droidfs.adapters.ExplorerElementAdapter import sushi.hardcore.droidfs.adapters.ExplorerElementAdapter
@ -36,9 +36,9 @@ import sushi.hardcore.droidfs.file_viewers.AudioPlayer
import sushi.hardcore.droidfs.file_viewers.ImageViewer import sushi.hardcore.droidfs.file_viewers.ImageViewer
import sushi.hardcore.droidfs.file_viewers.TextEditor import sushi.hardcore.droidfs.file_viewers.TextEditor
import sushi.hardcore.droidfs.file_viewers.VideoPlayer import sushi.hardcore.droidfs.file_viewers.VideoPlayer
import sushi.hardcore.droidfs.provider.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.util.ExternalProvider import sushi.hardcore.droidfs.content_providers.ExternalProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder

View File

@ -14,8 +14,8 @@ 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.file_operations.OperationFile import sushi.hardcore.droidfs.file_operations.OperationFile
import sushi.hardcore.droidfs.util.ExternalProvider import sushi.hardcore.droidfs.content_providers.ExternalProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
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.File import java.io.File

View File

@ -5,7 +5,7 @@ import android.content.Intent
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import java.util.* import java.util.*

View File

@ -0,0 +1,5 @@
package sushi.hardcore.droidfs.file_operations
import android.app.Notification
class FileOperationNotification(val notificationBuilder: Notification.Builder, val notificationId: Int)

View File

@ -1,4 +1,4 @@
package sushi.hardcore.droidfs package sushi.hardcore.droidfs.file_operations
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
@ -9,24 +9,23 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.* import android.os.*
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.explorers.ExplorerElement import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.file_operations.OperationFile import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.util.GocryptfsVolume
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.util.Wiper import sushi.hardcore.droidfs.util.Wiper
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
class FileOperationService : Service() { class FileOperationService : Service() {
companion object { companion object {
const val NOTIFICATION_ID = 1
const val NOTIFICATION_CHANNEL_ID = "FileOperations" const val NOTIFICATION_CHANNEL_ID = "FileOperations"
} }
private val binder = LocalBinder() private val binder = LocalBinder()
private lateinit var gocryptfsVolume: GocryptfsVolume private lateinit var gocryptfsVolume: GocryptfsVolume
private lateinit var notificationManager: NotificationManager private lateinit var notificationManager: NotificationManager
private var lastNotificationId = 0
inner class LocalBinder : Binder() { inner class LocalBinder : Binder() {
fun getService(): FileOperationService = this@FileOperationService fun getService(): FileOperationService = this@FileOperationService
@ -39,7 +38,7 @@ class FileOperationService : Service() {
return binder return binder
} }
private fun showNotification(message: String, total: Int): Notification.Builder { private fun showNotification(message: Int, total: Int): FileOperationNotification {
if (!::notificationManager.isInitialized){ if (!::notificationManager.isInitialized){
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
} }
@ -50,22 +49,26 @@ class FileOperationService : Service() {
} else { } else {
Notification.Builder(this) Notification.Builder(this)
} }
notificationBuilder.setOngoing(true) notificationBuilder
.setContentTitle(getString(R.string.file_op_notification_title)) .setOngoing(true)
.setContentText(message) .setContentTitle(getString(message))
.setContentText("0/$total")
.setSmallIcon(R.mipmap.icon_launcher) .setSmallIcon(R.mipmap.icon_launcher)
.setProgress(total, 0, false) .setProgress(total, 0, false)
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()) ++lastNotificationId
return notificationBuilder notificationManager.notify(lastNotificationId, notificationBuilder.build())
return FileOperationNotification(notificationBuilder, lastNotificationId)
} }
private fun updateNotificationProgress(notificationBuilder: Notification.Builder, progress: Int, total: Int){ private fun updateNotificationProgress(notification: FileOperationNotification, progress: Int, total: Int){
notificationBuilder.setProgress(total, progress, false) notification.notificationBuilder
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()) .setProgress(total, progress, false)
.setContentText("$progress/$total")
notificationManager.notify(notification.notificationId, notification.notificationBuilder.build())
} }
private fun cancelNotification(){ private fun cancelNotification(notification: FileOperationNotification){
notificationManager.cancel(NOTIFICATION_ID) notificationManager.cancel(notification.notificationId)
} }
private fun copyFile(srcPath: String, dstPath: String, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume): Boolean { private fun copyFile(srcPath: String, dstPath: String, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume): Boolean {
@ -99,7 +102,7 @@ class FileOperationService : Service() {
fun copyElements(items: ArrayList<OperationFile>, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume, callback: (String?) -> Unit){ fun copyElements(items: ArrayList<OperationFile>, remoteGocryptfsVolume: GocryptfsVolume = gocryptfsVolume, callback: (String?) -> Unit){
Thread { Thread {
val notificationBuilder = showNotification(getString(R.string.file_op_copy_msg), items.size) val notification = showNotification(R.string.file_op_copy_msg, items.size)
var failedItem: String? = null var failedItem: String? = null
for (i in 0 until items.size){ for (i in 0 until items.size){
if (items[i].explorerElement.isDirectory){ if (items[i].explorerElement.isDirectory){
@ -114,19 +117,19 @@ class FileOperationService : Service() {
} }
} }
if (failedItem == null){ if (failedItem == null){
updateNotificationProgress(notificationBuilder, i, items.size) updateNotificationProgress(notification, i, items.size)
} else { } else {
break break
} }
} }
cancelNotification() cancelNotification(notification)
callback(failedItem) callback(failedItem)
}.start() }.start()
} }
fun moveElements(items: ArrayList<OperationFile>, callback: (String?) -> Unit){ fun moveElements(items: ArrayList<OperationFile>, callback: (String?) -> Unit){
Thread { Thread {
val notificationBuilder = showNotification(getString(R.string.file_op_move_msg), items.size) val notification = showNotification(R.string.file_op_move_msg, items.size)
val mergedFolders = ArrayList<String>() val mergedFolders = ArrayList<String>()
var failedItem: String? = null var failedItem: String? = null
for (i in 0 until items.size){ for (i in 0 until items.size){
@ -137,7 +140,7 @@ class FileOperationService : Service() {
failedItem = items[i].explorerElement.fullPath failedItem = items[i].explorerElement.fullPath
break break
} else { } else {
updateNotificationProgress(notificationBuilder, i, items.size) updateNotificationProgress(notification, i, items.size)
} }
} }
} }
@ -147,18 +150,18 @@ class FileOperationService : Service() {
failedItem = mergedFolders[i] failedItem = mergedFolders[i]
break break
} else { } else {
updateNotificationProgress(notificationBuilder, items.size-(mergedFolders.size-i), items.size) updateNotificationProgress(notification, items.size-(mergedFolders.size-i), items.size)
} }
} }
} }
cancelNotification() cancelNotification(notification)
callback(failedItem) callback(failedItem)
}.start() }.start()
} }
fun importFilesFromUris(items: ArrayList<OperationFile>, uris: List<Uri>, callback: (String?) -> Unit){ fun importFilesFromUris(items: ArrayList<OperationFile>, uris: List<Uri>, callback: (String?) -> Unit){
Thread { Thread {
val notificationBuilder = showNotification(getString(R.string.file_op_import_msg), items.size) val notification = showNotification(R.string.file_op_import_msg, items.size)
var failedIndex = -1 var failedIndex = -1
for (i in 0 until items.size) { for (i in 0 until items.size) {
try { try {
@ -169,15 +172,15 @@ class FileOperationService : Service() {
failedIndex = i failedIndex = i
} }
if (failedIndex == -1) { if (failedIndex == -1) {
updateNotificationProgress(notificationBuilder, i, items.size) updateNotificationProgress(notification, i, items.size)
} else { } else {
cancelNotification() cancelNotification(notification)
callback(uris[failedIndex].toString()) callback(uris[failedIndex].toString())
break break
} }
} }
if (failedIndex == -1){ if (failedIndex == -1){
cancelNotification() cancelNotification(notification)
callback(null) callback(null)
} }
}.start() }.start()
@ -185,17 +188,17 @@ class FileOperationService : Service() {
fun wipeUris(uris: List<Uri>, callback: (String?) -> Unit){ fun wipeUris(uris: List<Uri>, callback: (String?) -> Unit){
Thread { Thread {
val notificationBuilder = showNotification(getString(R.string.file_op_wiping_msg), uris.size) val notification = showNotification(R.string.file_op_wiping_msg, uris.size)
var errorMsg: String? = null var errorMsg: String? = null
for (i in uris.indices) { for (i in uris.indices) {
errorMsg = Wiper.wipe(this, uris[i]) errorMsg = Wiper.wipe(this, uris[i])
if (errorMsg == null) { if (errorMsg == null) {
updateNotificationProgress(notificationBuilder, i, uris.size) updateNotificationProgress(notification, i, uris.size)
} else { } else {
break break
} }
} }
cancelNotification() cancelNotification(notification)
callback(errorMsg) callback(errorMsg)
}.start() }.start()
} }
@ -234,7 +237,7 @@ class FileOperationService : Service() {
Thread { Thread {
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION) contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
DocumentFile.fromTreeUri(this, uri)?.let { treeDocumentFile -> DocumentFile.fromTreeUri(this, uri)?.let { treeDocumentFile ->
val notificationBuilder = showNotification(getString(R.string.file_op_export_msg), items.size) val notification = showNotification(R.string.file_op_export_msg, items.size)
var failedItem: String? = null var failedItem: String? = null
for (i in items.indices) { for (i in items.indices) {
failedItem = if (items[i].isDirectory) { failedItem = if (items[i].isDirectory) {
@ -243,12 +246,12 @@ class FileOperationService : Service() {
if (exportFileInto(items[i].fullPath, treeDocumentFile)) null else items[i].fullPath if (exportFileInto(items[i].fullPath, treeDocumentFile)) null else items[i].fullPath
} }
if (failedItem == null) { if (failedItem == null) {
updateNotificationProgress(notificationBuilder, i, items.size) updateNotificationProgress(notification, i, items.size)
} else { } else {
break break
} }
} }
cancelNotification() cancelNotification(notification)
callback(failedItem) callback(failedItem)
} }
}.start() }.start()

View File

@ -4,8 +4,8 @@ import android.os.Bundle
import android.view.View import android.view.View
import sushi.hardcore.droidfs.BaseActivity import sushi.hardcore.droidfs.BaseActivity
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.provider.RestrictedFileProvider import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
abstract class FileViewerActivity: BaseActivity() { abstract class FileViewerActivity: BaseActivity() {

View File

@ -3,7 +3,7 @@ package sushi.hardcore.droidfs.file_viewers
import android.net.Uri import android.net.Uri
import com.google.android.exoplayer2.upstream.* import com.google.android.exoplayer2.upstream.*
import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.min import kotlin.math.min

View File

@ -9,7 +9,7 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.GocryptfsVolume
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.File import java.io.File

View File

@ -31,7 +31,7 @@ void jbyteArray_to_unsignedCharArray(const jbyte* src, unsigned char* dst, const
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_00024Companion_createVolume(JNIEnv *env, jclass clazz, Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv *env, jclass clazz,
jstring jroot_cipher_dir, jcharArray jpassword, jstring jroot_cipher_dir, jcharArray jpassword,
jint logN, jint logN,
jstring jcreator) { jstring jcreator) {
@ -55,7 +55,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_00024Companion_createVolume(JNI
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_00024Companion_init(JNIEnv *env, jobject clazz, Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_init(JNIEnv *env, jobject clazz,
jstring jroot_cipher_dir, jstring jroot_cipher_dir,
jcharArray jpassword, jcharArray jpassword,
jbyteArray jgiven_hash, jbyteArray jgiven_hash,
@ -127,13 +127,13 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_00024Companion_init(JNIEnv *env
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1is_1closed(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1is_1closed(JNIEnv *env, jobject thiz,
jint sessionID) { jint sessionID) {
return gcf_is_closed(sessionID); return gcf_is_closed(sessionID);
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_00024Companion_changePassword(JNIEnv *env, jclass clazz, Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_changePassword(JNIEnv *env, jclass clazz,
jstring jroot_cipher_dir, jstring jroot_cipher_dir,
jcharArray jold_password, jcharArray jold_password,
jbyteArray jgiven_hash, jbyteArray jgiven_hash,
@ -215,12 +215,12 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_00024Companion_changePassword(J
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1close(JNIEnv *env, jobject thiz, jint sessionID) { Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1close(JNIEnv *env, jobject thiz, jint sessionID) {
gcf_close(sessionID); gcf_close(sessionID);
} }
JNIEXPORT jobject JNICALL JNIEXPORT jobject JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1list_1dir(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1list_1dir(JNIEnv *env, jobject thiz,
jint sessionID, jstring jplain_dir) { jint sessionID, jstring jplain_dir) {
const char* plain_dir = (*env)->GetStringUTFChars(env, jplain_dir, NULL); const char* plain_dir = (*env)->GetStringUTFChars(env, jplain_dir, NULL);
const size_t plain_dir_len = strlen(plain_dir); const size_t plain_dir_len = strlen(plain_dir);
@ -228,14 +228,14 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1list_1dir(JNIEnv *env,
struct gcf_list_dir_return elements = gcf_list_dir(sessionID, go_plain_dir); struct gcf_list_dir_return elements = gcf_list_dir(sessionID, go_plain_dir);
jclass java_util_ArrayList = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "java/util/ArrayList")); jclass java_ArrayList = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "java/util/ArrayList"));
jmethodID java_util_ArrayList_init = (*env)->GetMethodID(env, java_util_ArrayList, "<init>", "(I)V"); jmethodID java_ArrayList_init = (*env)->GetMethodID(env, java_ArrayList, "<init>", "(I)V");
jmethodID java_util_ArrayList_add = (*env)->GetMethodID(env, java_util_ArrayList, "add", "(Ljava/lang/Object;)Z"); jmethodID java_ArrayList_add = (*env)->GetMethodID(env, java_ArrayList, "add", "(Ljava/lang/Object;)Z");
jclass classExplorerElement = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "sushi/hardcore/droidfs/explorers/ExplorerElement")); jclass classExplorerElement = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "sushi/hardcore/droidfs/explorers/ExplorerElement"));
jmethodID classExplorerElement_init = (*env)->GetMethodID(env, classExplorerElement, "<init>", "(Ljava/lang/String;SJJLjava/lang/String;)V"); jmethodID classExplorerElement_init = (*env)->GetMethodID(env, classExplorerElement, "<init>", "(Ljava/lang/String;SJJLjava/lang/String;)V");
jobject element_list = (*env)->NewObject(env, java_util_ArrayList, java_util_ArrayList_init, elements.r2); jobject element_list = (*env)->NewObject(env, java_ArrayList, java_ArrayList_init, elements.r2);
unsigned int c = 0; unsigned int c = 0;
for (unsigned int i=0; i<elements.r2; ++i){ for (unsigned int i=0; i<elements.r2; ++i){
const char* name = &(elements.r0[c]); const char* name = &(elements.r0[c]);
@ -261,7 +261,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1list_1dir(JNIEnv *env,
} }
jstring jname = (*env)->NewStringUTF(env, name); jstring jname = (*env)->NewStringUTF(env, name);
jobject explorerElement = (*env)->NewObject(env, classExplorerElement, classExplorerElement_init, jname, type, (long long)attrs.r0, attrs.r1, jplain_dir); jobject explorerElement = (*env)->NewObject(env, classExplorerElement, classExplorerElement_init, jname, type, (long long)attrs.r0, attrs.r1, jplain_dir);
(*env)->CallBooleanMethod(env, element_list, java_util_ArrayList_add, explorerElement); (*env)->CallBooleanMethod(env, element_list, java_ArrayList_add, explorerElement);
c += name_len+1; c += name_len+1;
} }
@ -274,7 +274,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1list_1dir(JNIEnv *env,
} }
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1get_1size(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1get_1size(JNIEnv *env, jobject thiz,
jint sessionID, jstring jfile_path) { jint sessionID, jstring jfile_path) {
const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL);
GoString go_file_path = {file_path, strlen(file_path)}; GoString go_file_path = {file_path, strlen(file_path)};
@ -287,7 +287,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1get_1size(JNIEnv *env,
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1path_1exists(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1path_1exists(JNIEnv *env, jobject thiz,
jint sessionID, jint sessionID,
jstring jfile_path) { jstring jfile_path) {
const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL);
@ -301,7 +301,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1path_1exists(JNIEnv *en
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1open_1read_1mode(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1open_1read_1mode(JNIEnv *env, jobject thiz,
jint sessionID, jint sessionID,
jstring jfile_path) { jstring jfile_path) {
const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL);
@ -315,7 +315,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1open_1read_1mode(JNIEnv
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1open_1write_1mode(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1open_1write_1mode(JNIEnv *env, jobject thiz,
jint sessionID, jint sessionID,
jstring jfile_path) { jstring jfile_path) {
const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL);
@ -329,7 +329,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1open_1write_1mode(JNIEn
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1write_1file(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1write_1file(JNIEnv *env, jobject thiz,
jint sessionID, jint handleID, jlong offset, jint sessionID, jint handleID, jlong offset,
jbyteArray jbuff, jint buff_size) { jbyteArray jbuff, jint buff_size) {
jbyte* buff = (*env)->GetByteArrayElements(env, jbuff, NULL); jbyte* buff = (*env)->GetByteArrayElements(env, jbuff, NULL);
@ -343,7 +343,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1write_1file(JNIEnv *env
} }
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1read_1file(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1read_1file(JNIEnv *env, jobject thiz,
jint sessionID, jint handleID, jlong offset, jint sessionID, jint handleID, jlong offset,
jbyteArray jbuff) { jbyteArray jbuff) {
const size_t buff_size = (*env)->GetArrayLength(env, jbuff); const size_t buff_size = (*env)->GetArrayLength(env, jbuff);
@ -360,7 +360,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1read_1file(JNIEnv *env,
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1truncate(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1truncate(JNIEnv *env, jobject thiz,
jint sessionID, jint sessionID,
jstring jfile_path, jlong offset) { jstring jfile_path, jlong offset) {
const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL);
@ -374,14 +374,14 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1truncate(JNIEnv *env, j
} }
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1close_1file(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1close_1file(JNIEnv *env, jobject thiz,
jint sessionID, jint sessionID,
jint handleID) { jint handleID) {
gcf_close_file(sessionID, handleID); gcf_close_file(sessionID, handleID);
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1remove_1file(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1remove_1file(JNIEnv *env, jobject thiz,
jint sessionID, jstring jfile_path) { jint sessionID, jstring jfile_path) {
const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL); const char* file_path = (*env)->GetStringUTFChars(env, jfile_path, NULL);
GoString go_file_path = {file_path, strlen(file_path)}; GoString go_file_path = {file_path, strlen(file_path)};
@ -394,7 +394,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1remove_1file(JNIEnv *en
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1mkdir(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1mkdir(JNIEnv *env, jobject thiz,
jint sessionID, jstring jdir_path) { jint sessionID, jstring jdir_path) {
const char* dir_path = (*env)->GetStringUTFChars(env, jdir_path, NULL); const char* dir_path = (*env)->GetStringUTFChars(env, jdir_path, NULL);
GoString go_dir_path = {dir_path, strlen(dir_path)}; GoString go_dir_path = {dir_path, strlen(dir_path)};
@ -407,7 +407,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1mkdir(JNIEnv *env, jobj
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1rmdir(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1rmdir(JNIEnv *env, jobject thiz,
jint sessionID, jstring jdir_path) { jint sessionID, jstring jdir_path) {
const char* dir_path = (*env)->GetStringUTFChars(env, jdir_path, NULL); const char* dir_path = (*env)->GetStringUTFChars(env, jdir_path, NULL);
GoString go_dir_path = {dir_path, strlen(dir_path)}; GoString go_dir_path = {dir_path, strlen(dir_path)};
@ -420,7 +420,7 @@ Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1rmdir(JNIEnv *env, jobj
} }
JNIEXPORT jboolean JNICALL JNIEXPORT jboolean JNICALL
Java_sushi_hardcore_droidfs_util_GocryptfsVolume_native_1rename(JNIEnv *env, jobject thiz, Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1rename(JNIEnv *env, jobject thiz,
jint sessionID, jstring jold_path, jint sessionID, jstring jold_path,
jstring jnew_path) { jstring jnew_path) {
const char* old_path = (*env)->GetStringUTFChars(env, jold_path, NULL); const char* old_path = (*env)->GetStringUTFChars(env, jold_path, NULL);

View File

@ -187,7 +187,6 @@
<string name="camera_perm_needed">Camera permission is needed to take photo.</string> <string name="camera_perm_needed">Camera permission is needed to take photo.</string>
<string name="choose_resolution">Choose a resolution</string> <string name="choose_resolution">Choose a resolution</string>
<string name="file_operations">File Operations</string> <string name="file_operations">File Operations</string>
<string name="file_op_notification_title">File Operations running…</string>
<string name="file_op_copy_msg">Copying files…</string> <string name="file_op_copy_msg">Copying files…</string>
<string name="file_op_import_msg">Importing files…</string> <string name="file_op_import_msg">Importing files…</string>
<string name="file_op_export_msg">Exporting files…</string> <string name="file_op_export_msg">Exporting files…</string>