mirror of
https://github.com/gedoor/legado.git
synced 2024-07-06 23:47:49 +08:00
优化
This commit is contained in:
parent
7a70e10d08
commit
cc71a6c22b
@ -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" />
|
||||
|
@ -0,0 +1,3 @@
|
||||
package io.legado.app.exception
|
||||
|
||||
class InvalidBooksDirException(msg: String) : NoStackTraceException(msg)
|
@ -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")
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,需要根据返回的内容判断是什么
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user