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