Merge pull request #103 from Myzel394/fix-100

Improve folder access test
This commit is contained in:
Myzel394 2024-04-20 22:22:56 +02:00 committed by GitHub
commit 5d0e84e4ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 135 additions and 37 deletions

View File

@ -441,23 +441,28 @@ abstract class BatchesFolder(
}
fun checkIfFolderIsAccessible(): Boolean {
return when (type) {
BatchType.INTERNAL -> true
BatchType.CUSTOM -> getCustomDefinedFolder().canWrite() && getCustomDefinedFolder().canRead()
BatchType.MEDIA -> {
if (SUPPORTS_SCOPED_STORAGE) {
return true
}
try {
return when (type) {
BatchType.INTERNAL -> true
BatchType.CUSTOM -> getCustomDefinedFolder().canWrite() && getCustomDefinedFolder().canRead()
BatchType.MEDIA -> {
if (SUPPORTS_SCOPED_STORAGE) {
return true
}
return PermissionHelper.hasGranted(
context,
Manifest.permission.READ_EXTERNAL_STORAGE
) &&
PermissionHelper.hasGranted(
context,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
return PermissionHelper.hasGranted(
context,
Manifest.permission.READ_EXTERNAL_STORAGE
) &&
PermissionHelper.hasGranted(
context,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
}
} catch (error: NullPointerException) {
error.printStackTrace()
return false
}
}
@ -586,6 +591,22 @@ abstract class BatchesFolder(
// 350 MiB sounds like a good default
return 350 * 1024 * 1024
}
fun canAccessFolder(context: Context, uri: Uri): Boolean {
return try {
// Create temp file
val tempFile = DocumentFile.fromSingleUri(context, uri)!!.createFile(
"application/octet-stream",
"temp"
)!!
tempFile.delete()
true
} catch (error: RuntimeException) {
error.printStackTrace()
false
}
}
}
}

View File

@ -65,6 +65,8 @@ abstract class IntervalRecorderService<I, B : BatchesFolder> :
if (!batchesFolder.checkIfFolderIsAccessible()) {
onBatchesFolderNotAccessible()
throw AvoidErrorDialogError()
}
createTimer()

View File

@ -1,13 +1,11 @@
package app.myzel394.alibi.services
import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.Notification
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat.getSystemService
import androidx.lifecycle.LifecycleService
import app.myzel394.alibi.NotificationHelper
import app.myzel394.alibi.enums.RecorderState
@ -63,7 +61,16 @@ abstract class RecorderService : LifecycleService() {
startForegroundService()
changeState(RecorderState.RECORDING)
start()
try {
start()
} catch (error: RuntimeException) {
error.printStackTrace()
if (error !is AvoidErrorDialogError) {
onError()
}
}
}
suspend fun stopRecording() {
@ -194,4 +201,9 @@ abstract class RecorderService : LifecycleService() {
}
}
}
// Throw this error if you show a dialog yourself.
// This will prevent the service from showing their generic error dialog.
class AvoidErrorDialogError : RuntimeException()
}

View File

@ -356,17 +356,16 @@ fun RecorderEventsHandler(
progress = processingProgress,
)
if (showRecorderError)
RecorderErrorDialog(
onClose = {
showRecorderError = false
},
)
if (showBatchesInaccessibleError)
BatchesInaccessibleDialog(
onClose = {
showBatchesInaccessibleError = false
},
)
else if (showRecorderError)
RecorderErrorDialog(
onClose = {
showRecorderError = false
},
)
}

View File

@ -2,7 +2,6 @@ package app.myzel394.alibi.ui.components.SettingsScreen.Tiles
import android.Manifest
import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -22,6 +21,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.InsertDriveFile
import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material.icons.filled.Cancel
import androidx.compose.material.icons.filled.Error
import androidx.compose.material.icons.filled.Folder
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.Mic
@ -62,6 +62,7 @@ import app.myzel394.alibi.R
import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.helpers.AudioBatchesFolder
import app.myzel394.alibi.helpers.BatchesFolder
import app.myzel394.alibi.helpers.VideoBatchesFolder
import app.myzel394.alibi.ui.AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME
import app.myzel394.alibi.ui.MEDIA_SUBFOLDER_NAME
@ -91,22 +92,44 @@ fun SaveFolderTile(
val context = LocalContext.current
val dataStore = context.dataStore
var showError by remember { mutableStateOf(false) }
val successMessage = stringResource(R.string.ui_settings_option_saveFolder_success)
fun updateValue(path: String?) {
if (settings.saveFolder != null && settings.saveFolder != RECORDER_MEDIA_SELECTED_VALUE) {
runCatching {
context.contentResolver.releasePersistableUriPermission(
Uri.parse(settings.saveFolder),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
if (path != null && path != RECORDER_MEDIA_SELECTED_VALUE) {
context.contentResolver.takePersistableUriPermission(
path.toUri(),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
if (!BatchesFolder.canAccessFolder(context, path.toUri())) {
showError = true
runCatching {
context.contentResolver.releasePersistableUriPermission(
path.toUri(),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
return
}
}
if (path != null && path != RECORDER_MEDIA_SELECTED_VALUE) {
context.contentResolver.takePersistableUriPermission(
Uri.parse(path),
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
runCatching {
// Clean up
val grantedURIs = context.contentResolver.persistedUriPermissions;
grantedURIs.forEach { permission ->
if (permission.uri == path?.toUri()) {
return@forEach
}
context.contentResolver.releasePersistableUriPermission(
permission.uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
}
}
scope.launch {
@ -130,6 +153,45 @@ fun SaveFolderTile(
}
}
if (showError) {
AlertDialog(
onDismissRequest = {
showError = false
},
icon = {
Icon(
Icons.Default.Error,
contentDescription = null,
)
},
title = {
Text(stringResource(R.string.ui_error_occurred_title))
},
confirmButton = {
Button(onClick = {
showError = false
}) {
Text(stringResource(R.string.dialog_close_neutral_label))
}
},
text = {
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(32.dp),
) {
Text(
stringResource(R.string.ui_settings_option_saveFolder_batchesFolderInaccessible_error),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurface,
)
}
}
)
}
if (selectionVisible) {
SelectionSheet(
sheetState = selectionSheetState,

View File

@ -222,4 +222,6 @@
<string name="ui_about_support_title">Get Support</string>
<string name="ui_about_support_message">If you have any questions, feedback or face any issues, please don\'t hesitate to contact me. I\'m happy to help you! Below is a list of ways to get in touch with me:</string>
<string name="ui_welcome_timeSettings_values_1min">1 Minute</string>
<string name="ui_error_occurred_title">There was an error</string>
<string name="ui_settings_option_saveFolder_batchesFolderInaccessible_error">Alibi can\'t access this folder. Please select a different one</string>
</resources>