Request storage permission to save PDF on Android <= 9

This commit is contained in:
Pierre-Yves Nicolas
2025-09-05 12:11:29 +02:00
parent b03af50b16
commit 0f77864859
6 changed files with 41 additions and 2 deletions

2
.gitignore vendored
View File

@@ -8,6 +8,8 @@
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
/.idea/androidTestResultsUserPreferences.xml
/.idea/deviceManager.xml
/.idea/deploymentTargetSelector.xml
.DS_Store
/build
/captures

View File

@@ -7,7 +7,7 @@
android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
<!-- Required (on Android 9 and lower) to save files -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
<application
android:allowBackup="true"

View File

@@ -14,19 +14,28 @@
*/
package org.fairscan.app
import android.Manifest
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.Q
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat.checkSelfPermission
import androidx.core.content.FileProvider
import androidx.core.net.toFile
import androidx.core.net.toUri
@@ -59,10 +68,22 @@ class MainActivity : ComponentActivity() {
}
enableEdgeToEdge()
setContent {
val context = LocalContext.current
val currentScreen by viewModel.currentScreen.collectAsStateWithLifecycle()
val liveAnalysisState by viewModel.liveAnalysisState.collectAsStateWithLifecycle()
val document by viewModel.documentUiModel.collectAsStateWithLifecycle()
val cameraPermission = rememberCameraPermissionState()
val savePdf = { savePdf(viewModel.getFinalPdf(), viewModel) }
val storagePermissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
savePdf()
} else {
val message = getString(R.string.storage_permission_denied)
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
}
MyScanTheme {
val navigation = Navigation(
toHomeScreen = { viewModel.navigateTo(Screen.Main.Home) },
@@ -112,7 +133,7 @@ class MainActivity : ComponentActivity() {
setFilename = viewModel::setFilename,
uiStateFlow = viewModel.pdfUiState,
sharePdf = { sharePdf(viewModel.getFinalPdf(), viewModel) },
savePdf = { savePdf(viewModel.getFinalPdf(), viewModel) },
savePdf = { checkPermissionThen(storagePermissionLauncher, savePdf) },
openPdf = { openPdf(viewModel.pdfUiState.value.savedFileUri) }
),
onCloseScan = {
@@ -154,6 +175,19 @@ class MainActivity : ComponentActivity() {
startActivity(chooser)
}
private fun checkPermissionThen(
requestPermissionLauncher: ManagedActivityResultLauncher<String, Boolean>,
action: () -> Unit
) {
val permission = Manifest.permission.WRITE_EXTERNAL_STORAGE
if (SDK_INT < Q && checkSelfPermission(this, permission) != PERMISSION_GRANTED
) {
requestPermissionLauncher.launch(permission)
} else {
action()
}
}
private fun savePdf(generatedPdf: GeneratedPdf?, viewModel: MainViewModel) {
if (generatedPdf == null)
return

View File

@@ -41,6 +41,7 @@
<string name="scan_in_progress">Scan läuft</string>
<string name="share">Teilen</string>
<string name="share_pdf">PDF teilen</string>
<string name="storage_permission_denied">PDF-Datei kann nicht gespeichert werden: Berechtigung verweigert</string>
<string name="unknown_size">Unbekannte Größe</string>
<string name="version">Version</string>
<string name="view_the_full_license">Vollständige Lizenz anzeigen</string>

View File

@@ -41,6 +41,7 @@
<string name="scan_in_progress">Scan en cours</string>
<string name="share">Partager</string>
<string name="share_pdf">Partager le PDF</string>
<string name="storage_permission_denied">Impossible denregistrer le fichier PDF : permission refusée</string>
<string name="unknown_size">Taille inconnue</string>
<string name="version">Version</string>
<string name="view_the_full_license">Voir la licence complète</string>

View File

@@ -42,6 +42,7 @@
<string name="scan_in_progress">Scan in progress</string>
<string name="share">Share</string>
<string name="share_pdf">Share PDF</string>
<string name="storage_permission_denied">Cannot save PDF file: permission was denied</string>
<string name="unknown_size">Unknown size</string>
<string name="version">Version</string>
<string name="view_the_full_license">View the full license</string>