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 { fun checkIfFolderIsAccessible(): Boolean {
return when (type) { try {
BatchType.INTERNAL -> true return when (type) {
BatchType.CUSTOM -> getCustomDefinedFolder().canWrite() && getCustomDefinedFolder().canRead() BatchType.INTERNAL -> true
BatchType.MEDIA -> { BatchType.CUSTOM -> getCustomDefinedFolder().canWrite() && getCustomDefinedFolder().canRead()
if (SUPPORTS_SCOPED_STORAGE) { BatchType.MEDIA -> {
return true if (SUPPORTS_SCOPED_STORAGE) {
} return true
}
return PermissionHelper.hasGranted( return PermissionHelper.hasGranted(
context, context,
Manifest.permission.READ_EXTERNAL_STORAGE Manifest.permission.READ_EXTERNAL_STORAGE
) && ) &&
PermissionHelper.hasGranted( PermissionHelper.hasGranted(
context, context,
Manifest.permission.WRITE_EXTERNAL_STORAGE 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 // 350 MiB sounds like a good default
return 350 * 1024 * 1024 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()) { if (!batchesFolder.checkIfFolderIsAccessible()) {
onBatchesFolderNotAccessible() onBatchesFolderNotAccessible()
throw AvoidErrorDialogError()
} }
createTimer() createTimer()

View File

@ -1,13 +1,11 @@
package app.myzel394.alibi.services package app.myzel394.alibi.services
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.Notification import android.app.Notification
import android.content.Intent import android.content.Intent
import android.os.Binder import android.os.Binder
import android.os.IBinder import android.os.IBinder
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat.getSystemService
import androidx.lifecycle.LifecycleService import androidx.lifecycle.LifecycleService
import app.myzel394.alibi.NotificationHelper import app.myzel394.alibi.NotificationHelper
import app.myzel394.alibi.enums.RecorderState import app.myzel394.alibi.enums.RecorderState
@ -63,7 +61,16 @@ abstract class RecorderService : LifecycleService() {
startForegroundService() startForegroundService()
changeState(RecorderState.RECORDING) changeState(RecorderState.RECORDING)
start()
try {
start()
} catch (error: RuntimeException) {
error.printStackTrace()
if (error !is AvoidErrorDialogError) {
onError()
}
}
} }
suspend fun stopRecording() { 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, progress = processingProgress,
) )
if (showRecorderError)
RecorderErrorDialog(
onClose = {
showRecorderError = false
},
)
if (showBatchesInaccessibleError) if (showBatchesInaccessibleError)
BatchesInaccessibleDialog( BatchesInaccessibleDialog(
onClose = { onClose = {
showBatchesInaccessibleError = false 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.Manifest
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable 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.automirrored.filled.InsertDriveFile
import androidx.compose.material.icons.filled.CameraAlt import androidx.compose.material.icons.filled.CameraAlt
import androidx.compose.material.icons.filled.Cancel 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.Folder
import androidx.compose.material.icons.filled.Lock import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.Mic 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.dataStore
import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.helpers.AudioBatchesFolder import app.myzel394.alibi.helpers.AudioBatchesFolder
import app.myzel394.alibi.helpers.BatchesFolder
import app.myzel394.alibi.helpers.VideoBatchesFolder import app.myzel394.alibi.helpers.VideoBatchesFolder
import app.myzel394.alibi.ui.AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME import app.myzel394.alibi.ui.AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME
import app.myzel394.alibi.ui.MEDIA_SUBFOLDER_NAME import app.myzel394.alibi.ui.MEDIA_SUBFOLDER_NAME
@ -91,22 +92,44 @@ fun SaveFolderTile(
val context = LocalContext.current val context = LocalContext.current
val dataStore = context.dataStore val dataStore = context.dataStore
var showError by remember { mutableStateOf(false) }
val successMessage = stringResource(R.string.ui_settings_option_saveFolder_success) val successMessage = stringResource(R.string.ui_settings_option_saveFolder_success)
fun updateValue(path: String?) { fun updateValue(path: String?) {
if (settings.saveFolder != null && settings.saveFolder != RECORDER_MEDIA_SELECTED_VALUE) { if (path != null && path != RECORDER_MEDIA_SELECTED_VALUE) {
runCatching { context.contentResolver.takePersistableUriPermission(
context.contentResolver.releasePersistableUriPermission( path.toUri(),
Uri.parse(settings.saveFolder), Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
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) { runCatching {
context.contentResolver.takePersistableUriPermission( // Clean up
Uri.parse(path), val grantedURIs = context.contentResolver.persistedUriPermissions;
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
) 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 { 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) { if (selectionVisible) {
SelectionSheet( SelectionSheet(
sheetState = selectionSheetState, sheetState = selectionSheetState,

View File

@ -222,4 +222,6 @@
<string name="ui_about_support_title">Get Support</string> <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_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_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> </resources>