Compare commits
2 Commits
a4db2740a1
...
9f8b653cc7
Author | SHA1 | Date | |
---|---|---|---|
9f8b653cc7 | |||
fcd382ca8b |
@ -45,25 +45,25 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "androidx.core:core-ktx:1.3.2"
|
||||
implementation "androidx.appcompat:appcompat:1.2.0"
|
||||
implementation "androidx.core:core-ktx:1.5.0"
|
||||
implementation "androidx.appcompat:appcompat:1.3.0"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
|
||||
|
||||
implementation "androidx.sqlite:sqlite-ktx:2.1.0"
|
||||
implementation "androidx.preference:preference-ktx:1.1.1"
|
||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
|
||||
implementation "com.jaredrummler:cyanea:1.0.2"
|
||||
implementation "com.github.bumptech.glide:glide:4.11.0"
|
||||
implementation "com.github.bumptech.glide:glide:4.12.0"
|
||||
implementation "androidx.biometric:biometric:1.1.0"
|
||||
|
||||
def exoplayer_version = "2.13.2"
|
||||
def exoplayer_version = "2.14.0"
|
||||
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
|
||||
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
|
||||
|
||||
def camerax_v1 = "1.1.0-alpha03"
|
||||
def camerax_v1 = "1.1.0-alpha05"
|
||||
implementation "androidx.camera:camera-camera2:$camerax_v1"
|
||||
implementation "androidx.camera:camera-lifecycle:$camerax_v1"
|
||||
def camerax_v2 = "1.0.0-alpha23"
|
||||
def camerax_v2 = "1.0.0-alpha25"
|
||||
implementation "androidx.camera:camera-view:$camerax_v2"
|
||||
implementation "androidx.camera:camera-extensions:$camerax_v2"
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package sushi.hardcore.droidfs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
@ -14,15 +13,14 @@ import kotlinx.android.synthetic.main.activity_change_password.*
|
||||
import kotlinx.android.synthetic.main.checkboxes_section.*
|
||||
import kotlinx.android.synthetic.main.volume_path_section.*
|
||||
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
||||
import sushi.hardcore.droidfs.util.*
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class ChangePasswordActivity : VolumeActionActivity() {
|
||||
companion object {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
}
|
||||
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -80,35 +78,27 @@ class ChangePasswordActivity : VolumeActionActivity() {
|
||||
}
|
||||
|
||||
fun pickDirectory(view: View?) {
|
||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
||||
safePickDirectory()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data!!)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.change_pwd_on_sdcard_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
override fun onDirectoryPicked(uri: Uri) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(uri, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.change_pwd_on_sdcard_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package sushi.hardcore.droidfs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
@ -11,15 +11,13 @@ import kotlinx.android.synthetic.main.activity_create.*
|
||||
import kotlinx.android.synthetic.main.checkboxes_section.*
|
||||
import kotlinx.android.synthetic.main.volume_path_section.*
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
||||
import sushi.hardcore.droidfs.util.*
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class CreateActivity : VolumeActionActivity() {
|
||||
companion object {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
}
|
||||
private var sessionID = -1
|
||||
private var isStartingExplorer = false
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -44,35 +42,27 @@ class CreateActivity : VolumeActionActivity() {
|
||||
}
|
||||
|
||||
fun pickDirectory(view: View?) {
|
||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
||||
safePickDirectory()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data?.data != null) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(data.data!!)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.create_on_sdcard_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
override fun onDirectoryPicked(uri: Uri) {
|
||||
if (PathUtils.isTreeUriOnPrimaryStorage(uri)){
|
||||
val path = PathUtils.getFullPathFromTreeUri(uri, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.warning)
|
||||
.setMessage(R.string.create_on_sdcard_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package sushi.hardcore.droidfs
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
@ -14,23 +14,23 @@ import kotlinx.android.synthetic.main.activity_open.*
|
||||
import kotlinx.android.synthetic.main.checkboxes_section.*
|
||||
import kotlinx.android.synthetic.main.volume_path_section.*
|
||||
import sushi.hardcore.droidfs.adapters.SavedVolumesAdapter
|
||||
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivity
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivityPick
|
||||
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
|
||||
import sushi.hardcore.droidfs.util.*
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class OpenActivity : VolumeActionActivity() {
|
||||
companion object {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
}
|
||||
private lateinit var savedVolumesAdapter: SavedVolumesAdapter
|
||||
private var sessionID = -1
|
||||
private var isStartingActivity = false
|
||||
private var isFinishingIntentionally = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_open)
|
||||
@ -107,28 +107,20 @@ class OpenActivity : VolumeActionActivity() {
|
||||
}
|
||||
|
||||
fun pickDirectory(view: View?) {
|
||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
isStartingActivity = true
|
||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
||||
safePickDirectory()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (data?.data != null) {
|
||||
val path = PathUtils.getFullPathFromTreeUri(data.data, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onDirectoryPicked(uri: Uri) {
|
||||
val path = PathUtils.getFullPathFromTreeUri(uri, this)
|
||||
if (path != null){
|
||||
edit_volume_path.setText(path)
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.path_from_uri_null_error_msg)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
package sushi.hardcore.droidfs
|
||||
|
||||
import android.app.KeyguardManager
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyPermanentlyInvalidatedException
|
||||
@ -9,6 +11,7 @@ import android.security.keystore.KeyProperties
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricPrompt
|
||||
@ -23,10 +26,15 @@ import java.security.KeyStore
|
||||
import javax.crypto.*
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
|
||||
open class VolumeActionActivity : BaseActivity() {
|
||||
abstract class VolumeActionActivity : BaseActivity() {
|
||||
protected lateinit var currentVolumeName: String
|
||||
protected lateinit var currentVolumePath: String
|
||||
protected lateinit var volumeDatabase: VolumeDatabase
|
||||
protected val pickDirectory = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||
if (uri != null) {
|
||||
onDirectoryPicked(uri)
|
||||
}
|
||||
}
|
||||
private var usf_fingerprint = false
|
||||
private var biometricCanAuthenticateCode: Int = -1
|
||||
private lateinit var biometricManager: BiometricManager
|
||||
@ -48,6 +56,20 @@ open class VolumeActionActivity : BaseActivity() {
|
||||
private const val GCM_TAG_LEN = 128
|
||||
}
|
||||
|
||||
protected abstract fun onDirectoryPicked(uri: Uri)
|
||||
|
||||
protected fun safePickDirectory() {
|
||||
try {
|
||||
pickDirectory.launch(null)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(R.string.open_tree_failed)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun setupFingerprintStuff(){
|
||||
originalHiddenVolumeSectionLayoutParams = hidden_volume_section.layoutParams as LinearLayout.LayoutParams
|
||||
originalNormalVolumeSectionLayoutParams = normal_volume_section.layoutParams as LinearLayout.LayoutParams
|
||||
@ -137,7 +159,7 @@ open class VolumeActionActivity : BaseActivity() {
|
||||
return if (!keyguardManager.isKeyguardSecure) {
|
||||
1
|
||||
} else {
|
||||
when (biometricManager.canAuthenticate()){
|
||||
when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)){
|
||||
BiometricManager.BIOMETRIC_SUCCESS -> 0
|
||||
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> 2
|
||||
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> 3
|
||||
@ -209,7 +231,7 @@ open class VolumeActionActivity : BaseActivity() {
|
||||
.setSubtitle(getString(R.string.encrypt_action_description))
|
||||
.setDescription(getString(R.string.fingerprint_instruction))
|
||||
.setNegativeButtonText(getString(R.string.cancel))
|
||||
.setDeviceCredentialAllowed(false)
|
||||
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
.setConfirmationRequired(false)
|
||||
.build()
|
||||
if (!isCipherReady){
|
||||
@ -233,7 +255,7 @@ open class VolumeActionActivity : BaseActivity() {
|
||||
.setSubtitle(getString(R.string.decrypt_action_description))
|
||||
.setDescription(getString(R.string.fingerprint_instruction))
|
||||
.setNegativeButtonText(getString(R.string.cancel))
|
||||
.setDeviceCredentialAllowed(false)
|
||||
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
|
||||
.setConfirmationRequired(false)
|
||||
.build()
|
||||
this.onPasswordDecrypted = onPasswordDecrypted
|
||||
|
@ -2,35 +2,148 @@ package sushi.hardcore.droidfs.explorers
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import sushi.hardcore.droidfs.CameraActivity
|
||||
import sushi.hardcore.droidfs.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.OpenActivity
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.adapters.IconTextDialogAdapter
|
||||
import sushi.hardcore.droidfs.file_operations.OperationFile
|
||||
import sushi.hardcore.droidfs.content_providers.ExternalProvider
|
||||
import sushi.hardcore.droidfs.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.file_operations.OperationFile
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
|
||||
import java.io.File
|
||||
|
||||
class ExplorerActivity : BaseExplorerActivity() {
|
||||
companion object {
|
||||
private const val PICK_DIRECTORY_REQUEST_CODE = 1
|
||||
private const val PICK_FILES_REQUEST_CODE = 2
|
||||
private const val PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE = 3
|
||||
private enum class ItemsActions {NONE, COPY, MOVE}
|
||||
}
|
||||
private var usf_decrypt = false
|
||||
private var usf_share = false
|
||||
private var currentItemAction = ItemsActions.NONE
|
||||
private val itemsToProcess = ArrayList<OperationFile>()
|
||||
private val pickFromOtherVolumes = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
result.data?.let { resultIntent ->
|
||||
val remoteSessionID = resultIntent.getIntExtra("sessionID", -1)
|
||||
val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
|
||||
val path = resultIntent.getStringExtra("path")
|
||||
val operationFiles = ArrayList<OperationFile>()
|
||||
if (path == null){ //multiples elements
|
||||
val paths = resultIntent.getStringArrayListExtra("paths")
|
||||
val types = resultIntent.getIntegerArrayListExtra("types")
|
||||
if (types != null && paths != null){
|
||||
for (i in paths.indices) {
|
||||
operationFiles.add(
|
||||
OperationFile.fromExplorerElement(
|
||||
ExplorerElement(File(paths[i]).name, types[i].toShort(), -1, -1, PathUtils.getParentPath(paths[i]))
|
||||
)
|
||||
)
|
||||
if (types[i] == 0){ //directory
|
||||
remoteGocryptfsVolume.recursiveMapFiles(paths[i]).forEach {
|
||||
operationFiles.add(OperationFile.fromExplorerElement(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
operationFiles.add(
|
||||
OperationFile.fromExplorerElement(
|
||||
ExplorerElement(File(path).name, 1, -1, -1, PathUtils.getParentPath(path))
|
||||
)
|
||||
)
|
||||
}
|
||||
if (operationFiles.size > 0){
|
||||
checkPathOverwrite(operationFiles, currentDirectoryPath) { items ->
|
||||
if (items == null) {
|
||||
remoteGocryptfsVolume.close()
|
||||
} else {
|
||||
fileOperationService.copyElements(items, remoteGocryptfsVolume){ failedItem ->
|
||||
runOnUiThread {
|
||||
if (failedItem == null){
|
||||
Toast.makeText(this, R.string.success_import, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
}
|
||||
remoteGocryptfsVolume.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
remoteGocryptfsVolume.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val pickFiles = registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris ->
|
||||
if (uris != null) {
|
||||
importFilesFromUris(uris){ failedItem ->
|
||||
if (failedItem == null){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_import)
|
||||
.setMessage("""
|
||||
${getString(R.string.success_import_msg)}
|
||||
${getString(R.string.ask_for_wipe)}
|
||||
""".trimIndent())
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
fileOperationService.wipeUris(uris) { errorMsg ->
|
||||
runOnUiThread {
|
||||
if (errorMsg == null){
|
||||
Toast.makeText(this, R.string.wipe_successful, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.wipe_failed, errorMsg))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
private val pickDirectory = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||
if (uri != null) {
|
||||
fileOperationService.exportFiles(uri, explorerAdapter.selectedItems.map { i -> explorerElements[i] }){ failedItem ->
|
||||
runOnUiThread {
|
||||
if (failedItem == null){
|
||||
Toast.makeText(this, R.string.success_export, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.export_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unselectAll()
|
||||
}
|
||||
|
||||
override fun init() {
|
||||
setContentView(R.layout.activity_explorer)
|
||||
usf_decrypt = sharedPrefs.getBoolean("usf_decrypt", false)
|
||||
@ -82,15 +195,11 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
intent.action = "pick"
|
||||
intent.putExtra("sessionID", gocryptfsVolume.sessionID)
|
||||
isStartingActivity = true
|
||||
startActivityForResult(intent, PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE)
|
||||
pickFromOtherVolumes.launch(intent)
|
||||
}
|
||||
"importFiles" -> {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
|
||||
intent.type = "*/*"
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
isStartingActivity = true
|
||||
startActivityForResult(intent, PICK_FILES_REQUEST_CODE)
|
||||
pickFiles.launch(arrayOf("*/*"))
|
||||
}
|
||||
"createFile" -> {
|
||||
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
|
||||
@ -132,136 +241,6 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == PICK_FILES_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val uris: MutableList<Uri> = ArrayList()
|
||||
val singleUri = data.data
|
||||
if (singleUri == null) { //multiples choices
|
||||
val clipData = data.clipData
|
||||
if (clipData != null){
|
||||
for (i in 0 until clipData.itemCount) {
|
||||
uris.add(clipData.getItemAt(i).uri)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uris.add(singleUri)
|
||||
}
|
||||
importFilesFromUris(uris){ failedItem ->
|
||||
if (failedItem == null){
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.success_import)
|
||||
.setMessage("""
|
||||
${getString(R.string.success_import_msg)}
|
||||
${getString(R.string.ask_for_wipe)}
|
||||
""".trimIndent())
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
fileOperationService.wipeUris(uris) { errorMsg ->
|
||||
runOnUiThread {
|
||||
if (errorMsg == null){
|
||||
Toast.makeText(this, R.string.wipe_successful, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.wipe_failed, errorMsg))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
}
|
||||
}
|
||||
} else if (requestCode == PICK_DIRECTORY_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
data.data?.let { uri ->
|
||||
fileOperationService.exportFiles(uri, explorerAdapter.selectedItems.map { i -> explorerElements[i] }){ failedItem ->
|
||||
runOnUiThread {
|
||||
if (failedItem == null){
|
||||
Toast.makeText(this, R.string.success_export, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.export_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
unselectAll()
|
||||
}
|
||||
}
|
||||
} else if (requestCode == PICK_OTHER_VOLUME_ITEMS_REQUEST_CODE) {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
val remoteSessionID = data.getIntExtra("sessionID", -1)
|
||||
val remoteGocryptfsVolume = GocryptfsVolume(remoteSessionID)
|
||||
val path = data.getStringExtra("path")
|
||||
val operationFiles = ArrayList<OperationFile>()
|
||||
if (path == null){ //multiples elements
|
||||
val paths = data.getStringArrayListExtra("paths")
|
||||
val types = data.getIntegerArrayListExtra("types")
|
||||
if (types != null && paths != null){
|
||||
for (i in paths.indices) {
|
||||
operationFiles.add(
|
||||
OperationFile.fromExplorerElement(
|
||||
ExplorerElement(File(paths[i]).name, types[i].toShort(), -1, -1, PathUtils.getParentPath(paths[i]))
|
||||
)
|
||||
)
|
||||
if (types[i] == 0){ //directory
|
||||
remoteGocryptfsVolume.recursiveMapFiles(paths[i]).forEach {
|
||||
operationFiles.add(OperationFile.fromExplorerElement(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
operationFiles.add(
|
||||
OperationFile.fromExplorerElement(
|
||||
ExplorerElement(File(path).name, 1, -1, -1, PathUtils.getParentPath(path))
|
||||
)
|
||||
)
|
||||
}
|
||||
if (operationFiles.size > 0){
|
||||
checkPathOverwrite(operationFiles, currentDirectoryPath) { items ->
|
||||
if (items == null) {
|
||||
remoteGocryptfsVolume.close()
|
||||
} else {
|
||||
fileOperationService.copyElements(items, remoteGocryptfsVolume){ failedItem ->
|
||||
runOnUiThread {
|
||||
if (failedItem == null){
|
||||
Toast.makeText(this, R.string.success_import, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ColoredAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error)
|
||||
.setMessage(getString(R.string.import_failed, failedItem))
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.show()
|
||||
}
|
||||
setCurrentPath(currentDirectoryPath)
|
||||
}
|
||||
remoteGocryptfsVolume.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
remoteGocryptfsVolume.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.explorer, menu)
|
||||
if (currentItemAction != ItemsActions.NONE) {
|
||||
@ -398,9 +377,8 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
true
|
||||
}
|
||||
R.id.decrypt -> {
|
||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
isStartingActivity = true
|
||||
startActivityForResult(i, PICK_DIRECTORY_REQUEST_CODE)
|
||||
pickDirectory.launch(null)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
|
@ -5,6 +5,7 @@ import com.google.android.exoplayer2.ExoPlaybackException
|
||||
import com.google.android.exoplayer2.MediaItem
|
||||
import com.google.android.exoplayer2.Player
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||
import com.google.android.exoplayer2.extractor.ExtractorsFactory
|
||||
import com.google.android.exoplayer2.extractor.flac.FlacExtractor
|
||||
import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor
|
||||
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor
|
||||
@ -31,7 +32,7 @@ abstract class MediaPlayer: FileViewerActivity() {
|
||||
|
||||
private fun createMediaSource(filePath: String): MediaSource {
|
||||
val dataSourceFactory = GocryptfsDataSource.Factory(gocryptfsVolume, filePath)
|
||||
return ProgressiveMediaSource.Factory(dataSourceFactory, { arrayOf(
|
||||
return ProgressiveMediaSource.Factory(dataSourceFactory, ExtractorsFactory { arrayOf(
|
||||
MatroskaExtractor(),
|
||||
Mp4Extractor(),
|
||||
Mp3Extractor(),
|
||||
@ -51,7 +52,7 @@ abstract class MediaPlayer: FileViewerActivity() {
|
||||
player.repeatMode = Player.REPEAT_MODE_ALL
|
||||
player.seekToDefaultPosition(currentPlaylistIndex)
|
||||
player.playWhenReady = true
|
||||
player.addListener(object : Player.EventListener{
|
||||
player.addListener(object : Player.Listener{
|
||||
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
|
||||
if (playbackState == Player.STATE_READY) {
|
||||
onPlayerReady()
|
||||
|
@ -8,7 +8,7 @@
|
||||
<com.google.android.exoplayer2.ui.PlayerView
|
||||
android:id="@+id/video_player"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
@ -194,4 +194,5 @@
|
||||
<string name="folders_first_summary">Show folders at the beginning of the list</string>
|
||||
<string name="auto_fit_title">Video player screen auto-rotation</string>
|
||||
<string name="auto_fit_summary">Auto-rotate the screen to fit video dimensions</string>
|
||||
<string name="open_tree_failed">No file explorer found. Please install one and retry.</string>
|
||||
</resources>
|
||||
|
@ -1,12 +1,12 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = "1.4.21"
|
||||
ext.kotlin_version = "1.5.10"
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||
classpath 'com.android.tools.build:gradle:4.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,7 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user