Magisk/app/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt
topjohnwu ec8fffe61c Merge Magisk install zip into Magisk Manager
Distribute Magisk directly with Magisk Manager APK. The APK will
contain all required binaries and scripts for installation and
uninstallation. App versions will now align with Magisk releases.

Extra effort is spent to make the APK itself also a flashable zip that
can be used in custom recoveries, so those still prefer to install
Magisk with recoveries will not be affected with this change.

As a bonus, this makes the whole installation and uninstallation
process 100% offline. The existing Magisk Manager was not really
functional without an Internet connection, as the installation process
was highly tied to zips hosted on the server.

An additional bonus: since all binaries are now shipped as "native
libraries" of the APK, we can finally bump the target SDK version
higher than 28. The target SDK version was stuck at 28 for a long time
because newer SELinux restricts running executables from internal
storage. More details can be found here: https://github.com/termux/termux-app/issues/1072
The target SDK bump will be addressed in a future commit.

Co-authored with @vvb2060
2021-01-22 02:29:54 -08:00

123 lines
3.9 KiB
Kotlin

package com.topjohnwu.magisk.events
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.view.View
import android.widget.Toast
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.*
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.base.ActivityResultCallback
import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.core.model.module.OnlineModule
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.magisk.view.Shortcuts
import kotlinx.coroutines.launch
class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) = action(activity)
}
class OpenReadmeEvent(val item: OnlineModule) : ViewEventWithScope(), ContextExecutor {
override fun invoke(context: Context) {
scope.launch {
MarkDownWindow.show(context, null, item::notes)
}
}
}
class PermissionEvent(
private val permission: String,
private val callback: (Boolean) -> Unit
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) =
activity.withPermission(permission) {
onSuccess {
callback(true)
}
onFailure {
callback(false)
}
}
}
class BackPressEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
activity.onBackPressed()
}
}
class DieEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
activity.finish()
}
}
class ShowUIEvent(private val delegate: View.AccessibilityDelegate?)
: ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
activity.setContentView()
activity.setAccessibilityDelegate(delegate)
}
}
class RecreateEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
activity.recreate()
}
}
class MagiskInstallFileEvent(private val callback: ActivityResultCallback)
: ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
val intent = Intent(Intent.ACTION_GET_CONTENT).setType("*/*")
try {
activity.startActivityForResult(intent, Const.ID.SELECT_FILE, callback)
Utils.toast(R.string.patch_file_msg, Toast.LENGTH_LONG)
} catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT)
}
}
}
class NavigationEvent(
private val directions: NavDirections
) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseUIActivity<*, *>) {
(activity as? BaseUIActivity<*, *>)?.apply {
directions.navigate()
}
}
}
class AddHomeIconEvent : ViewEvent(), ContextExecutor {
override fun invoke(context: Context) {
Shortcuts.addHomeIcon(context)
}
}
class SelectModuleEvent : ViewEvent(), FragmentExecutor {
override fun invoke(fragment: BaseUIFragment<*, *>) {
val intent = Intent(Intent.ACTION_GET_CONTENT).setType("application/zip")
try {
fragment.apply {
activity.startActivityForResult(intent, Const.ID.FETCH_ZIP) { code, intent ->
if (code == Activity.RESULT_OK && intent != null) {
intent.data?.also {
MainDirections.actionFlashFragment(Const.Value.FLASH_ZIP, it).navigate()
}
}
}
}
} catch (e: ActivityNotFoundException) {
Utils.toast(R.string.app_not_found, Toast.LENGTH_SHORT)
}
}
}