Fix Xiaomi picker crash on non-persistable content Uri
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
package io.legado.app.ui.config.otherConfig
|
package io.legado.app.ui.config.otherConfig
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
@@ -43,6 +42,7 @@ import io.legado.app.ui.widget.components.settingItem.InputSettingItem
|
|||||||
import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
|
import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
|
||||||
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
|
import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
|
||||||
import io.legado.app.utils.restart
|
import io.legado.app.utils.restart
|
||||||
|
import io.legado.app.utils.takePersistablePermissionSafely
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -75,9 +75,7 @@ fun OtherConfigScreen(
|
|||||||
contract = ActivityResultContracts.OpenDocumentTree()
|
contract = ActivityResultContracts.OpenDocumentTree()
|
||||||
) { uri ->
|
) { uri ->
|
||||||
uri?.let {
|
uri?.let {
|
||||||
val modeFlags =
|
it.takePersistablePermissionSafely(context)
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
context.contentResolver.takePersistableUriPermission(it, modeFlags)
|
|
||||||
viewModel.updateLocalBookDir(it.toString())
|
viewModel.updateLocalBookDir(it.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,4 +507,4 @@ fun ConfirmDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import io.legado.app.utils.externalFiles
|
|||||||
import io.legado.app.utils.getJsonArray
|
import io.legado.app.utils.getJsonArray
|
||||||
import io.legado.app.utils.isContentScheme
|
import io.legado.app.utils.isContentScheme
|
||||||
import io.legado.app.utils.launch
|
import io.legado.app.utils.launch
|
||||||
|
import io.legado.app.utils.takePersistablePermissionSafely
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
@@ -40,9 +41,7 @@ class HandleFileActivity :
|
|||||||
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||||
uri?.let {
|
uri?.let {
|
||||||
if (uri.isContentScheme()) {
|
if (uri.isContentScheme()) {
|
||||||
val modeFlags =
|
uri.takePersistablePermissionSafely(this)
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
contentResolver.takePersistableUriPermission(uri, modeFlags)
|
|
||||||
}
|
}
|
||||||
onResult(Intent().setData(uri))
|
onResult(Intent().setData(uri))
|
||||||
} ?: finish()
|
} ?: finish()
|
||||||
@@ -51,9 +50,7 @@ class HandleFileActivity :
|
|||||||
private val selectDoc = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
private val selectDoc = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||||
it?.let {
|
it?.let {
|
||||||
if (it.isContentScheme()) {
|
if (it.isContentScheme()) {
|
||||||
val modeFlags =
|
it.takePersistablePermissionSafely(this)
|
||||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
contentResolver.takePersistableUriPermission(it, modeFlags)
|
|
||||||
}
|
}
|
||||||
onResult(Intent().setData(it))
|
onResult(Intent().setData(it))
|
||||||
} ?: finish()
|
} ?: finish()
|
||||||
@@ -307,4 +304,4 @@ class HandleFileActivity :
|
|||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,43 @@ fun Uri.isContentScheme() = this.scheme == "content"
|
|||||||
|
|
||||||
fun Uri.isFileScheme() = this.scheme == "file"
|
fun Uri.isFileScheme() = this.scheme == "file"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some vendors return non-persistable content Uris even in system picker flows.
|
||||||
|
* Try to persist read/write grants separately and never throw.
|
||||||
|
*/
|
||||||
|
fun Uri.takePersistablePermissionSafely(
|
||||||
|
context: Context,
|
||||||
|
modeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
): Boolean {
|
||||||
|
if (!isContentScheme()) return false
|
||||||
|
var granted = false
|
||||||
|
if (modeFlags and Intent.FLAG_GRANT_READ_URI_PERMISSION != 0) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
context.contentResolver.takePersistableUriPermission(
|
||||||
|
this,
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
)
|
||||||
|
}.onSuccess {
|
||||||
|
granted = true
|
||||||
|
}.onFailure {
|
||||||
|
AppLog.put("持久化读取权限失败: $this", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modeFlags and Intent.FLAG_GRANT_WRITE_URI_PERMISSION != 0) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
context.contentResolver.takePersistableUriPermission(
|
||||||
|
this,
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
)
|
||||||
|
}.onSuccess {
|
||||||
|
granted = true
|
||||||
|
}.onFailure {
|
||||||
|
AppLog.put("持久化写入权限失败: $this", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return granted
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取URI
|
* 读取URI
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user