This commit is contained in:
Horis 2023-12-16 16:06:36 +08:00
parent 7a70e10d08
commit cc71a6c22b
7 changed files with 68 additions and 26 deletions

View File

@ -23,13 +23,13 @@
<application
android:name=".App"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme.Light"
android:enableOnBackInvokedCallback="true"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute">
<!-- 主入口 -->
<activity
@ -367,6 +367,7 @@
<data android:mimeType="application/epub+zip" />
<!-- pdf -->
<data android:mimeType="application/pdf" />
<data android:mimeType="application/octet-stream" />
</intent-filter>
<!-- Works when an app doesn't know the media type, e.g. Dropbox -->
<intent-filter>
@ -428,9 +429,9 @@
<service
android:name=".service.WebTileService"
android:exported="true"
android:foregroundServiceType="dataSync"
android:icon="@drawable/ic_web_service_noti"
android:label="legado Web Service"
android:foregroundServiceType="dataSync"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />

View File

@ -0,0 +1,3 @@
package io.legado.app.exception
class InvalidBooksDirException(msg: String) : NoStackTraceException(msg)

View File

@ -43,7 +43,10 @@ class PermissionActivity : AppCompatActivity() {
try {
if (Permissions.isManageExternalStorage()) {
val settingIntent =
Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
Intent(
Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
Uri.parse("package:$packageName")
)
settingActivityResult.launch(settingIntent)
} else {
throw NoStackTraceException("no MANAGE_ALL_FILES_ACCESS_PERMISSION")

View File

@ -4,12 +4,14 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.os.postDelayed
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.lifecycleScope
import io.legado.app.R
import io.legado.app.base.VMBaseActivity
import io.legado.app.constant.AppLog
import io.legado.app.databinding.ActivityTranslucenceBinding
import io.legado.app.exception.InvalidBooksDirException
import io.legado.app.help.config.AppConfig
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.permission.Permissions
@ -17,6 +19,8 @@ import io.legado.app.lib.permission.PermissionsCompat
import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.file.HandleFileContract
import io.legado.app.utils.FileUtils
import io.legado.app.utils.buildMainHandler
import io.legado.app.utils.canRead
import io.legado.app.utils.checkWrite
import io.legado.app.utils.getFile
import io.legado.app.utils.isContentScheme
@ -43,7 +47,7 @@ class FileAssociationActivity :
} ?: let {
val storageHelp = String(assets.open("storageHelp.md").readBytes())
toastOnUi(storageHelp)
viewModel.importBook(uri)
importBook(null, uri)
}
}
}
@ -52,6 +56,10 @@ class FileAssociationActivity :
override val viewModel by viewModels<FileAssociationViewModel>()
private val handler by lazy {
buildMainHandler()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
binding.rotateLoading.visible()
viewModel.importBookLiveData.observe(this) { uri ->
@ -114,21 +122,20 @@ class FileAssociationActivity :
noButton {
finish()
}
onCancelled {
finish()
}
}
}
intent.data?.let { data ->
if (data.isContentScheme()) {
viewModel.dispatchIndent(data)
if (data.canRead()) {
viewModel.dispatchIntent(data)
} else {
dispatchWithPermission(data)
}
} else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
PermissionsCompat.Builder()
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
viewModel.dispatchIndent(data)
}.onDenied {
toastOnUi("请求存储权限失败。")
finish()
}.request()
dispatchWithPermission(data)
} else {
toastOnUi("由于安卓系统限制,请使用系统文件管理重新打开。")
finish()
@ -136,6 +143,18 @@ class FileAssociationActivity :
} ?: finish()
}
private fun dispatchWithPermission(data: Uri) {
PermissionsCompat.Builder()
.addPermissions(*Permissions.Group.STORAGE)
.rationale(R.string.tip_perm_request_storage)
.onGranted {
viewModel.dispatchIntent(data)
}.onDenied {
toastOnUi("请求存储权限失败。")
finish()
}.request()
}
private fun importBook(uri: Uri) {
if (uri.isContentScheme()) {
val treeUriStr = AppConfig.defaultBookTreeUri
@ -148,19 +167,21 @@ class FileAssociationActivity :
importBook(Uri.parse(treeUriStr), uri)
}
} else {
viewModel.importBook(uri)
importBook(null, uri)
}
}
private fun importBook(treeUri: Uri, uri: Uri) {
private fun importBook(treeUri: Uri?, uri: Uri) {
lifecycleScope.launch {
runCatching {
withContext(IO) {
if (treeUri.isContentScheme()) {
if (treeUri == null) {
viewModel.importBook(uri)
} else if (treeUri.isContentScheme()) {
val treeDoc =
DocumentFile.fromTreeUri(this@FileAssociationActivity, treeUri)
if (!treeDoc!!.checkWrite()) {
throw SecurityException("请重新设置书籍保存位置\nPermission Denial")
throw InvalidBooksDirException("请重新设置书籍保存位置\nPermission Denial")
}
readUri(uri) { fileDoc, inputStream ->
val name = fileDoc.name
@ -168,7 +189,7 @@ class FileAssociationActivity :
if (doc == null || fileDoc.lastModified > doc.lastModified()) {
if (doc == null) {
doc = treeDoc.createFile(FileUtils.getMimeType(name), name)
?: throw SecurityException("请重新设置书籍保存位置\nPermission Denial")
?: throw InvalidBooksDirException("请重新设置书籍保存位置\nPermission Denial")
}
contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
inputStream.copyTo(oStream)
@ -180,7 +201,7 @@ class FileAssociationActivity :
} else {
val treeFile = File(treeUri.path ?: treeUri.toString())
if (!treeFile.checkWrite()) {
throw SecurityException("请重新设置书籍保存位置\nPermission Denial")
throw InvalidBooksDirException("请重新设置书籍保存位置\nPermission Denial")
}
readUri(uri) { fileDoc, inputStream ->
val name = fileDoc.name
@ -197,7 +218,7 @@ class FileAssociationActivity :
}
}.onFailure {
when (it) {
is SecurityException -> localBookTreeSelect.launch {
is InvalidBooksDirException -> localBookTreeSelect.launch {
title = getString(R.string.select_book_folder)
mode = HandleFileContract.DIR_SYS
}
@ -206,7 +227,9 @@ class FileAssociationActivity :
val msg = "导入书籍失败\n${it.localizedMessage}"
AppLog.put(msg, it)
toastOnUi(msg)
finish()
handler.postDelayed(2000) {
finish()
}
}
}
}

View File

@ -15,7 +15,7 @@ class FileAssociationViewModel(application: Application) : BaseAssociationViewMo
val openBookLiveData = MutableLiveData<String>()
val notSupportedLiveData = MutableLiveData<Pair<Uri, String>>()
fun dispatchIndent(uri: Uri) {
fun dispatchIntent(uri: Uri) {
execute {
lateinit var fileName: String
//如果是普通的url需要根据返回的内容判断是什么

View File

@ -159,6 +159,9 @@ fun Context.getCompatDrawable(@DrawableRes id: Int): Drawable? = ContextCompat.g
fun Context.getCompatColorStateList(@ColorRes id: Int): ColorStateList? =
ContextCompat.getColorStateList(this, id)
fun Context.checkSelfUriPermission(uri: Uri, modeFlags: Int): Int =
checkUriPermission(uri, Process.myPid(), Process.myUid(), modeFlags)
fun Context.restart() {
val intent: Intent? = packageManager.getLaunchIntentForPackage(packageName)
intent?.let {

View File

@ -1,6 +1,8 @@
package io.legado.app.utils
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.ParcelFileDescriptor
import androidx.appcompat.app.AppCompatActivity
@ -63,7 +65,7 @@ fun AppCompatActivity.readUri(
}
} catch (e: Exception) {
e.printOnDebug()
toastOnUi(e.localizedMessage ?: "read uri error")
toastOnUi("读取Uri出错\n${e.localizedMessage}")
if (e is SecurityException) {
throw e
}
@ -104,7 +106,7 @@ fun Fragment.readUri(uri: Uri?, success: (fileDoc: FileDoc, inputStream: InputSt
}
} catch (e: Exception) {
e.printOnDebug()
toastOnUi(e.localizedMessage ?: "read uri error")
toastOnUi("读取Uri出错\n${e.localizedMessage}")
}
}
@ -311,4 +313,11 @@ fun Uri.toRequestBody(contentType: MediaType? = null): RequestBody {
}
}
}
}
}
fun Uri.canRead(): Boolean {
return appCtx.checkSelfUriPermission(
this,
Intent.FLAG_GRANT_READ_URI_PERMISSION
) == PackageManager.PERMISSION_GRANTED
}