Compare commits

...

2 Commits

Author SHA1 Message Date
9f8b653cc7
Safe volume directory picking 2021-06-07 14:12:40 +02:00
fcd382ca8b
Update gradle dependencies 2021-06-07 13:23:11 +02:00
10 changed files with 223 additions and 249 deletions

View File

@ -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"
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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>

View File

@ -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>

View File

@ -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()
}
}