diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 033ceef1f..b02053369 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -29,9 +29,6 @@
-
-
-
FlashActivity.uninstall(this, subject.file, id)
- EnvFix -> { remove(id); EnvFixTask(subject.file).exec() }
- is Patch -> FlashActivity.patch(this, subject.file, conf.fileUri, id)
- is Flash -> FlashActivity.flash(this, subject.file, conf is Secondary, id)
+ Uninstall -> FlashFragment.uninstall(subject.file, id)
+ EnvFix -> {
+ remove(id); EnvFixTask(subject.file).exec()
+ }
+ is Patch -> FlashFragment.patch(subject.file, conf.fileUri, id)
+ is Flash -> FlashFragment.flash(subject.file, conf is Secondary, id)
else -> Unit
}
@@ -56,7 +58,7 @@ open class DownloadService : RemoteFileService() {
subject: Module,
id: Int
) = when (subject.configuration) {
- is Flash -> FlashActivity.install(this, subject.file, id)
+ is Flash -> FlashFragment.install(subject.file, id)
else -> Unit
}
@@ -94,9 +96,15 @@ open class DownloadService : RemoteFileService() {
.takeIf { it.exists(get()) }
?.let { addAction(0, R.string.download_open_self, it.chooser()) }
}
- Uninstall -> setContentIntent(FlashActivity.uninstallIntent(context, subject.file))
- is Flash -> setContentIntent(FlashActivity.flashIntent(context, subject.file, conf is Secondary))
- is Patch -> setContentIntent(FlashActivity.patchIntent(context, subject.file, conf.fileUri))
+ Uninstall -> setContentIntent(FlashFragment.uninstallIntent(context, subject.file))
+ is Flash -> setContentIntent(
+ FlashFragment.flashIntent(
+ context,
+ subject.file,
+ conf is Secondary
+ )
+ )
+ is Patch -> setContentIntent(FlashFragment.patchIntent(context, subject.file, conf.fileUri))
else -> this
}
@@ -110,7 +118,7 @@ open class DownloadService : RemoteFileService() {
.takeIf { it.exists(get()) }
?.let { addAction(0, R.string.download_open_self, it.chooser()) }
}
- is Flash -> setContentIntent(FlashActivity.installIntent(context, subject.file))
+ is Flash -> setContentIntent(FlashFragment.installIntent(context, subject.file))
else -> this
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt
index 18a1a475b..222d99783 100644
--- a/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/core/download/RemoteFileService.kt
@@ -29,7 +29,10 @@ abstract class RemoteFileService : NotificationService() {
val service: GithubRawServices by inject()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- intent?.getParcelableExtra(ARG_URL)?.let { start(it) }
+ intent?.getParcelableExtra(ARG_URL)?.let {
+ update(it.hashCode())
+ start(it)
+ }
return START_REDELIVER_INTENT
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
index 527aceab6..2b658f440 100644
--- a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
@@ -1,8 +1,9 @@
package com.topjohnwu.magisk.di
-import com.topjohnwu.magisk.legacy.flash.FlashViewModel
import com.topjohnwu.magisk.legacy.surequest.SuRequestViewModel
import com.topjohnwu.magisk.ui.MainViewModel
+import com.topjohnwu.magisk.ui.flash.FlashFragmentArgs
+import com.topjohnwu.magisk.ui.flash.FlashViewModel
import com.topjohnwu.magisk.ui.hide.HideViewModel
import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.ui.install.InstallViewModel
@@ -30,6 +31,6 @@ val viewModelModules = module {
viewModel { MainViewModel() }
// Legacy
- viewModel { FlashViewModel(get()) }
+ viewModel { (args: FlashFragmentArgs) -> FlashViewModel(args, get()) }
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/legacy/flash/FlashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/legacy/flash/FlashActivity.kt
deleted file mode 100644
index 9d731e08b..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/legacy/flash/FlashActivity.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.topjohnwu.magisk.legacy.flash
-
-import android.content.Context
-import android.content.Intent
-import android.content.pm.ActivityInfo
-import android.net.Uri
-import android.os.Bundle
-import androidx.core.net.toUri
-import androidx.navigation.NavController
-import com.topjohnwu.magisk.R
-import com.topjohnwu.magisk.core.Const
-import com.topjohnwu.magisk.core.intent
-import com.topjohnwu.magisk.core.view.Notifications
-import com.topjohnwu.magisk.databinding.ActivityFlashBinding
-import com.topjohnwu.magisk.extensions.snackbar
-import com.topjohnwu.magisk.model.events.PermissionEvent
-import com.topjohnwu.magisk.model.events.SnackbarEvent
-import com.topjohnwu.magisk.model.events.ViewEvent
-import com.topjohnwu.magisk.ui.base.BaseUIActivity
-import org.koin.androidx.viewmodel.ext.android.viewModel
-import java.io.File
-
-open class FlashActivity : BaseUIActivity() {
-
- override val layoutRes: Int = R.layout.activity_flash
- override val viewModel: FlashViewModel by viewModel()
-
- override val navigation: NavController? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
- super.onCreate(savedInstanceState)
- val id = intent.getIntExtra(Const.Key.DISMISS_ID, -1)
- if (id != -1)
- Notifications.mgr.cancel(id)
- viewModel.startFlashing(intent)
- }
-
- override fun onBackPressed() {
- if (viewModel.loading) return
- super.onBackPressed()
- }
-
- override fun onEventDispatched(event: ViewEvent) {
- super.onEventDispatched(event)
- when (event) {
- is SnackbarEvent -> snackbar(snackbarView, event.message(this), event.length, event.f)
- is PermissionEvent -> withPermissions(*event.permissions.toTypedArray()) {
- onSuccess { event.callback.onNext(true) }
- onFailure {
- event.callback.onNext(false)
- event.callback.onError(SecurityException("User refused permissions"))
- }
- }
- }
- }
-
- companion object {
-
- private fun intent(context: Context) = context.intent()
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- private fun intent(context: Context, file: File) = intent(context).setData(file.toUri())
-
- private fun flashType(isSecondSlot: Boolean) =
- if (isSecondSlot) Const.Value.FLASH_INACTIVE_SLOT else Const.Value.FLASH_MAGISK
-
- /* Flashing is understood as installing / flashing magisk itself */
-
- fun flashIntent(context: Context, file: File, isSecondSlot: Boolean, id : Int = -1)
- = intent(context, file)
- .putExtra(Const.Key.FLASH_ACTION, flashType(isSecondSlot))
- .putExtra(Const.Key.DISMISS_ID, id)
-
- fun flash(context: Context, file: File, isSecondSlot: Boolean, id: Int) =
- context.startActivity(flashIntent(context, file, isSecondSlot, id))
-
- /* Patching is understood as injecting img files with magisk */
-
- fun patchIntent(context: Context, file: File, uri: Uri, id : Int = -1)
- = intent(context, file)
- .putExtra(Const.Key.FLASH_DATA, uri)
- .putExtra(Const.Key.FLASH_ACTION, Const.Value.PATCH_FILE)
- .putExtra(Const.Key.DISMISS_ID, id)
-
- fun patch(context: Context, file: File, uri: Uri, id: Int) =
- context.startActivity(patchIntent(context, file, uri, id))
-
- /* Uninstalling is understood as removing magisk entirely */
-
- fun uninstallIntent(context: Context, file: File, id : Int = -1)
- = intent(context, file)
- .putExtra(Const.Key.FLASH_ACTION, Const.Value.UNINSTALL)
- .putExtra(Const.Key.DISMISS_ID, id)
-
- fun uninstall(context: Context, file: File, id: Int) =
- context.startActivity(uninstallIntent(context, file, id))
-
- /* Installing is understood as flashing modules / zips */
-
- fun installIntent(context: Context, file: File, id : Int = -1)
- = intent(context, file)
- .putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP)
- .putExtra(Const.Key.DISMISS_ID, id)
-
- fun install(context: Context, file: File, id: Int) =
- context.startActivity(installIntent(context, file, id))
-
- }
-
-}
diff --git a/app/src/main/java/com/topjohnwu/magisk/legacy/flash/FlashViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/legacy/flash/FlashViewModel.kt
deleted file mode 100644
index 67bff9ed4..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/legacy/flash/FlashViewModel.kt
+++ /dev/null
@@ -1,117 +0,0 @@
-package com.topjohnwu.magisk.legacy.flash
-
-import android.Manifest.permission.READ_EXTERNAL_STORAGE
-import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
-import android.content.Intent
-import android.content.res.Resources
-import android.net.Uri
-import android.os.Handler
-import android.view.MenuItem
-import androidx.core.os.postDelayed
-import androidx.databinding.ObservableArrayList
-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.MagiskInstaller
-import com.topjohnwu.magisk.extensions.*
-import com.topjohnwu.magisk.model.binding.BindingAdapter
-import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
-import com.topjohnwu.magisk.model.events.SnackbarEvent
-import com.topjohnwu.magisk.ui.base.BaseViewModel
-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 java.io.File
-import java.util.*
-
-class FlashViewModel(
- private val resources: Resources
-) : BaseViewModel(), FlashResultListener {
-
- val canShowReboot = Shell.rootAccess()
- val showRestartTitle = KObservableField(false)
-
- val behaviorText = KObservableField(resources.getString(R.string.flashing))
-
- val adapter = BindingAdapter()
- val items = diffListOf()
- val itemBinding = itemBindingOf()
-
- private val outItems = ObservableArrayList()
- private val logItems = Collections.synchronizedList(mutableListOf())
-
- init {
- outItems.sendUpdatesTo(items) { it.map { ConsoleItem(it) } }
- outItems.copyNewInputInto(logItems)
- }
-
- fun startFlashing(intent: Intent) {
- val installer = intent.data ?: return
- val uri: Uri? = intent.getParcelableExtra(Const.Key.FLASH_DATA)
- val action = intent.getStringExtra(Const.Key.FLASH_ACTION) ?: return
-
- when (action) {
- Const.Value.FLASH_ZIP -> Flashing
- .Install(installer, outItems, logItems, this)
- .exec()
- Const.Value.UNINSTALL -> Flashing
- .Uninstall(installer, outItems, logItems, this)
- .exec()
- Const.Value.FLASH_MAGISK -> MagiskInstaller
- .Direct(installer, outItems, logItems, this)
- .exec()
- Const.Value.FLASH_INACTIVE_SLOT -> MagiskInstaller
- .SecondSlot(installer, outItems, logItems, this)
- .exec()
- Const.Value.PATCH_FILE -> MagiskInstaller
- .Patch(installer, uri ?: return, outItems, logItems, this)
- .exec()
- }
- }
-
- override fun onResult(success: Boolean) {
- state = if (success) State.LOADED else State.LOADING_FAILED
- behaviorText.value = when {
- success -> resources.getString(R.string.done)
- else -> resources.getString(R.string.failure)
- }
-
- if (success) {
- Handler().postDelayed(500) {
- showRestartTitle.value = true
- }
- }
- }
-
- fun onMenuItemClicked(item: MenuItem): Boolean {
- when (item.itemId) {
- R.id.action_save -> savePressed()
- }
- return true
- }
-
- private fun savePressed() = withPermissions(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE)
- .map { now }
- .map { it.toTime(timeFormatStandard) }
- .map { Const.MAGISK_INSTALL_LOG_FILENAME.format(it) }
- .map { File(Config.downloadDirectory, it) }
- .map { file ->
- file.bufferedWriter().use { writer ->
- logItems.forEach {
- writer.write(it)
- writer.newLine()
- }
- }
- file.path
- }
- .subscribeK { SnackbarEvent(it).publish() }
- .add()
-
- fun restartPressed() = reboot()
-
- fun backPressed() = back()
-
-}
diff --git a/app/src/main/java/com/topjohnwu/magisk/model/events/InstallExternalModuleEvent.kt b/app/src/main/java/com/topjohnwu/magisk/model/events/InstallExternalModuleEvent.kt
index e4a955ecf..ba452a276 100644
--- a/app/src/main/java/com/topjohnwu/magisk/model/events/InstallExternalModuleEvent.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/model/events/InstallExternalModuleEvent.kt
@@ -2,13 +2,12 @@ package com.topjohnwu.magisk.model.events
import android.Manifest
import android.app.Activity
-import android.content.Context
import android.content.Intent
import androidx.annotation.RequiresPermission
+import androidx.navigation.NavDirections
+import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.base.BaseActivity
-import com.topjohnwu.magisk.core.intent
-import com.topjohnwu.magisk.legacy.flash.FlashActivity
class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor {
@@ -21,13 +20,14 @@ class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor {
companion object {
- fun onActivityResult(context: Context, requestCode: Int, resultCode: Int, data: Intent?) {
+ fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): NavDirections? {
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
- // Get the URI of the selected file
- val intent = context.intent()
- intent.setData(data.data).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP)
- context.startActivity(intent)
+ val data = data.data
+ if (data != null) {
+ return MainDirections.actionFlashFragment(data, Const.Key.FLASH_ACTION)
+ }
}
+ return null
}
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseUIActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseUIActivity.kt
index 6cc96d67e..96a3e8cf8 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseUIActivity.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/base/BaseUIActivity.kt
@@ -9,6 +9,8 @@ import androidx.core.graphics.Insets
import androidx.databinding.DataBindingUtil
import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.Observer
import androidx.navigation.NavDirections
import androidx.navigation.findNavController
import com.topjohnwu.magisk.BR
@@ -71,6 +73,14 @@ abstract class BaseUIActivity()
+
+ fun postDirections(navDirections: NavDirections) =
+ directionsDispatcher.postValue(navDirections)
+
+ }
+
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt
index 009cc6e5f..4871ebd8f 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashFragment.kt
@@ -1,13 +1,147 @@
package com.topjohnwu.magisk.ui.flash
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.PendingIntent
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.net.Uri
+import android.os.Bundle
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
+import androidx.core.net.toUri
+import androidx.navigation.NavDeepLinkBuilder
import com.topjohnwu.magisk.R
+import com.topjohnwu.magisk.core.ClassMap
+import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.FragmentFlashMd2Binding
+import com.topjohnwu.magisk.ui.MainActivity
+import com.topjohnwu.magisk.ui.base.BaseUIActivity
import com.topjohnwu.magisk.ui.base.BaseUIFragment
import org.koin.androidx.viewmodel.ext.android.viewModel
+import org.koin.core.parameter.parametersOf
+import java.io.File
+import com.topjohnwu.magisk.MainDirections.Companion.actionFlashFragment as toFlash
+import com.topjohnwu.magisk.ui.flash.FlashFragmentArgs as args
class FlashFragment : BaseUIFragment() {
override val layoutRes = R.layout.fragment_flash_md2
- override val viewModel by viewModel()
+ override val viewModel by viewModel {
+ parametersOf(args.fromBundle(requireArguments()))
+ }
+
+ private var defaultOrientation = -1
+
+ override fun onStart() {
+ super.onStart()
+ setHasOptionsMenu(true)
+ activity.setTitle(R.string.flash_screen_title)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ inflater.inflate(R.menu.menu_flash, menu)
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ return viewModel.onMenuItemClicked(item)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ defaultOrientation = activity.requestedOrientation
+ activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
+ }
+
+ @SuppressLint("WrongConstant")
+ override fun onDestroyView() {
+ if (defaultOrientation != -1) {
+ activity.requestedOrientation = defaultOrientation
+ }
+ super.onDestroyView()
+ }
+
+ override fun onBackPressed(): Boolean {
+ if (viewModel.loading) return true
+ return super.onBackPressed()
+ }
+
+ override fun onPreBind(binding: FragmentFlashMd2Binding) = Unit
+
+ companion object {
+
+ private fun createIntent(context: Context, args: args): PendingIntent {
+ return NavDeepLinkBuilder(context)
+ .setGraph(R.navigation.main)
+ .setComponentName(ClassMap[MainActivity::class.java] as Class)
+ .setDestination(R.id.flashFragment)
+ .setArguments(args.toBundle())
+ .createPendingIntent()
+ }
+
+ private fun flashType(isSecondSlot: Boolean) =
+ if (isSecondSlot) Const.Value.FLASH_INACTIVE_SLOT else Const.Value.FLASH_MAGISK
+
+ /* Flashing is understood as installing / flashing magisk itself */
+
+ fun flashIntent(context: Context, file: File, isSecondSlot: Boolean, id: Int = -1) = args(
+ installer = file.toUri(),
+ action = flashType(isSecondSlot),
+ dismissId = id
+ ).let { createIntent(context, it) }
+
+ fun flash(file: File, isSecondSlot: Boolean, id: Int) = toFlash(
+ installer = file.toUri(),
+ action = flashType(isSecondSlot),
+ dismissId = id
+ ).let { BaseUIActivity.postDirections(it) }
+
+ /* Patching is understood as injecting img files with magisk */
+
+ fun patchIntent(context: Context, file: File, uri: Uri, id: Int = -1) = args(
+ installer = file.toUri(),
+ action = Const.Value.PATCH_FILE,
+ additionalData = uri,
+ dismissId = id
+ ).let { createIntent(context, it) }
+
+ fun patch(file: File, uri: Uri, id: Int) = toFlash(
+ installer = file.toUri(),
+ action = Const.Value.PATCH_FILE,
+ additionalData = uri,
+ dismissId = id
+ ).let { BaseUIActivity.postDirections(it) }
+
+ /* Uninstalling is understood as removing magisk entirely */
+
+ fun uninstallIntent(context: Context, file: File, id: Int = -1) = args(
+ installer = file.toUri(),
+ action = Const.Value.UNINSTALL,
+ dismissId = id
+ ).let { createIntent(context, it) }
+
+ fun uninstall(file: File, id: Int) = toFlash(
+ installer = file.toUri(),
+ action = Const.Value.UNINSTALL,
+ dismissId = id
+ ).let { BaseUIActivity.postDirections(it) }
+
+ /* Installing is understood as flashing modules / zips */
+
+ fun installIntent(context: Context, file: File, id: Int = -1) = args(
+ installer = file.toUri(),
+ action = Const.Value.FLASH_ZIP,
+ dismissId = id
+ ).let { createIntent(context, it) }
+
+ fun install(file: File, id: Int) = toFlash(
+ installer = file.toUri(),
+ action = Const.Value.FLASH_ZIP,
+ dismissId = id
+ ).let { BaseUIActivity.postDirections(it) }
+ }
}
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
index 4f1b716ed..3747c5c36 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/flash/FlashViewModel.kt
@@ -1,5 +1,141 @@
package com.topjohnwu.magisk.ui.flash
+import android.Manifest
+import android.content.res.Resources
+import android.net.Uri
+import android.os.Handler
+import android.view.MenuItem
+import androidx.core.os.postDelayed
+import androidx.databinding.ObservableArrayList
+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.MagiskInstaller
+import com.topjohnwu.magisk.core.view.Notifications
+import com.topjohnwu.magisk.extensions.*
+import com.topjohnwu.magisk.model.binding.BindingAdapter
+import com.topjohnwu.magisk.model.entity.recycler.ConsoleItem
+import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.ui.base.BaseViewModel
+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 java.io.File
+import java.util.*
-class FlashViewModel : BaseViewModel()
+class FlashViewModel(
+ private val args: FlashFragmentArgs,
+ private val resources: Resources
+) : BaseViewModel(),
+ FlashResultListener {
+
+ val canShowReboot = Shell.rootAccess()
+ val showRestartTitle = KObservableField(false)
+
+ val behaviorText = KObservableField(resources.getString(R.string.flashing))
+
+ val adapter = BindingAdapter()
+ val items = diffListOf()
+ val itemBinding = itemBindingOf()
+
+ private val outItems = ObservableArrayList()
+ private val logItems =
+ Collections.synchronizedList(mutableListOf())
+
+ init {
+ outItems.sendUpdatesTo(items) { it.map { ConsoleItem(it) } }
+ outItems.copyNewInputInto(logItems)
+
+ args.dismissId.takeIf { it != -1 }?.also {
+ Notifications.mgr.cancel(it)
+ }
+ val (installer, action, uri) = args
+ startFlashing(installer, uri, action)
+ }
+
+ private fun startFlashing(installer: Uri, uri: Uri?, action: String) {
+ when (action) {
+ Const.Value.FLASH_ZIP -> Flashing.Install(
+ installer,
+ outItems,
+ logItems,
+ this
+ ).exec()
+ Const.Value.UNINSTALL -> Flashing.Uninstall(
+ installer,
+ outItems,
+ logItems,
+ this
+ ).exec()
+ Const.Value.FLASH_MAGISK -> MagiskInstaller.Direct(
+ installer,
+ outItems,
+ logItems,
+ this
+ ).exec()
+ Const.Value.FLASH_INACTIVE_SLOT -> MagiskInstaller.SecondSlot(
+ installer,
+ outItems,
+ logItems,
+ this
+ ).exec()
+ Const.Value.PATCH_FILE -> MagiskInstaller.Patch(
+ installer,
+ uri ?: return,
+ outItems,
+ logItems,
+ this
+ ).exec()
+ else -> backPressed()
+ }
+ }
+
+ override fun onResult(success: Boolean) {
+ state = if (success) State.LOADED else State.LOADING_FAILED
+ behaviorText.value = when {
+ success -> resources.getString(R.string.done)
+ else -> resources.getString(R.string.failure)
+ }
+
+ if (success) {
+ Handler().postDelayed(500) {
+ showRestartTitle.value = true
+ }
+ }
+ }
+
+ fun onMenuItemClicked(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.action_save -> savePressed()
+ }
+ return true
+ }
+
+ private fun savePressed() = withPermissions(
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+ .map { now }
+ .map { it.toTime(timeFormatStandard) }
+ .map { Const.MAGISK_INSTALL_LOG_FILENAME.format(it) }
+ .map { File(Config.downloadDirectory, it) }
+ .map { file ->
+ file.bufferedWriter().use { writer ->
+ logItems.forEach {
+ writer.write(it)
+ writer.newLine()
+ }
+ }
+ file.path
+ }
+ .subscribeK { SnackbarEvent(it).publish() }
+ .add()
+
+ fun restartPressed() = reboot()
+
+ fun backPressed() = back()
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt
index 2d8fa4110..5dfd530ed 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt
@@ -40,7 +40,7 @@ class InstallViewModel : BaseViewModel(State.LOADED) {
this.progress.value = progress.times(100).roundToInt()
if (this.progress.value >= 100) {
// this might cause issues if the flash activity launches on top of this sooner
- back()
+ // back()
}
}
method.addOnPropertyChangedCallback {
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt
index e172ba9c3..3f194608d 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/module/ModuleFragment.kt
@@ -42,7 +42,9 @@ class ModuleFragment : BaseUIFragment
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- InstallExternalModuleEvent.onActivityResult(requireContext(), requestCode, resultCode, data)
+ InstallExternalModuleEvent.onActivityResult(requestCode, resultCode, data)?.also {
+ it.navigate()
+ }
}
override fun onStart() {
diff --git a/app/src/main/res/layout/activity_flash.xml b/app/src/main/res/layout/activity_flash.xml
deleted file mode 100644
index 17a46775e..000000000
--- a/app/src/main/res/layout/activity_flash.xml
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/fragment_flash_md2.xml b/app/src/main/res/layout/fragment_flash_md2.xml
index 55900f5c7..aa2d61da0 100644
--- a/app/src/main/res/layout/fragment_flash_md2.xml
+++ b/app/src/main/res/layout/fragment_flash_md2.xml
@@ -1,5 +1,7 @@
-
+
@@ -9,15 +11,74 @@
-
+ android:layout_height="match_parent">
-
+ android:layout_height="match_parent"
+ android:layout_marginTop="@{viewModel.insets.top + (int) @dimen/internal_action_bar_size}"
+ tools:layout_marginTop="@dimen/internal_action_bar_size">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/navigation/main.xml b/app/src/main/res/navigation/main.xml
index ca0254d91..f75adda2e 100644
--- a/app/src/main/res/navigation/main.xml
+++ b/app/src/main/res/navigation/main.xml
@@ -35,6 +35,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 715a80d79..024001f81 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -61,6 +61,7 @@
Select and Patch a File
Select a raw image (*.img) or an ODIN tarfile (*.tar)
Rebooting in 5 seconds…
+ Installation
Superuser Request