From 97e30639989b1900853d24b765981607df8c962f Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 12 Jul 2021 14:04:24 +0900 Subject: [PATCH] remove URI permissions for obsolete paths --- android/app/build.gradle | 2 +- .../thibault/aves/utils/PermissionManager.kt | 27 +++++++++++++++++-- .../thibault/aves/utils/StorageUtils.kt | 1 + android/build.gradle | 2 +- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 921eef776..01584967c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -105,7 +105,7 @@ repositories { dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9' - implementation 'androidx.core:core-ktx:1.5.0' + implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.exifinterface:exifinterface:1.3.2' implementation 'androidx.multidex:multidex:2.0.1' implementation 'com.caverock:androidsvg-aar:1.4' diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt index ae6701cbf..8a180a0ab 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt @@ -133,8 +133,7 @@ object PermissionManager { @RequiresApi(Build.VERSION_CODES.LOLLIPOP) fun revokeDirectoryAccess(context: Context, path: String): Boolean { return StorageUtils.convertDirPathToTreeUri(context, path)?.let { - val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - context.contentResolver.releasePersistableUriPermission(it, flags) + releaseUriPermission(context, it) true } ?: false } @@ -158,4 +157,28 @@ object PermissionManager { } return accessibleDirs } + + // As of Android R, `MediaStore.getDocumentUri` fails if any of the persisted + // URI permissions we hold points to a folder that no longer exists, + // so we should remove these obsolete URIs before proceeding. + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + fun sanitizePersistedUriPermissions(context: Context) { + try { + for (uriPermission in context.contentResolver.persistedUriPermissions) { + val uri = uriPermission.uri + val path = StorageUtils.convertTreeUriToDirPath(context, uri) + if (path != null && !File(path).exists()) { + Log.d(LOG_TAG, "revoke URI permission for obsolete path=$path") + releaseUriPermission(context, uri) + } + } + } catch (e: Exception) { + Log.w(LOG_TAG, "failed to sanitize persisted URI permissions", e) + } + } + + private fun releaseUriPermission(context: Context, it: Uri) { + val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + context.contentResolver.releasePersistableUriPermission(it, flags) + } } \ No newline at end of file diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt index 0a3167d47..49eea7d96 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt @@ -293,6 +293,7 @@ object StorageUtils { // need a document URI (not a media content URI) to open a `DocumentFile` output stream if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isMediaStoreContentUri(mediaUri)) { // cleanest API to get it + PermissionManager.sanitizePersistedUriPermissions(context) try { val docUri = MediaStore.getDocumentUri(context, mediaUri) if (docUri != null) { diff --git a/android/build.gradle b/android/build.gradle index 80a95abbc..d1dfbc412 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' + classpath 'com.android.tools.build:gradle:4.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.8' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'