mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 22:27:39 +00:00
Added most of the remaining functionality for Magisk install dialog
This commit is contained in:
parent
dc09ec7598
commit
8a014ff786
@ -177,7 +177,9 @@ fun Intent.toCommand(args: MutableList<String>) {
|
|||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
val len = java.lang.reflect.Array.getLength(v)
|
val len = java.lang.reflect.Array.getLength(v)
|
||||||
for (i in 0 until len) {
|
for (i in 0 until len) {
|
||||||
sb.append(java.lang.reflect.Array.get(v, i)!!.toString().replace(",", "\\,"))
|
sb.append(
|
||||||
|
java.lang.reflect.Array.get(v, i)!!.toString().replace(",", "\\,")
|
||||||
|
)
|
||||||
sb.append(',')
|
sb.append(',')
|
||||||
}
|
}
|
||||||
// Remove trailing comma
|
// Remove trailing comma
|
||||||
@ -262,10 +264,10 @@ fun Context.startEndToLeftRight(start: Int, end: Int): Pair<Int, Int> {
|
|||||||
fun Context.openUrl(url: String) = Utils.openLink(this, url.toUri())
|
fun Context.openUrl(url: String) = Utils.openLink(this, url.toUri())
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
inline fun <reified T> T.DynamicClassLoader(apk: File)
|
inline fun <reified T> T.DynamicClassLoader(apk: File) =
|
||||||
= DynamicClassLoader(apk, T::class.java.classLoader)
|
DynamicClassLoader(apk, T::class.java.classLoader)
|
||||||
|
|
||||||
fun Context.unwrap() : Context {
|
fun Context.unwrap(): Context {
|
||||||
var context = this
|
var context = this
|
||||||
while (true) {
|
while (true) {
|
||||||
if (context is ContextWrapper)
|
if (context is ContextWrapper)
|
||||||
@ -275,3 +277,7 @@ fun Context.unwrap() : Context {
|
|||||||
}
|
}
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.hasPermissions(vararg permissions: String) = permissions.all {
|
||||||
|
ContextCompat.checkSelfPermission(this, it) == PERMISSION_GRANTED
|
||||||
|
}
|
@ -1,11 +1,19 @@
|
|||||||
package com.topjohnwu.magisk.model.events.dialog
|
package com.topjohnwu.magisk.model.events.dialog
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.net.Uri
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.widget.Toast
|
||||||
import com.topjohnwu.magisk.Info
|
import com.topjohnwu.magisk.Info
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.IncludeInstallOptionsBinding
|
import com.topjohnwu.magisk.databinding.IncludeInstallOptionsBinding
|
||||||
|
import com.topjohnwu.magisk.extensions.hasPermissions
|
||||||
import com.topjohnwu.magisk.extensions.res
|
import com.topjohnwu.magisk.extensions.res
|
||||||
|
import com.topjohnwu.magisk.model.download.DownloadService
|
||||||
|
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||||
|
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||||
import com.topjohnwu.magisk.model.events.OpenInappLinkEvent
|
import com.topjohnwu.magisk.model.events.OpenInappLinkEvent
|
||||||
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
import com.topjohnwu.magisk.view.MagiskDialog
|
import com.topjohnwu.magisk.view.MagiskDialog
|
||||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
@ -15,8 +23,10 @@ class MagiskInstallDialog : DialogEvent() {
|
|||||||
|
|
||||||
override fun build(dialog: MagiskDialog) {
|
override fun build(dialog: MagiskDialog) {
|
||||||
with(dialog) {
|
with(dialog) {
|
||||||
val filename =
|
val filename = "Magisk v%s (%d)".format(
|
||||||
"Magisk v${Info.remote.magisk.version}(${Info.remote.magisk.versionCode})"
|
Info.remote.magisk.version,
|
||||||
|
Info.remote.magisk.versionCode
|
||||||
|
)
|
||||||
applyTitle(R.string.repo_install_title.res(R.string.magisk.res()))
|
applyTitle(R.string.repo_install_title.res(R.string.magisk.res()))
|
||||||
applyMessage(R.string.repo_install_msg.res(filename))
|
applyMessage(R.string.repo_install_msg.res(filename))
|
||||||
setCancelable(true)
|
setCancelable(true)
|
||||||
@ -24,9 +34,10 @@ class MagiskInstallDialog : DialogEvent() {
|
|||||||
titleRes = R.string.install
|
titleRes = R.string.install
|
||||||
preventDismiss = true
|
preventDismiss = true
|
||||||
onClick {
|
onClick {
|
||||||
updateForInstallMethod(dialog)
|
updateForInstallMethod(dialog.reset())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Info.remote.magisk.note.isEmpty()) return
|
if (Info.remote.magisk.note.isEmpty()) return
|
||||||
applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
titleRes = R.string.release_notes
|
titleRes = R.string.release_notes
|
||||||
@ -44,38 +55,75 @@ class MagiskInstallDialog : DialogEvent() {
|
|||||||
private fun updateForInstallMethod(dialog: MagiskDialog) {
|
private fun updateForInstallMethod(dialog: MagiskDialog) {
|
||||||
with(dialog) {
|
with(dialog) {
|
||||||
applyTitle(R.string.select_method)
|
applyTitle(R.string.select_method)
|
||||||
applyMessage("")
|
|
||||||
applyView(IncludeInstallOptionsBinding.inflate(LayoutInflater.from(dialog.context)))
|
applyView(IncludeInstallOptionsBinding.inflate(LayoutInflater.from(dialog.context)))
|
||||||
applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
titleRes = R.string.download_zip_only
|
titleRes = R.string.download_zip_only
|
||||||
onClick {
|
onClick {
|
||||||
preventDismiss = false
|
preventDismiss = false
|
||||||
TODO()
|
download()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applyButton(MagiskDialog.ButtonType.NEUTRAL) {
|
applyButton(MagiskDialog.ButtonType.NEUTRAL) {
|
||||||
|
isEnabled = false
|
||||||
titleRes = R.string.select_patch_file
|
titleRes = R.string.select_patch_file
|
||||||
onClick {
|
// todo maybe leverage rxbus for this?
|
||||||
TODO()
|
onClick { Utils.toast("This is not currently possible", Toast.LENGTH_LONG) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Shell.rootAccess()) return
|
if (!Shell.rootAccess()) return
|
||||||
applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
titleRes = R.string.direct_install
|
titleRes = R.string.direct_install
|
||||||
onClick {
|
onClick { flash() }
|
||||||
TODO()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isABDevice()) return
|
if (!isABDevice()) return
|
||||||
applyButton(MagiskDialog.ButtonType.IDGAF) {
|
applyButton(MagiskDialog.ButtonType.IDGAF) {
|
||||||
titleRes = R.string.install_inactive_slot
|
titleRes = R.string.install_inactive_slot
|
||||||
onClick {
|
preventDismiss = true
|
||||||
TODO()
|
onClick { inactiveSlotDialog(dialog.reset()) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun inactiveSlotDialog(dialog: MagiskDialog) {
|
||||||
|
dialog.applyTitle(R.string.warning)
|
||||||
|
.applyMessage(R.string.install_inactive_slot_msg)
|
||||||
|
.applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||||
|
titleRes = R.string.yes
|
||||||
|
onClick {
|
||||||
|
flash(Configuration.Flash.Secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||||
|
titleRes = R.string.no_thanks
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
private fun hasPermissions() = dialog.context.hasPermissions(
|
||||||
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun patch(data: Uri) = download(DownloadSubject.Magisk(Configuration.Patch(data)))
|
||||||
|
|
||||||
|
private fun flash(
|
||||||
|
type: Configuration.Flash = Configuration.Flash.Primary
|
||||||
|
) = download(DownloadSubject.Magisk(type))
|
||||||
|
|
||||||
|
private fun download(
|
||||||
|
type: DownloadSubject.Magisk = DownloadSubject.Magisk(Configuration.Download)
|
||||||
|
) {
|
||||||
|
if (!hasPermissions()) {
|
||||||
|
Utils.toast("Storage permissions are required for this action", Toast.LENGTH_LONG)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
DownloadService(dialog.context) { subject = type }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
private fun isABDevice() = ShellUtils
|
private fun isABDevice() = ShellUtils
|
||||||
.fastCmd("grep_prop ro.build.ab_update")
|
.fastCmd("grep_prop ro.build.ab_update")
|
||||||
.let { it.isNotEmpty() && it.toBoolean() }
|
.let { it.isNotEmpty() && it.toBoolean() }
|
||||||
|
@ -58,8 +58,20 @@ class MagiskDialog @JvmOverloads constructor(
|
|||||||
var preventDismiss = false
|
var preventDismiss = false
|
||||||
|
|
||||||
fun clicked() {
|
fun clicked() {
|
||||||
|
//we might not want the click to dismiss the button to begin with
|
||||||
|
var prevention = preventDismiss
|
||||||
|
|
||||||
onClickAction(this@MagiskDialog)
|
onClickAction(this@MagiskDialog)
|
||||||
if (!preventDismiss) {
|
|
||||||
|
//in case we don't want the dialog to close after clicking the button
|
||||||
|
//ie. the input is incorrect ...
|
||||||
|
//otherwise we disregard the request, bcs it just might reset the button in the new
|
||||||
|
//instance
|
||||||
|
if (preventDismiss) {
|
||||||
|
prevention = preventDismiss
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prevention) {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,7 +143,7 @@ class MagiskDialog @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun <Binding : ViewDataBinding> applyView(binding: Binding, body: Binding.() -> Unit = {}) =
|
fun <Binding : ViewDataBinding> applyView(binding: Binding, body: Binding.() -> Unit = {}) =
|
||||||
apply {
|
apply {
|
||||||
this.binding.dialogBaseContainer.removeAllViews()
|
resetView()
|
||||||
this.binding.dialogBaseContainer.addView(binding.root)
|
this.binding.dialogBaseContainer.addView(binding.root)
|
||||||
binding.apply(body)
|
binding.apply(body)
|
||||||
}
|
}
|
||||||
@ -144,6 +156,34 @@ class MagiskDialog @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun reveal() = apply { super.show() }
|
fun reveal() = apply { super.show() }
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
fun resetView() = apply {
|
||||||
|
binding.dialogBaseContainer.removeAllViews()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetTitle() = applyTitle("")
|
||||||
|
fun resetMessage() = applyMessage("")
|
||||||
|
fun resetIcon() = applyIcon(0)
|
||||||
|
|
||||||
|
fun resetButtons() = apply {
|
||||||
|
ButtonType.values().forEach {
|
||||||
|
applyButton(it) {
|
||||||
|
title = ""
|
||||||
|
icon = 0
|
||||||
|
isEnabled = true
|
||||||
|
preventDismiss = false
|
||||||
|
onClick {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() = resetTitle()
|
||||||
|
.resetMessage()
|
||||||
|
.resetView()
|
||||||
|
.resetIcon()
|
||||||
|
.resetButtons()
|
||||||
|
|
||||||
//region Deprecated Members
|
//region Deprecated Members
|
||||||
@Deprecated("Use applyTitle instead", ReplaceWith("applyTitle"))
|
@Deprecated("Use applyTitle instead", ReplaceWith("applyTitle"))
|
||||||
override fun setTitle(title: CharSequence?) = Unit
|
override fun setTitle(title: CharSequence?) = Unit
|
||||||
|
Loading…
x
Reference in New Issue
Block a user