Updated flash screen so it's a fragment

The FlashActivity has been removed and all of it's functionality has been transferred to the FlashFragment.
The FlashFragment needs to be however launched in a different way than the activity using the MainActivity's stub and so seemingly massive changes had to be made.

Notably the RemoteFileService didn't seem to be calling Service.startForeground(), which has been crashing the application due to the system requirements, so that's been fixed.
This commit is contained in:
Viktor De Pasquale
2020-03-24 18:07:20 +01:00
committed by John Wu
parent fc2d0246e6
commit 6907651756
19 changed files with 435 additions and 369 deletions
@@ -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<FlashViewModel, FragmentFlashMd2Binding>() {
override val layoutRes = R.layout.fragment_flash_md2
override val viewModel by viewModel<FlashViewModel>()
override val viewModel by viewModel<FlashViewModel> {
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<out Activity>)
.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) }
}
}
@@ -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<ConsoleItem>()
val items = diffListOf<ConsoleItem>()
val itemBinding = itemBindingOf<ConsoleItem>()
private val outItems = ObservableArrayList<String>()
private val logItems =
Collections.synchronizedList(mutableListOf<String>())
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()
}