Minor fixes and cleanups

This commit is contained in:
topjohnwu 2019-07-22 01:49:21 -07:00
parent 6fb032b3c2
commit 094c3d559a
12 changed files with 47 additions and 86 deletions

View File

@ -2,6 +2,7 @@ package com.topjohnwu.magisk
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Environment
import android.util.Xml import android.util.Xml
import androidx.core.content.edit import androidx.core.content.edit
import com.topjohnwu.magisk.data.database.SettingsDao import com.topjohnwu.magisk.data.database.SettingsDao
@ -97,10 +98,8 @@ object Config : PreferenceModel, DBConfig {
if (Utils.isCanary) Value.CANARY_DEBUG_CHANNEL if (Utils.isCanary) Value.CANARY_DEBUG_CHANNEL
else Value.DEFAULT_CHANNEL else Value.DEFAULT_CHANNEL
private val defaultDownloadPath get() = Const.EXTERNAL_PATH.toRelativeString(Const.EXTERNAL_PATH.parentFile)
var isDownloadCacheEnabled by preference(Key.DOWNLOAD_CACHE, true) var isDownloadCacheEnabled by preference(Key.DOWNLOAD_CACHE, true)
var downloadPath by preference(Key.DOWNLOAD_PATH, defaultDownloadPath) var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE) var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE)
var suDefaultTimeout by preferenceStrInt(Key.SU_REQUEST_TIMEOUT, 10) var suDefaultTimeout by preferenceStrInt(Key.SU_REQUEST_TIMEOUT, 10)
@ -128,14 +127,9 @@ object Config : PreferenceModel, DBConfig {
@JvmStatic @JvmStatic
var suManager by dbStrings(Key.SU_MANAGER, "") var suManager by dbStrings(Key.SU_MANAGER, "")
fun downloadsFile(path: String = downloadPath) = // Always return a path in external storage where we can write
File(Const.EXTERNAL_PATH.parentFile, path).run { val downloadDirectory get() =
if (exists()) { Utils.ensureDownloadPath(downloadPath) ?: get<Context>().getExternalFilesDir(null)!!
if (isDirectory) this else null
} else {
if (mkdirs()) this else null
}
}
fun initialize() = prefs.edit { fun initialize() = prefs.edit {
parsePrefs(this) parsePrefs(this)

View File

@ -6,13 +6,13 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Environment
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresPermission import androidx.annotation.RequiresPermission
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.model.entity.internal.Configuration.* import com.topjohnwu.magisk.model.entity.internal.Configuration.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
@ -31,7 +31,7 @@ import kotlin.random.Random.Default.nextInt
open class DownloadService : RemoteFileService() { open class DownloadService : RemoteFileService() {
private val context get() = this private val context get() = this
private val String.downloadsFile get() = Config.downloadsFile()?.let { File(it, this) } private val String.downloadsFile get() = File(Config.downloadDirectory, this)
private val File.type private val File.type
get() = MimeTypeMap.getSingleton() get() = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(extension) .getMimeTypeFromExtension(extension)
@ -40,7 +40,6 @@ open class DownloadService : RemoteFileService() {
override fun onFinished(file: File, subject: DownloadSubject) = when (subject) { override fun onFinished(file: File, subject: DownloadSubject) = when (subject) {
is Magisk -> onFinishedInternal(file, subject) is Magisk -> onFinishedInternal(file, subject)
is Module -> onFinishedInternal(file, subject) is Module -> onFinishedInternal(file, subject)
else -> Unit
} }
private fun onFinishedInternal( private fun onFinishedInternal(
@ -71,7 +70,6 @@ open class DownloadService : RemoteFileService() {
) = when (subject) { ) = when (subject) {
is Magisk -> addActionsInternal(file, subject) is Magisk -> addActionsInternal(file, subject)
is Module -> addActionsInternal(file, subject) is Module -> addActionsInternal(file, subject)
else -> this
} }
private fun NotificationCompat.Builder.addActionsInternal( private fun NotificationCompat.Builder.addActionsInternal(
@ -109,13 +107,7 @@ open class DownloadService : RemoteFileService() {
// --- // ---
private fun moveToDownloads(file: File) { private fun moveToDownloads(file: File) {
val destination = file.name.downloadsFile ?: let { val destination = file.name.downloadsFile
Utils.toast(
getString(R.string.download_file_folder_error),
Toast.LENGTH_LONG
)
return
}
if (file != destination) { if (file != destination) {
destination.deleteRecursively() destination.deleteRecursively()
@ -125,32 +117,18 @@ open class DownloadService : RemoteFileService() {
Utils.toast( Utils.toast(
getString( getString(
R.string.internal_storage, R.string.internal_storage,
"/" + destination.toRelativeString(Const.EXTERNAL_PATH.parentFile) "/" + destination.toRelativeString(Environment.getExternalStorageDirectory())
), ),
Toast.LENGTH_LONG Toast.LENGTH_LONG
) )
} }
private fun fileIntent(fileName: String): Intent { private fun fileIntent(fileName: String): Intent {
val file = fileName.downloadsFile ?: let { return fileIntent(fileName.downloadsFile)
Utils.toast(
getString(R.string.download_file_folder_error),
Toast.LENGTH_LONG
)
return Intent()
}
return fileIntent(file)
} }
private fun fileParentIntent(fileName: String): Intent { private fun fileParentIntent(fileName: String): Intent {
val file = fileName.downloadsFile?.parentFile ?: let { return fileIntent(fileName.downloadsFile.parentFile!!)
Utils.toast(
getString(R.string.download_file_folder_error),
Toast.LENGTH_LONG
)
return Intent()
}
return fileIntent(file)
} }
private fun fileIntent(file: File): Intent { private fun fileIntent(file: File): Intent {

View File

@ -8,7 +8,8 @@ import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.repository.FileRepository import com.topjohnwu.magisk.data.repository.FileRepository
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module
import com.topjohnwu.magisk.utils.ProgInputStream import com.topjohnwu.magisk.utils.ProgInputStream
import com.topjohnwu.magisk.utils.cachedFile import com.topjohnwu.magisk.utils.cachedFile
import com.topjohnwu.magisk.utils.firstMap import com.topjohnwu.magisk.utils.firstMap
@ -30,8 +31,7 @@ abstract class RemoteFileService : NotificationService() {
private val supportedFolders private val supportedFolders
get() = listOfNotNull( get() = listOfNotNull(
cacheDir, cacheDir,
Config.downloadsFile(), Config.downloadDirectory
Const.EXTERNAL_PATH
) )
override val defaultNotification: NotificationCompat.Builder override val defaultNotification: NotificationCompat.Builder
@ -46,31 +46,27 @@ abstract class RemoteFileService : NotificationService() {
// --- // ---
private fun startInternal(subject: DownloadSubject): Single<File> = search(subject) private fun start(subject: DownloadSubject) = search(subject)
.onErrorResumeNext(download(subject)) .onErrorResumeNext(download(subject))
.doOnSubscribe { update(subject.hashCode()) { it.setContentTitle(subject.fileName) } } .doOnSubscribe { update(subject.hashCode()) { it.setContentTitle(subject.fileName) } }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.doOnSuccess { .doOnSuccess {
runCatching { onFinished(it, subject) }.onFailure { Timber.e(it) } runCatching { onFinished(it, subject) }.onFailure { Timber.e(it) }
finish(it, subject) finish(it, subject)
} }.subscribeK()
private fun start(subject: DownloadSubject) = startInternal(subject).subscribeK()
private fun search(subject: DownloadSubject) = Single.fromCallable { private fun search(subject: DownloadSubject) = Single.fromCallable {
if (!Config.isDownloadCacheEnabled) { if (!Config.isDownloadCacheEnabled) {
throw IllegalStateException("The download cache is disabled") throw IllegalStateException("The download cache is disabled")
} }
val file = supportedFolders.firstMap { it.find(subject.fileName) } supportedFolders.firstMap { it.find(subject.fileName) }.also {
if (subject is Magisk) {
if (subject is Magisk) { if (!ShellUtils.checkSum("MD5", it, subject.magisk.hash)) {
if (!ShellUtils.checkSum("MD5", file, subject.magisk.hash)) { throw IllegalStateException("The given file doesn't match the hash")
throw IllegalStateException("The given file doesn't match the hash") }
} }
} }
file
} }
private fun download(subject: DownloadSubject) = repo.downloadFile(subject.url) private fun download(subject: DownloadSubject) = repo.downloadFile(subject.url)
@ -107,8 +103,6 @@ abstract class RemoteFileService : NotificationService() {
} }
private fun finish(file: File, subject: DownloadSubject) = finishWork(subject.hashCode()) { private fun finish(file: File, subject: DownloadSubject) = finishWork(subject.hashCode()) {
if (subject is Installer) return@finishWork null
it.addActions(file, subject) it.addActions(file, subject)
.setContentText(getString(R.string.download_complete)) .setContentText(getString(R.string.download_complete))
.setSmallIcon(android.R.drawable.stat_sys_download_done) .setSmallIcon(android.R.drawable.stat_sys_download_done)

View File

@ -14,10 +14,6 @@ sealed class Configuration : Parcelable {
@Parcelize @Parcelize
object Secondary : Flash() object Secondary : Flash()
companion object {
operator fun invoke(): Flash = Primary
}
} }
@Parcelize @Parcelize

View File

@ -1,12 +0,0 @@
package com.topjohnwu.magisk.model.entity.internal
import com.skoumal.teanity.util.KObservableField
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.model.observer.Observer
class DownloadDialogData(initialValue: String) {
val text = KObservableField(initialValue)
val path = Observer(text) { Config.downloadsFile(text.value)?.absolutePath.orEmpty() }
}

View File

@ -1,8 +1,6 @@
package com.topjohnwu.magisk.model.entity.internal package com.topjohnwu.magisk.model.entity.internal
import android.os.Parcelable import android.os.Parcelable
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.model.entity.MagiskJson import com.topjohnwu.magisk.model.entity.MagiskJson
import com.topjohnwu.magisk.model.entity.Repo import com.topjohnwu.magisk.model.entity.Repo
@ -39,10 +37,4 @@ sealed class DownloadSubject : Parcelable {
} }
@Parcelize
object Installer : DownloadSubject() {
override val fileName: String get() = "module_installer(${BuildConfig.VERSION_CODE}).sh"
override val url: String get() = Const.Url.MODULE_INSTALLER
}
} }

View File

@ -18,7 +18,7 @@ open class FlashActivity : MagiskActivity<FlashViewModel, ActivityFlashBinding>(
override val layoutRes: Int = R.layout.activity_flash override val layoutRes: Int = R.layout.activity_flash
override val viewModel: FlashViewModel by viewModel { override val viewModel: FlashViewModel by viewModel {
val uri = intent.data ?: let { finish(); Uri.EMPTY } val uri = intent.data ?: let { finish(); Uri.EMPTY }
val additionalUri = intent.getParcelableExtra<Uri>(Const.Key.FLASH_DATA) ?: uri val additionalUri = intent.getParcelableExtra(Const.Key.FLASH_DATA) ?: uri
val action = intent.getStringExtra(Const.Key.FLASH_ACTION) ?: let { finish();"" } val action = intent.getStringExtra(Const.Key.FLASH_ACTION) ?: let { finish();"" }
parametersOf(action, uri, additionalUri) parametersOf(action, uri, additionalUri)
} }

View File

@ -99,7 +99,7 @@ class ReposFragment : MagiskFragment<ModuleViewModel, FragmentReposBinding>(),
fun download(install: Boolean) = context.withExternalRW { fun download(install: Boolean) = context.withExternalRW {
onSuccess { onSuccess {
DownloadService(context) { DownloadService(context) {
val config = if (install) Configuration.Flash() else Configuration.Download val config = if (install) Configuration.Flash.Primary else Configuration.Download
subject = DownloadSubject.Module(item, config) subject = DownloadSubject.Module(item, config)
} }
} }

View File

@ -3,6 +3,7 @@ package com.topjohnwu.magisk.ui.settings
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.EditText import android.widget.EditText
import android.widget.Toast import android.widget.Toast
@ -14,19 +15,21 @@ import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import com.skoumal.teanity.extensions.subscribeK import com.skoumal.teanity.extensions.subscribeK
import com.skoumal.teanity.util.KObservableField
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.RepoDatabaseHelper import com.topjohnwu.magisk.data.database.RepoDatabaseHelper
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
import com.topjohnwu.magisk.model.entity.internal.DownloadDialogData import com.topjohnwu.magisk.model.observer.Observer
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment import com.topjohnwu.magisk.ui.base.BasePreferenceFragment
import com.topjohnwu.magisk.utils.* import com.topjohnwu.magisk.utils.*
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
import com.topjohnwu.net.Networking import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import java.io.File
class SettingsFragment : BasePreferenceFragment() { class SettingsFragment : BasePreferenceFragment() {
@ -297,6 +300,13 @@ class SettingsFragment : BasePreferenceFragment() {
.show() .show()
} }
inner class DownloadDialogData(initialValue: String) {
val text = KObservableField(initialValue)
val path = Observer(text) {
File(Environment.getExternalStorageDirectory(), text.value).absolutePath
}
}
private inline fun showDownloadDialog( private inline fun showDownloadDialog(
initialValue: String = Config.downloadPath, initialValue: String = Config.downloadPath,
crossinline onSuccess: (String) -> Unit crossinline onSuccess: (String) -> Unit
@ -310,10 +320,10 @@ class SettingsFragment : BasePreferenceFragment() {
.setTitle(R.string.settings_download_path_title) .setTitle(R.string.settings_download_path_title)
.setView(binding.root) .setView(binding.root)
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(R.string.ok) { _, _ ->
Config.downloadsFile(data.text.value)?.let { onSuccess(data.text.value) } Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) }
?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT) ?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT)
} }
.setNegativeButton(R.string.close, null) .setNegativeButton(R.string.close, null)
.show() .show()
} }
} }

View File

@ -8,6 +8,7 @@ import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import android.net.Uri import android.net.Uri
import android.os.Environment
import android.widget.Toast import android.widget.Toast
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.work.* import androidx.work.*
@ -19,6 +20,7 @@ import com.topjohnwu.net.Networking
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile
import java.io.File
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -120,4 +122,9 @@ object Utils {
} }
} }
fun ensureDownloadPath(path : String) =
File(Environment.getExternalStorageDirectory(), path).run {
if ((exists() && isDirectory) || mkdirs()) this else null
}
} }

View File

@ -7,7 +7,7 @@
<variable <variable
name="data" name="data"
type="com.topjohnwu.magisk.model.entity.internal.DownloadDialogData" /> type="com.topjohnwu.magisk.ui.settings.SettingsFragment.DownloadDialogData" />
</data> </data>

View File

@ -3,4 +3,6 @@
<files-path name="internal_files" path="."/> <files-path name="internal_files" path="."/>
<cache-path name="cache_files" path="." /> <cache-path name="cache_files" path="." />
<external-path name="external_files" path="."/> <external-path name="external_files" path="."/>
</paths> <external-cache-path name="external_cache_files" path="."/>
<external-files-path name="private_external_files" path="."/>
</paths>