Have some fun with Kotlin Coroutines
This commit is contained in:
parent
89e11c9cc8
commit
820427e93b
@ -21,6 +21,8 @@ import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
|
||||
import com.topjohnwu.magisk.ui.flash.FlashFragment
|
||||
import com.topjohnwu.magisk.utils.APKInstall
|
||||
import io.reactivex.Completable
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.core.get
|
||||
import java.io.File
|
||||
import kotlin.random.Random.Default.nextInt
|
||||
@ -47,7 +49,9 @@ open class DownloadService : RemoteFileService() {
|
||||
) = when (val conf = subject.configuration) {
|
||||
Uninstall -> FlashFragment.uninstall(subject.file, id)
|
||||
EnvFix -> {
|
||||
remove(id); EnvFixTask(subject.file).exec()
|
||||
remove(id)
|
||||
GlobalScope.launch { EnvFixTask(subject.file).exec() }
|
||||
Unit
|
||||
}
|
||||
is Patch -> FlashFragment.patch(subject.file, conf.fileUri, id)
|
||||
is Flash -> FlashFragment.flash(subject.file, conf is Secondary, id)
|
||||
|
@ -2,25 +2,29 @@ package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.core.os.postDelayed
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.utils.unzip
|
||||
import com.topjohnwu.magisk.extensions.fileName
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.extensions.readUri
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import io.reactivex.Single
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.inject
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
|
||||
abstract class FlashZip(
|
||||
open class FlashZip(
|
||||
private val mUri: Uri,
|
||||
private val console: MutableList<String>,
|
||||
private val logs: MutableList<String>
|
||||
) : FlashResultListener {
|
||||
): KoinComponent {
|
||||
|
||||
private val context: Context by inject()
|
||||
val context: Context by inject()
|
||||
private val installFolder = File(context.cacheDir, "flash").apply {
|
||||
if (!exists()) mkdirs()
|
||||
}
|
||||
@ -79,19 +83,37 @@ abstract class FlashZip(
|
||||
.exec().isSuccess
|
||||
}
|
||||
|
||||
fun exec() = Single
|
||||
.fromCallable {
|
||||
runCatching {
|
||||
flash()
|
||||
}.getOrElse {
|
||||
it.printStackTrace()
|
||||
open suspend fun exec() = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
if (!flash()) {
|
||||
console.add("! Installation failed")
|
||||
false
|
||||
}.apply {
|
||||
Shell.su("cd /", "rm -rf ${tmpFile.parent} ${Const.TMP_FOLDER_PATH}")
|
||||
.submit()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
false
|
||||
} finally {
|
||||
Shell.su("cd /", "rm -rf ${tmpFile.parent} ${Const.TMP_FOLDER_PATH}").submit()
|
||||
}
|
||||
}
|
||||
|
||||
class Uninstall(
|
||||
uri: Uri,
|
||||
console: MutableList<String>,
|
||||
log: MutableList<String>
|
||||
) : FlashZip(uri, console, log) {
|
||||
|
||||
override suspend fun exec(): Boolean {
|
||||
val success = super.exec()
|
||||
if (success) {
|
||||
UiThreadHandler.handler.postDelayed(3000) {
|
||||
Shell.su("pm uninstall " + context.packageName).exec()
|
||||
}
|
||||
}
|
||||
return success
|
||||
}
|
||||
}
|
||||
.subscribeK(onError = { onResult(false) }) { onResult(it) }
|
||||
.let { Unit } // ignores result disposable
|
||||
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.core.os.postDelayed
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
|
||||
sealed class Flashing(
|
||||
uri: Uri,
|
||||
private val console: MutableList<String>,
|
||||
log: MutableList<String>,
|
||||
private val resultListener: FlashResultListener
|
||||
) : FlashZip(uri, console, log) {
|
||||
|
||||
override fun onResult(success: Boolean) {
|
||||
if (!success) {
|
||||
console.add("! Installation failed")
|
||||
}
|
||||
|
||||
resultListener.onResult(success)
|
||||
}
|
||||
|
||||
class Install(
|
||||
uri: Uri,
|
||||
console: MutableList<String>,
|
||||
log: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : Flashing(uri, console, log, resultListener)
|
||||
|
||||
class Uninstall(
|
||||
uri: Uri,
|
||||
console: MutableList<String>,
|
||||
log: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : Flashing(uri, console, log, resultListener) {
|
||||
|
||||
private val context: Context by inject()
|
||||
|
||||
override fun onResult(success: Boolean) {
|
||||
if (success) {
|
||||
UiThreadHandler.handler.postDelayed(3000) {
|
||||
Shell.su("pm uninstall " + context.packageName).exec()
|
||||
}
|
||||
}
|
||||
super.onResult(success)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,6 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.postDelayed
|
||||
@ -26,7 +25,8 @@ import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream
|
||||
import io.reactivex.Single
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.kamranzafar.jtar.TarEntry
|
||||
import org.kamranzafar.jtar.TarHeader
|
||||
import org.kamranzafar.jtar.TarInputStream
|
||||
@ -43,14 +43,7 @@ import java.nio.ByteBuffer
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
interface FlashResultListener {
|
||||
|
||||
@MainThread
|
||||
fun onResult(success: Boolean)
|
||||
|
||||
}
|
||||
|
||||
abstract class MagiskInstallImpl : FlashResultListener, KoinComponent {
|
||||
abstract class MagiskInstallImpl : KoinComponent {
|
||||
|
||||
protected lateinit var installDir: File
|
||||
private lateinit var srcBoot: String
|
||||
@ -388,53 +381,48 @@ abstract class MagiskInstallImpl : FlashResultListener, KoinComponent {
|
||||
@WorkerThread
|
||||
protected abstract fun operations(): Boolean
|
||||
|
||||
fun exec() {
|
||||
Single.fromCallable { operations() }.subscribeK { onResult(it) }
|
||||
}
|
||||
open suspend fun exec() = withContext(Dispatchers.IO) { operations() }
|
||||
}
|
||||
|
||||
sealed class MagiskInstaller(
|
||||
file: Uri,
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>,
|
||||
private val resultListener: FlashResultListener
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstallImpl(file, console, logs) {
|
||||
|
||||
override fun onResult(success: Boolean) {
|
||||
override suspend fun exec(): Boolean {
|
||||
val success = super.exec()
|
||||
if (success) {
|
||||
console.add("- All done!")
|
||||
} else {
|
||||
Shell.sh("rm -rf $installDir").submit()
|
||||
console.add("! Installation failed")
|
||||
}
|
||||
resultListener.onResult(success)
|
||||
return success
|
||||
}
|
||||
|
||||
class Patch(
|
||||
file: Uri,
|
||||
private val uri: Uri,
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : MagiskInstaller(file, console, logs, resultListener) {
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(file, console, logs) {
|
||||
override fun operations() = doPatchFile(uri)
|
||||
}
|
||||
|
||||
class SecondSlot(
|
||||
file: Uri,
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : MagiskInstaller(file, console, logs, resultListener) {
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(file, console, logs) {
|
||||
override fun operations() = secondSlot()
|
||||
}
|
||||
|
||||
class Direct(
|
||||
file: Uri,
|
||||
console: MutableList<String>,
|
||||
logs: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : MagiskInstaller(file, console, logs, resultListener) {
|
||||
logs: MutableList<String>
|
||||
) : MagiskInstaller(file, console, logs) {
|
||||
override fun operations() = direct()
|
||||
}
|
||||
|
||||
@ -445,7 +433,8 @@ class EnvFixTask(
|
||||
) : MagiskInstallImpl() {
|
||||
override fun operations() = fixEnv(zip)
|
||||
|
||||
override fun onResult(success: Boolean) {
|
||||
override suspend fun exec(): Boolean {
|
||||
val success = super.exec()
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(EnvFixDialog.DISMISS))
|
||||
Utils.toast(
|
||||
if (success) R.string.reboot_delay_toast else R.string.setup_fail,
|
||||
@ -453,5 +442,6 @@ class EnvFixTask(
|
||||
)
|
||||
if (success)
|
||||
UiThreadHandler.handler.postDelayed(5000) { reboot() }
|
||||
return success
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.view.MenuItem
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.tasks.FlashResultListener
|
||||
import com.topjohnwu.magisk.core.tasks.Flashing
|
||||
import com.topjohnwu.magisk.core.tasks.FlashZip
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import com.topjohnwu.magisk.extensions.*
|
||||
@ -21,13 +21,14 @@ import com.topjohnwu.magisk.ui.base.diffListOf
|
||||
import com.topjohnwu.magisk.ui.base.itemBindingOf
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class FlashViewModel(
|
||||
args: FlashFragmentArgs,
|
||||
private val resources: Resources
|
||||
) : BaseViewModel(), FlashResultListener {
|
||||
) : BaseViewModel() {
|
||||
|
||||
val showReboot = KObservableField(Shell.rootAccess())
|
||||
val behaviorText = KObservableField(resources.getString(R.string.flashing))
|
||||
@ -51,30 +52,36 @@ class FlashViewModel(
|
||||
}
|
||||
|
||||
private fun startFlashing(installer: Uri, uri: Uri?, action: String) {
|
||||
when (action) {
|
||||
viewModelScope.launch {
|
||||
val result = when (action) {
|
||||
Const.Value.FLASH_ZIP -> {
|
||||
Flashing.Install(installer, outItems, logItems, this).exec()
|
||||
FlashZip(installer, outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.UNINSTALL -> {
|
||||
showReboot.value = false
|
||||
Flashing.Uninstall(installer, outItems, logItems, this).exec()
|
||||
FlashZip.Uninstall(installer, outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.FLASH_MAGISK -> {
|
||||
MagiskInstaller.Direct(installer, outItems, logItems, this).exec()
|
||||
MagiskInstaller.Direct(installer, outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.FLASH_INACTIVE_SLOT -> {
|
||||
MagiskInstaller.SecondSlot(installer, outItems, logItems, this).exec()
|
||||
MagiskInstaller.SecondSlot(installer, outItems, logItems).exec()
|
||||
}
|
||||
Const.Value.PATCH_FILE -> {
|
||||
uri ?: return
|
||||
uri ?: return@launch
|
||||
showReboot.value = false
|
||||
MagiskInstaller.Patch(installer, uri, outItems, logItems, this).exec()
|
||||
MagiskInstaller.Patch(installer, uri, outItems, logItems).exec()
|
||||
}
|
||||
else -> back()
|
||||
else -> {
|
||||
back()
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
onResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResult(success: Boolean) {
|
||||
private fun onResult(success: Boolean) {
|
||||
state = if (success) State.LOADED else State.LOADING_FAILED
|
||||
behaviorText.value = when {
|
||||
success -> resources.getString(R.string.done)
|
||||
|
Loading…
Reference in New Issue
Block a user