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