mirror of
https://github.com/topjohnwu/Magisk
synced 2025-11-09 00:32:30 +01:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb64ba0ef6 | ||
|
|
d89a568897 | ||
|
|
9fd1f41e8b | ||
|
|
c1ab348673 | ||
|
|
00247c7901 | ||
|
|
3c75f474c6 | ||
|
|
db1f5b0397 | ||
|
|
db277c3e55 | ||
|
|
b9c93c66f6 | ||
|
|
a250e2b56c | ||
|
|
cd96454886 | ||
|
|
741b679306 | ||
|
|
90013e486d | ||
|
|
4e2ecdb920 | ||
|
|
6e5df1f06b | ||
|
|
9469e79e3c | ||
|
|
db78c20161 | ||
|
|
1699da1754 | ||
|
|
754e690274 | ||
|
|
6f74ed6ceb | ||
|
|
71205bc530 | ||
|
|
10e236abdf | ||
|
|
2248af00f3 | ||
|
|
7e61716277 | ||
|
|
50edb8d072 | ||
|
|
515f81944c | ||
|
|
46d4708386 | ||
|
|
aabc36f86b | ||
|
|
e0d5d90267 | ||
|
|
482a5b991b | ||
|
|
20124fe410 | ||
|
|
f8dcec116a | ||
|
|
343a339aae | ||
|
|
42606efe56 | ||
|
|
cae58c8790 | ||
|
|
3a39dd4049 | ||
|
|
89ff3c6572 | ||
|
|
7bf9c74216 | ||
|
|
e2f3753551 |
@@ -19,7 +19,7 @@ Some highlight features:
|
|||||||
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
|
[Github](https://github.com/topjohnwu/Magisk/) is the only source where you can get official Magisk information and downloads.
|
||||||
|
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v24.3)
|
[](https://github.com/topjohnwu/Magisk/releases/tag/v24.3)
|
||||||
[](https://github.com/topjohnwu/Magisk/releases/tag/v24.3)
|
[](https://github.com/topjohnwu/Magisk/releases/tag/v25.0)
|
||||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
|
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-release.apk)
|
||||||
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
|
[](https://raw.githubusercontent.com/topjohnwu/magisk-files/canary/app-debug.apk)
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ dependencies {
|
|||||||
implementation("com.squareup.moshi:moshi:${vMoshi}")
|
implementation("com.squareup.moshi:moshi:${vMoshi}")
|
||||||
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
|
kapt("com.squareup.moshi:moshi-kotlin-codegen:${vMoshi}")
|
||||||
|
|
||||||
val vRoom = "2.4.2"
|
val vRoom = "2.5.0-alpha02"
|
||||||
implementation("androidx.room:room-runtime:${vRoom}")
|
implementation("androidx.room:room-runtime:${vRoom}")
|
||||||
implementation("androidx.room:room-ktx:${vRoom}")
|
implementation("androidx.room:room-ktx:${vRoom}")
|
||||||
kapt("androidx.room:room-compiler:${vRoom}")
|
kapt("androidx.room:room-compiler:${vRoom}")
|
||||||
@@ -109,12 +109,12 @@ dependencies {
|
|||||||
implementation("androidx.biometric:biometric:1.1.0")
|
implementation("androidx.biometric:biometric:1.1.0")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
||||||
implementation("androidx.appcompat:appcompat:1.4.1")
|
implementation("androidx.appcompat:appcompat:1.4.2")
|
||||||
implementation("androidx.preference:preference:1.2.0")
|
implementation("androidx.preference:preference:1.2.0")
|
||||||
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
implementation("androidx.recyclerview:recyclerview:1.2.1")
|
||||||
implementation("androidx.fragment:fragment-ktx:1.4.1")
|
implementation("androidx.fragment:fragment-ktx:1.4.1")
|
||||||
implementation("androidx.transition:transition:1.4.1")
|
implementation("androidx.transition:transition:1.4.1")
|
||||||
implementation("androidx.core:core-ktx:1.7.0")
|
implementation("androidx.core:core-ktx:1.8.0")
|
||||||
implementation("androidx.core:core-splashscreen:1.0.0-rc01")
|
implementation("androidx.core:core-splashscreen:1.0.0-rc01")
|
||||||
implementation("com.google.android.material:material:1.6.0")
|
implementation("com.google.android.material:material:1.6.1")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
android:name=".ui.surequest.SuRequestActivity"
|
android:name=".ui.surequest.SuRequestActivity"
|
||||||
android:directBootAware="true"
|
android:directBootAware="true"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
android:taskAffinity=""
|
||||||
tools:ignore="AppLinkUrlError">
|
tools:ignore="AppLinkUrlError">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.topjohnwu.magisk.arch
|
||||||
|
|
||||||
|
import androidx.annotation.MainThread
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
abstract class AsyncLoadViewModel : BaseViewModel() {
|
||||||
|
|
||||||
|
private var loadingJob: Job? = null
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
fun startLoading() {
|
||||||
|
if (loadingJob?.isActive == true) {
|
||||||
|
// Prevent multiple jobs from running at the same time
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadingJob = viewModelScope.launch { doLoadWork() }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract suspend fun doLoadWork()
|
||||||
|
}
|
||||||
@@ -76,7 +76,10 @@ abstract class BaseFragment<Binding : ViewDataBinding> : Fragment(), ViewModelHo
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
viewModel.requestRefresh()
|
viewModel.let {
|
||||||
|
if (it is AsyncLoadViewModel)
|
||||||
|
it.startLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun onPreBind(binding: Binding) {
|
protected open fun onPreBind(binding: Binding) {
|
||||||
|
|||||||
@@ -4,61 +4,29 @@ import android.Manifest.permission.REQUEST_INSTALL_PACKAGES
|
|||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.databinding.Bindable
|
|
||||||
import androidx.databinding.PropertyChangeRegistry
|
import androidx.databinding.PropertyChangeRegistry
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import com.topjohnwu.magisk.BR
|
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.databinding.ObservableHost
|
import com.topjohnwu.magisk.databinding.ObservableHost
|
||||||
import com.topjohnwu.magisk.databinding.set
|
|
||||||
import com.topjohnwu.magisk.events.BackPressEvent
|
import com.topjohnwu.magisk.events.BackPressEvent
|
||||||
import com.topjohnwu.magisk.events.NavigationEvent
|
import com.topjohnwu.magisk.events.NavigationEvent
|
||||||
import com.topjohnwu.magisk.events.PermissionEvent
|
import com.topjohnwu.magisk.events.PermissionEvent
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
|
|
||||||
abstract class BaseViewModel(
|
abstract class BaseViewModel : ViewModel(), ObservableHost {
|
||||||
initialState: State = State.LOADING
|
|
||||||
) : ViewModel(), ObservableHost {
|
|
||||||
|
|
||||||
override var callbacks: PropertyChangeRegistry? = null
|
override var callbacks: PropertyChangeRegistry? = null
|
||||||
|
|
||||||
enum class State {
|
|
||||||
LOADED, LOADING, LOADING_FAILED
|
|
||||||
}
|
|
||||||
|
|
||||||
@get:Bindable
|
|
||||||
val loading get() = state == State.LOADING
|
|
||||||
@get:Bindable
|
|
||||||
val loaded get() = state == State.LOADED
|
|
||||||
@get:Bindable
|
|
||||||
val loadFailed get() = state == State.LOADING_FAILED
|
|
||||||
|
|
||||||
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
|
|
||||||
|
|
||||||
var state= initialState
|
|
||||||
set(value) = set(value, field, { field = it }, BR.loading, BR.loaded, BR.loadFailed)
|
|
||||||
|
|
||||||
private val _viewEvents = MutableLiveData<ViewEvent>()
|
private val _viewEvents = MutableLiveData<ViewEvent>()
|
||||||
private var runningJob: Job? = null
|
val viewEvents: LiveData<ViewEvent> get() = _viewEvents
|
||||||
|
|
||||||
open fun onSaveState(state: Bundle) {}
|
open fun onSaveState(state: Bundle) {}
|
||||||
open fun onRestoreState(state: Bundle) {}
|
open fun onRestoreState(state: Bundle) {}
|
||||||
|
open fun onNetworkChanged(network: Boolean) {}
|
||||||
/** This should probably never be called manually, it's called manually via delegate. */
|
|
||||||
@Synchronized
|
|
||||||
fun requestRefresh() {
|
|
||||||
if (runningJob?.isActive == true) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
runningJob = refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun refresh(): Job? = null
|
|
||||||
|
|
||||||
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
|
fun withPermission(permission: String, callback: (Boolean) -> Unit) {
|
||||||
PermissionEvent(permission, callback).publish()
|
PermissionEvent(permission, callback).publish()
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ abstract class UIActivity<Binding : ViewDataBinding> : BaseActivity(), ViewModel
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
viewModel.requestRefresh()
|
viewModel.let {
|
||||||
|
if (it is AsyncLoadViewModel)
|
||||||
|
it.startLoading()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEventDispatched(event: ViewEvent) = when (event) {
|
override fun onEventDispatched(event: ViewEvent) = when (event) {
|
||||||
|
|||||||
@@ -17,12 +17,8 @@ interface ViewModelHolder : LifecycleOwner, ViewModelStoreOwner {
|
|||||||
val viewModel: BaseViewModel
|
val viewModel: BaseViewModel
|
||||||
|
|
||||||
fun startObserveLiveData() {
|
fun startObserveLiveData() {
|
||||||
viewModel.viewEvents.observe(this) {
|
viewModel.viewEvents.observe(this, this::onEventDispatched)
|
||||||
onEventDispatched(it)
|
Info.isConnected.observe(this, viewModel::onNetworkChanged)
|
||||||
}
|
|
||||||
Info.isConnected.observe(this) {
|
|
||||||
viewModel.requestRefresh()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import com.topjohnwu.magisk.core.repository.NetworkService
|
|||||||
import com.topjohnwu.magisk.core.utils.net.NetworkObserver
|
import com.topjohnwu.magisk.core.utils.net.NetworkObserver
|
||||||
import com.topjohnwu.magisk.ktx.getProperty
|
import com.topjohnwu.magisk.ktx.getProperty
|
||||||
import com.topjohnwu.superuser.ShellUtils.fastCmd
|
import com.topjohnwu.superuser.ShellUtils.fastCmd
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
|
||||||
|
|
||||||
val isRunningAsStub get() = Info.stub != null
|
val isRunningAsStub get() = Info.stub != null
|
||||||
|
|
||||||
@@ -47,7 +46,8 @@ object Info {
|
|||||||
val isConnected: LiveData<Boolean> by lazy {
|
val isConnected: LiveData<Boolean> by lazy {
|
||||||
MutableLiveData(false).also { field ->
|
MutableLiveData(false).also { field ->
|
||||||
NetworkObserver.observe(AppContext) {
|
NetworkObserver.observe(AppContext) {
|
||||||
UiThreadHandler.run { field.value = it }
|
remote = EMPTY_REMOTE
|
||||||
|
field.postValue(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,10 @@ class NetworkService(
|
|||||||
|
|
||||||
private inline fun <T> safe(factory: () -> T): T? {
|
private inline fun <T> safe(factory: () -> T): T? {
|
||||||
return try {
|
return try {
|
||||||
factory()
|
if (Info.isConnected.value == true)
|
||||||
|
factory()
|
||||||
|
else
|
||||||
|
null
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import java.io.*
|
|||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ abstract class MagiskInstallImpl protected constructor(
|
|||||||
private val localFS get() = FileSystemManager.getLocal()
|
private val localFS get() = FileSystemManager.getLocal()
|
||||||
|
|
||||||
private fun findImage(): Boolean {
|
private fun findImage(): Boolean {
|
||||||
val bootPath = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh()
|
val bootPath = "RECOVERYMODE=${Config.recovery} find_boot_image; echo \"\$BOOTIMAGE\"".fsh()
|
||||||
if (bootPath.isEmpty()) {
|
if (bootPath.isEmpty()) {
|
||||||
console.add("! Unable to detect target image")
|
console.add("! Unable to detect target image")
|
||||||
return false
|
return false
|
||||||
@@ -420,20 +421,15 @@ abstract class MagiskInstallImpl protected constructor(
|
|||||||
protected abstract suspend fun operations(): Boolean
|
protected abstract suspend fun operations(): Boolean
|
||||||
|
|
||||||
open suspend fun exec(): Boolean {
|
open suspend fun exec(): Boolean {
|
||||||
synchronized(Companion) {
|
if (haveActiveSession.getAndSet(true))
|
||||||
if (haveActiveSession)
|
return false
|
||||||
return false
|
|
||||||
haveActiveSession = true
|
|
||||||
}
|
|
||||||
val result = withContext(Dispatchers.IO) { operations() }
|
val result = withContext(Dispatchers.IO) { operations() }
|
||||||
synchronized(Companion) {
|
haveActiveSession.set(false)
|
||||||
haveActiveSession = false
|
|
||||||
}
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var haveActiveSession = false
|
private var haveActiveSession = AtomicBoolean(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.databinding.ViewDataBinding
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.StubApk
|
||||||
import com.topjohnwu.magisk.arch.NavigationActivity
|
import com.topjohnwu.magisk.arch.NavigationActivity
|
||||||
import com.topjohnwu.magisk.core.Config
|
import com.topjohnwu.magisk.core.Config
|
||||||
import com.topjohnwu.magisk.core.Const
|
import com.topjohnwu.magisk.core.Const
|
||||||
@@ -98,10 +99,10 @@ abstract class SplashActivity<Binding : ViewDataBinding> : NavigationActivity<Bi
|
|||||||
|
|
||||||
Config.load(prevPkg)
|
Config.load(prevPkg)
|
||||||
handleRepackage(prevPkg)
|
handleRepackage(prevPkg)
|
||||||
if (prevPkg != null && !isRunningAsStub) {
|
if (prevPkg != null) {
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
// Might have new configuration loaded, relaunch the activity
|
// Relaunch the process after package migration
|
||||||
relaunch()
|
StubApk.restartProcess(this)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,22 @@ package com.topjohnwu.magisk.ui.deny
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
import com.topjohnwu.magisk.databinding.bindExtra
|
||||||
import com.topjohnwu.magisk.databinding.filterableListOf
|
import com.topjohnwu.magisk.databinding.filterableListOf
|
||||||
|
import com.topjohnwu.magisk.databinding.set
|
||||||
import com.topjohnwu.magisk.ktx.concurrentMap
|
import com.topjohnwu.magisk.ktx.concurrentMap
|
||||||
import com.topjohnwu.magisk.utils.Utils
|
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.toCollection
|
import kotlinx.coroutines.flow.toCollection
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class DenyListViewModel : BaseViewModel() {
|
class DenyListViewModel : AsyncLoadViewModel() {
|
||||||
|
|
||||||
var isShowSystem = false
|
var isShowSystem = false
|
||||||
set(value) {
|
set(value) {
|
||||||
@@ -43,13 +42,13 @@ class DenyListViewModel : BaseViewModel() {
|
|||||||
it.put(BR.viewModel, this)
|
it.put(BR.viewModel, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@get:Bindable
|
||||||
|
var loading = true
|
||||||
|
private set(value) = set(value, field, { field = it }, BR.loading)
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
if (!Utils.showSuperUser()) {
|
loading = true
|
||||||
state = State.LOADING_FAILED
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
state = State.LOADING
|
|
||||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
val (apps, diff) = withContext(Dispatchers.Default) {
|
||||||
val pm = AppContext.packageManager
|
val pm = AppContext.packageManager
|
||||||
val denyList = Shell.cmd("magisk --denylist ls").exec().out
|
val denyList = Shell.cmd("magisk --denylist ls").exec().out
|
||||||
@@ -84,6 +83,6 @@ class DenyListViewModel : BaseViewModel() {
|
|||||||
|
|
||||||
(it.isChecked || (filterSystem() && filterOS())) && filterQuery()
|
(it.isChecked || (filterSystem() && filterOS())) && filterQuery()
|
||||||
}
|
}
|
||||||
state = State.LOADED
|
loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.pm.ActivityInfo
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import androidx.navigation.NavDeepLinkBuilder
|
import androidx.navigation.NavDeepLinkBuilder
|
||||||
import com.topjohnwu.magisk.MainDirections
|
import com.topjohnwu.magisk.MainDirections
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
@@ -21,6 +22,8 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
|
|||||||
override val layoutRes = R.layout.fragment_flash_md2
|
override val layoutRes = R.layout.fragment_flash_md2
|
||||||
override val viewModel by viewModel<FlashViewModel>()
|
override val viewModel by viewModel<FlashViewModel>()
|
||||||
override val snackbarView: View get() = binding.snackbarContainer
|
override val snackbarView: View get() = binding.snackbarContainer
|
||||||
|
override val snackbarAnchorView: View?
|
||||||
|
get() = if (binding.restartBtn.isShown) binding.restartBtn else super.snackbarAnchorView
|
||||||
|
|
||||||
private var defaultOrientation = -1
|
private var defaultOrientation = -1
|
||||||
|
|
||||||
@@ -34,8 +37,20 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
|
|||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
activity?.setTitle(R.string.flash_screen_title)
|
activity?.setTitle(R.string.flash_screen_title)
|
||||||
|
|
||||||
viewModel.subtitle.observe(this) {
|
viewModel.state.observe(this) {
|
||||||
activity?.supportActionBar?.setSubtitle(it)
|
activity?.supportActionBar?.setSubtitle(
|
||||||
|
when (it) {
|
||||||
|
FlashViewModel.State.FLASHING -> R.string.flashing
|
||||||
|
FlashViewModel.State.SUCCESS -> R.string.done
|
||||||
|
FlashViewModel.State.FAILED -> R.string.failure
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if (it == FlashViewModel.State.SUCCESS && viewModel.showReboot) {
|
||||||
|
binding.restartBtn.apply {
|
||||||
|
if (!this.isVisible) this.show()
|
||||||
|
if (!this.isFocused) this.requestFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +81,7 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyEvent(event: KeyEvent): Boolean {
|
override fun onKeyEvent(event: KeyEvent): Boolean {
|
||||||
return when(event.keyCode) {
|
return when (event.keyCode) {
|
||||||
KeyEvent.KEYCODE_VOLUME_UP,
|
KeyEvent.KEYCODE_VOLUME_UP,
|
||||||
KeyEvent.KEYCODE_VOLUME_DOWN -> true
|
KeyEvent.KEYCODE_VOLUME_DOWN -> true
|
||||||
else -> false
|
else -> false
|
||||||
@@ -74,7 +89,8 @@ class FlashFragment : BaseFragment<FragmentFlashMd2Binding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
override fun onBackPressed(): Boolean {
|
||||||
if (viewModel.loading) return true
|
if (viewModel.flashing.value == true)
|
||||||
|
return true
|
||||||
return super.onBackPressed()
|
return super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.view.MenuItem
|
|||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.Transformations
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
@@ -27,13 +28,18 @@ import kotlinx.coroutines.launch
|
|||||||
|
|
||||||
class FlashViewModel : BaseViewModel() {
|
class FlashViewModel : BaseViewModel() {
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
FLASHING, SUCCESS, FAILED
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _state = MutableLiveData(State.FLASHING)
|
||||||
|
val state: LiveData<State> get() = _state
|
||||||
|
val flashing = Transformations.map(state) { it == State.FLASHING }
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var showReboot = Info.isRooted
|
var showReboot = Info.isRooted
|
||||||
set(value) = set(value, field, { field = it }, BR.showReboot)
|
set(value) = set(value, field, { field = it }, BR.showReboot)
|
||||||
|
|
||||||
private val _subtitle = MutableLiveData(R.string.flashing)
|
|
||||||
val subtitle get() = _subtitle as LiveData<Int>
|
|
||||||
|
|
||||||
val items = diffListOf<ConsoleItem>()
|
val items = diffListOf<ConsoleItem>()
|
||||||
lateinit var args: FlashFragmentArgs
|
lateinit var args: FlashFragmentArgs
|
||||||
|
|
||||||
@@ -83,11 +89,7 @@ class FlashViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onResult(success: Boolean) {
|
private fun onResult(success: Boolean) {
|
||||||
state = if (success) State.LOADED else State.LOADING_FAILED
|
_state.value = if (success) State.SUCCESS else State.FAILED
|
||||||
when {
|
|
||||||
success -> _subtitle.postValue(R.string.done)
|
|
||||||
else -> _subtitle.postValue(R.string.failure)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMenuItemClicked(item: MenuItem): Boolean {
|
fun onMenuItemClicked(item: MenuItem): Boolean {
|
||||||
@@ -100,7 +102,8 @@ class FlashViewModel : BaseViewModel() {
|
|||||||
private fun savePressed() = withExternalRW {
|
private fun savePressed() = withExternalRW {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
val name = "magisk_install_log_%s.log".format(
|
val name = "magisk_install_log_%s.log".format(
|
||||||
System.currentTimeMillis().toTime(timeFormatStandard))
|
System.currentTimeMillis().toTime(timeFormatStandard)
|
||||||
|
)
|
||||||
val file = MediaStoreUtils.getFile(name, true)
|
val file = MediaStoreUtils.getFile(name, true)
|
||||||
file.uri.outputStream().bufferedWriter().use { writer ->
|
file.uri.outputStream().bufferedWriter().use { writer ->
|
||||||
synchronized(logItems) {
|
synchronized(logItems) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.home
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
import com.topjohnwu.magisk.BuildConfig
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
@@ -23,16 +22,15 @@ import com.topjohnwu.magisk.ktx.await
|
|||||||
import com.topjohnwu.magisk.utils.Utils
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
import com.topjohnwu.magisk.utils.asText
|
import com.topjohnwu.magisk.utils.asText
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
enum class MagiskState {
|
|
||||||
NOT_INSTALLED, UP_TO_DATE, OBSOLETE, LOADING
|
|
||||||
}
|
|
||||||
|
|
||||||
class HomeViewModel(
|
class HomeViewModel(
|
||||||
private val svc: NetworkService
|
private val svc: NetworkService
|
||||||
) : BaseViewModel() {
|
) : AsyncLoadViewModel() {
|
||||||
|
|
||||||
|
enum class State {
|
||||||
|
LOADING, INVALID, OUTDATED, UP_TO_DATE
|
||||||
|
}
|
||||||
|
|
||||||
val magiskTitleBarrierIds =
|
val magiskTitleBarrierIds =
|
||||||
intArrayOf(R.id.home_magisk_icon, R.id.home_magisk_title, R.id.home_magisk_button)
|
intArrayOf(R.id.home_magisk_icon, R.id.home_magisk_title, R.id.home_magisk_button)
|
||||||
@@ -43,16 +41,16 @@ class HomeViewModel(
|
|||||||
var isNoticeVisible = Config.safetyNotice
|
var isNoticeVisible = Config.safetyNotice
|
||||||
set(value) = set(value, field, { field = it }, BR.noticeVisible)
|
set(value) = set(value, field, { field = it }, BR.noticeVisible)
|
||||||
|
|
||||||
val stateMagisk
|
val magiskState
|
||||||
get() = when {
|
get() = when {
|
||||||
!Info.env.isActive -> MagiskState.NOT_INSTALLED
|
!Info.env.isActive -> State.INVALID
|
||||||
Info.env.versionCode < BuildConfig.VERSION_CODE -> MagiskState.OBSOLETE
|
Info.env.versionCode < BuildConfig.VERSION_CODE -> State.OUTDATED
|
||||||
else -> MagiskState.UP_TO_DATE
|
else -> State.UP_TO_DATE
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var stateManager = MagiskState.LOADING
|
var appState = State.LOADING
|
||||||
set(value) = set(value, field, { field = it }, BR.stateManager)
|
set(value) = set(value, field, { field = it }, BR.appState)
|
||||||
|
|
||||||
val magiskInstalledVersion
|
val magiskInstalledVersion
|
||||||
get() = Info.env.run {
|
get() = Info.env.run {
|
||||||
@@ -83,14 +81,12 @@ class HomeViewModel(
|
|||||||
private var checkedEnv = false
|
private var checkedEnv = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
state = State.LOADING
|
appState = State.LOADING
|
||||||
Info.getRemote(svc)?.apply {
|
Info.getRemote(svc)?.apply {
|
||||||
state = State.LOADED
|
appState = when {
|
||||||
|
BuildConfig.VERSION_CODE < magisk.versionCode -> State.OUTDATED
|
||||||
stateManager = when {
|
else -> State.UP_TO_DATE
|
||||||
BuildConfig.VERSION_CODE < magisk.versionCode -> MagiskState.OBSOLETE
|
|
||||||
else -> MagiskState.UP_TO_DATE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
|
val isDebug = Config.updateChannel == Config.Value.DEBUG_CHANNEL
|
||||||
@@ -98,19 +94,12 @@ class HomeViewModel(
|
|||||||
("${magisk.version} (${magisk.versionCode}) (${stub.versionCode})" +
|
("${magisk.version} (${magisk.versionCode}) (${stub.versionCode})" +
|
||||||
if (isDebug) " (D)" else "").asText()
|
if (isDebug) " (D)" else "").asText()
|
||||||
} ?: run {
|
} ?: run {
|
||||||
state = State.LOADING_FAILED
|
|
||||||
managerRemoteVersion = R.string.not_available.asText()
|
managerRemoteVersion = R.string.not_available.asText()
|
||||||
}
|
}
|
||||||
ensureEnv()
|
ensureEnv()
|
||||||
}
|
}
|
||||||
|
|
||||||
val showTest = false
|
override fun onNetworkChanged(network: Boolean) = startLoading()
|
||||||
|
|
||||||
fun onTestPressed() = object : ViewEvent(), ActivityExecutor {
|
|
||||||
override fun invoke(activity: UIActivity<*>) {
|
|
||||||
/* Entry point to trigger test events within the app */
|
|
||||||
}
|
|
||||||
}.publish()
|
|
||||||
|
|
||||||
fun onProgressUpdate(progress: Float, subject: Subject) {
|
fun onProgressUpdate(progress: Float, subject: Subject) {
|
||||||
if (subject is App)
|
if (subject is App)
|
||||||
@@ -123,14 +112,14 @@ class HomeViewModel(
|
|||||||
|
|
||||||
fun onDeletePressed() = UninstallDialog().publish()
|
fun onDeletePressed() = UninstallDialog().publish()
|
||||||
|
|
||||||
fun onManagerPressed() = when (state) {
|
fun onManagerPressed() = when (magiskState) {
|
||||||
State.LOADED -> withExternalRW {
|
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
||||||
|
State.INVALID -> SnackbarEvent(R.string.no_connection).publish()
|
||||||
|
else -> withExternalRW {
|
||||||
withInstallPermission {
|
withInstallPermission {
|
||||||
ManagerInstallDialog().publish()
|
ManagerInstallDialog().publish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State.LOADING -> SnackbarEvent(R.string.loading).publish()
|
|
||||||
else -> SnackbarEvent(R.string.no_connection).publish()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onMagiskPressed() = withExternalRW {
|
fun onMagiskPressed() = withExternalRW {
|
||||||
@@ -143,7 +132,7 @@ class HomeViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ensureEnv() {
|
private suspend fun ensureEnv() {
|
||||||
if (MagiskState.NOT_INSTALLED == stateMagisk || checkedEnv) return
|
if (magiskState == State.INVALID || checkedEnv) return
|
||||||
val cmd = "env_check ${Info.env.versionString} ${Info.env.versionCode}"
|
val cmd = "env_check ${Info.env.versionString} ${Info.env.versionCode}"
|
||||||
if (!Shell.cmd(cmd).await().isSuccess) {
|
if (!Shell.cmd(cmd).await().isSuccess) {
|
||||||
EnvFixDialog(this).publish()
|
EnvFixDialog(this).publish()
|
||||||
@@ -151,4 +140,10 @@ class HomeViewModel(
|
|||||||
checkedEnv = true
|
checkedEnv = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val showTest = false
|
||||||
|
fun onTestPressed() = object : ViewEvent(), ActivityExecutor {
|
||||||
|
override fun invoke(activity: UIActivity<*>) {
|
||||||
|
/* Entry point to trigger test events within the app */
|
||||||
|
}
|
||||||
|
}.publish()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ class InstallViewModel(
|
|||||||
R.id.method_inactive_slot -> FlashFragment.flash(true).navigate(true)
|
R.id.method_inactive_slot -> FlashFragment.flash(true).navigate(true)
|
||||||
else -> error("Unknown value")
|
else -> error("Unknown value")
|
||||||
}
|
}
|
||||||
state = State.LOADING
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveState(state: Bundle) {
|
override fun onSaveState(state: Bundle) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.BuildConfig
|
import com.topjohnwu.magisk.BuildConfig
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.repository.LogRepository
|
import com.topjohnwu.magisk.core.repository.LogRepository
|
||||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||||
@@ -24,7 +24,7 @@ import java.io.FileInputStream
|
|||||||
|
|
||||||
class LogViewModel(
|
class LogViewModel(
|
||||||
private val repo: LogRepository
|
private val repo: LogRepository
|
||||||
) : BaseViewModel() {
|
) : AsyncLoadViewModel() {
|
||||||
|
|
||||||
// --- empty view
|
// --- empty view
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class LogViewModel(
|
|||||||
var consoleText = " "
|
var consoleText = " "
|
||||||
set(value) = set(value, field, { field = it }, BR.consoleText)
|
set(value) = set(value, field, { field = it }, BR.consoleText)
|
||||||
|
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
consoleText = repo.fetchMagiskLogs()
|
consoleText = repo.fetchMagiskLogs()
|
||||||
val (suLogs, diff) = withContext(Dispatchers.Default) {
|
val (suLogs, diff) = withContext(Dispatchers.Default) {
|
||||||
val suLogs = repo.fetchSuLogs().map { LogRvItem(it) }
|
val suLogs = repo.fetchSuLogs().map { LogRvItem(it) }
|
||||||
@@ -89,12 +89,12 @@ class LogViewModel(
|
|||||||
|
|
||||||
fun clearMagiskLog() = repo.clearMagiskLogs {
|
fun clearMagiskLog() = repo.clearMagiskLogs {
|
||||||
SnackbarEvent(R.string.logs_cleared).publish()
|
SnackbarEvent(R.string.logs_cleared).publish()
|
||||||
requestRefresh()
|
startLoading()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearLog() = viewModelScope.launch {
|
fun clearLog() = viewModelScope.launch {
|
||||||
repo.clearLogs()
|
repo.clearLogs()
|
||||||
SnackbarEvent(R.string.logs_cleared).publish()
|
SnackbarEvent(R.string.logs_cleared).publish()
|
||||||
requestRefresh()
|
startLoading()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,24 @@
|
|||||||
package com.topjohnwu.magisk.ui.module
|
package com.topjohnwu.magisk.ui.module
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.Info
|
import com.topjohnwu.magisk.core.Info
|
||||||
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
import com.topjohnwu.magisk.core.base.ContentResultCallback
|
||||||
import com.topjohnwu.magisk.core.model.module.LocalModule
|
import com.topjohnwu.magisk.core.model.module.LocalModule
|
||||||
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
import com.topjohnwu.magisk.core.model.module.OnlineModule
|
||||||
import com.topjohnwu.magisk.databinding.MergeObservableList
|
import com.topjohnwu.magisk.databinding.*
|
||||||
import com.topjohnwu.magisk.databinding.RvItem
|
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
|
||||||
import com.topjohnwu.magisk.databinding.diffListOf
|
|
||||||
import com.topjohnwu.magisk.events.GetContentEvent
|
import com.topjohnwu.magisk.events.GetContentEvent
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
|
import com.topjohnwu.magisk.events.dialog.ModuleInstallDialog
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
class ModuleViewModel : BaseViewModel() {
|
class ModuleViewModel : AsyncLoadViewModel() {
|
||||||
|
|
||||||
val bottomBarBarrierIds = intArrayOf(R.id.module_update, R.id.module_remove)
|
val bottomBarBarrierIds = intArrayOf(R.id.module_update, R.id.module_remove)
|
||||||
|
|
||||||
@@ -36,6 +31,10 @@ class ModuleViewModel : BaseViewModel() {
|
|||||||
|
|
||||||
val data get() = uri
|
val data get() = uri
|
||||||
|
|
||||||
|
@get:Bindable
|
||||||
|
var loading = true
|
||||||
|
private set(value) = set(value, field, { field = it }, BR.loading)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (Info.env.isActive && LocalModule.loaded()) {
|
if (Info.env.isActive && LocalModule.loaded()) {
|
||||||
items.insertItem(InstallModule)
|
items.insertItem(InstallModule)
|
||||||
@@ -43,15 +42,15 @@ class ModuleViewModel : BaseViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun refresh(): Job {
|
override suspend fun doLoadWork() {
|
||||||
return viewModelScope.launch {
|
loading = true
|
||||||
state = State.LOADING
|
loadInstalled()
|
||||||
loadInstalled()
|
loading = false
|
||||||
state = State.LOADED
|
loadUpdateInfo()
|
||||||
loadUpdateInfo()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onNetworkChanged(network: Boolean) = startLoading()
|
||||||
|
|
||||||
private suspend fun loadInstalled() {
|
private suspend fun loadInstalled() {
|
||||||
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
val installed = LocalModule.installed().map { LocalModuleRvItem(it) }
|
||||||
val diff = withContext(Dispatchers.Default) {
|
val diff = withContext(Dispatchers.Default) {
|
||||||
|
|||||||
@@ -4,20 +4,18 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
|
import androidx.databinding.Bindable
|
||||||
import androidx.databinding.ObservableArrayList
|
import androidx.databinding.ObservableArrayList
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.AsyncLoadViewModel
|
||||||
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
import com.topjohnwu.magisk.core.data.magiskdb.PolicyDao
|
||||||
import com.topjohnwu.magisk.core.di.AppContext
|
import com.topjohnwu.magisk.core.di.AppContext
|
||||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||||
import com.topjohnwu.magisk.databinding.AnyDiffRvItem
|
import com.topjohnwu.magisk.databinding.*
|
||||||
import com.topjohnwu.magisk.databinding.MergeObservableList
|
|
||||||
import com.topjohnwu.magisk.databinding.bindExtra
|
|
||||||
import com.topjohnwu.magisk.databinding.diffListOf
|
|
||||||
import com.topjohnwu.magisk.events.SnackbarEvent
|
import com.topjohnwu.magisk.events.SnackbarEvent
|
||||||
import com.topjohnwu.magisk.events.dialog.BiometricEvent
|
import com.topjohnwu.magisk.events.dialog.BiometricEvent
|
||||||
import com.topjohnwu.magisk.events.dialog.SuperuserRevokeDialog
|
import com.topjohnwu.magisk.events.dialog.SuperuserRevokeDialog
|
||||||
@@ -31,7 +29,7 @@ import kotlinx.coroutines.withContext
|
|||||||
|
|
||||||
class SuperuserViewModel(
|
class SuperuserViewModel(
|
||||||
private val db: PolicyDao
|
private val db: PolicyDao
|
||||||
) : BaseViewModel() {
|
) : AsyncLoadViewModel() {
|
||||||
|
|
||||||
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
private val itemNoData = TextItem(R.string.superuser_policy_none)
|
||||||
|
|
||||||
@@ -45,15 +43,17 @@ class SuperuserViewModel(
|
|||||||
it.put(BR.listener, this)
|
it.put(BR.listener, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
@get:Bindable
|
||||||
|
var loading = true
|
||||||
|
private set(value) = set(value, field, { field = it }, BR.loading)
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
override fun refresh() = viewModelScope.launch {
|
override suspend fun doLoadWork() {
|
||||||
if (!Utils.showSuperUser()) {
|
if (!Utils.showSuperUser()) {
|
||||||
state = State.LOADING_FAILED
|
loading = false
|
||||||
return@launch
|
return
|
||||||
}
|
}
|
||||||
state = State.LOADING
|
loading = true
|
||||||
val (policies, diff) = withContext(Dispatchers.IO) {
|
val (policies, diff) = withContext(Dispatchers.IO) {
|
||||||
db.deleteOutdated()
|
db.deleteOutdated()
|
||||||
db.delete(AppContext.applicationInfo.uid)
|
db.delete(AppContext.applicationInfo.uid)
|
||||||
@@ -98,7 +98,7 @@ class SuperuserViewModel(
|
|||||||
itemsHelpers.clear()
|
itemsHelpers.clear()
|
||||||
else if (itemsHelpers.isEmpty())
|
else if (itemsHelpers.isEmpty())
|
||||||
itemsHelpers.add(itemNoData)
|
itemsHelpers.add(itemNoData)
|
||||||
state = State.LOADED
|
loading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|||||||
@@ -24,13 +24,9 @@ open class SuRequestActivity : UIActivity<ActivityRequestBinding>() {
|
|||||||
override val layoutRes: Int = R.layout.activity_request
|
override val layoutRes: Int = R.layout.activity_request
|
||||||
override val viewModel: SuRequestViewModel by viewModel()
|
override val viewModel: SuRequestViewModel by viewModel()
|
||||||
|
|
||||||
override fun onBackPressed() {
|
|
||||||
viewModel.denyPressed()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
|
supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||||
lockOrientation()
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
window.addFlags(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
window.addFlags(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
@@ -62,7 +58,11 @@ open class SuRequestActivity : UIActivity<ActivityRequestBinding>() {
|
|||||||
return theme
|
return theme
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lockOrientation() {
|
override fun onBackPressed() {
|
||||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
viewModel.denyPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
super.finishAndRemoveTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
android:paddingTop="@dimen/internal_action_bar_size"
|
android:paddingTop="@dimen/internal_action_bar_size"
|
||||||
app:fitsSystemWindowsInsets="top|bottom"
|
app:fitsSystemWindowsInsets="top|bottom"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:invisibleUnless="@{viewModel.loaded}"
|
app:invisible="@{viewModel.loading}"
|
||||||
app:items="@{viewModel.items}"
|
app:items="@{viewModel.items}"
|
||||||
app:extraBindings="@{viewModel.extraBindings}"
|
app:extraBindings="@{viewModel.extraBindings}"
|
||||||
tools:listitem="@layout/item_hide_md2"
|
tools:listitem="@layout/item_hide_md2"
|
||||||
@@ -52,24 +52,6 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
goneUnless="@{viewModel.loadFailed}"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
tools:visibility="gone">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/not_available"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Title"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -24,13 +24,13 @@
|
|||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/flash_content"
|
android:id="@+id/flash_content"
|
||||||
app:items="@{viewModel.items}"
|
|
||||||
scrollToLast="@{true}"
|
scrollToLast="@{true}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:fitsSystemWindowsInsets="start|end|bottom"
|
app:fitsSystemWindowsInsets="start|end|bottom"
|
||||||
|
app:items="@{viewModel.items}"
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
tools:listitem="@layout/item_console_md2" />
|
tools:listitem="@layout/item_console_md2" />
|
||||||
@@ -38,27 +38,31 @@
|
|||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
gone="@{!viewModel.loaded || !viewModel.showReboot}"
|
android:id="@+id/restart_btn"
|
||||||
|
gone="@{viewModel.flashing || !viewModel.showReboot}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_margin="@dimen/l1"
|
android:layout_margin="@dimen/l1"
|
||||||
android:layout_marginBottom="@dimen/l1"
|
android:layout_marginBottom="@dimen/l1"
|
||||||
|
android:clickable="@{!viewModel.flashing}"
|
||||||
|
android:enabled="@{!viewModel.flashing}"
|
||||||
|
android:focusable="true"
|
||||||
android:onClick="@{() -> viewModel.restartPressed()}"
|
android:onClick="@{() -> viewModel.restartPressed()}"
|
||||||
android:text="@string/reboot"
|
android:text="@string/reboot"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
android:textColor="?colorOnPrimary"
|
android:textColor="?colorOnPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_fitsSystemWindowsInsets="bottom"
|
|
||||||
app:backgroundTint="?colorPrimary"
|
app:backgroundTint="?colorPrimary"
|
||||||
app:icon="@drawable/ic_restart"
|
app:icon="@drawable/ic_restart"
|
||||||
app:iconTint="?colorOnPrimary" />
|
app:iconTint="?colorOnPrimary"
|
||||||
|
app:layout_fitsSystemWindowsInsets="bottom" />
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/snackbar_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/snackbar_container"
|
app:fitsSystemWindowsInsets="top|bottom" />
|
||||||
app:fitsSystemWindowsInsets="top|bottom"/>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
|
|
||||||
<import type="com.topjohnwu.magisk.core.Info" />
|
<import type="com.topjohnwu.magisk.core.Info" />
|
||||||
|
|
||||||
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
|
|
||||||
|
|
||||||
<import type="com.topjohnwu.magisk.ui.home.DeveloperItem" />
|
<import type="com.topjohnwu.magisk.ui.home.DeveloperItem" />
|
||||||
|
|
||||||
<import type="com.topjohnwu.magisk.ui.home.IconLink" />
|
<import type="com.topjohnwu.magisk.ui.home.IconLink" />
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/superuser_list"
|
android:id="@+id/superuser_list"
|
||||||
goneUnless="@{viewModel.loaded || !viewModel.items.empty}"
|
gone="@{viewModel.loading}"
|
||||||
app:items="@{viewModel.items}"
|
app:items="@{viewModel.items}"
|
||||||
app:extraBindings="@{viewModel.extraBindings}"
|
app:extraBindings="@{viewModel.extraBindings}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
tools:listitem="@layout/item_policy_md2" />
|
tools:listitem="@layout/item_policy_md2" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
goneUnless="@{viewModel.loading && viewModel.items.empty}"
|
goneUnless="@{viewModel.loading}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
@@ -54,24 +54,6 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
goneUnless="@{viewModel.loadFailed}"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
tools:visibility="gone">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/not_available"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Title"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<import type="com.topjohnwu.magisk.core.Info" />
|
<import type="com.topjohnwu.magisk.core.Info" />
|
||||||
|
|
||||||
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
|
<import type="com.topjohnwu.magisk.ui.home.HomeViewModel.State" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/WidgetFoundation.Button"
|
style="@style/WidgetFoundation.Button"
|
||||||
gone="@{viewModel.stateMagisk != MagiskState.OBSOLETE}"
|
gone="@{viewModel.magiskState != State.OUTDATED}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:onClick="@{() -> viewModel.onMagiskPressed()}"
|
android:onClick="@{() -> viewModel.onMagiskPressed()}"
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/WidgetFoundation.Button.Text"
|
style="@style/WidgetFoundation.Button.Text"
|
||||||
gone="@{viewModel.stateMagisk == MagiskState.OBSOLETE}"
|
gone="@{viewModel.magiskState == State.OUTDATED}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<import type="com.topjohnwu.magisk.core.Info" />
|
<import type="com.topjohnwu.magisk.core.Info" />
|
||||||
|
|
||||||
<import type="com.topjohnwu.magisk.ui.home.MagiskState" />
|
<import type="com.topjohnwu.magisk.ui.home.HomeViewModel.State" />
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/WidgetFoundation.Button"
|
style="@style/WidgetFoundation.Button"
|
||||||
gone="@{viewModel.stateManager != MagiskState.OBSOLETE}"
|
gone="@{viewModel.appState != State.OUTDATED}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:onClick="@{() -> viewModel.onManagerPressed()}"
|
android:onClick="@{() -> viewModel.onManagerPressed()}"
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
style="@style/WidgetFoundation.Button.Text"
|
style="@style/WidgetFoundation.Button.Text"
|
||||||
gone="@{viewModel.stateManager != MagiskState.UP_TO_DATE}"
|
gone="@{viewModel.appState != State.UP_TO_DATE}"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ env_check() {
|
|||||||
for file in busybox magiskboot magiskinit util_functions.sh boot_patch.sh; do
|
for file in busybox magiskboot magiskinit util_functions.sh boot_patch.sh; do
|
||||||
[ -f "$MAGISKBIN/$file" ] || return 1
|
[ -f "$MAGISKBIN/$file" ] || return 1
|
||||||
done
|
done
|
||||||
if [ "$2" -ge 24302 ]; then
|
if [ "$2" -ge 25000 ]; then
|
||||||
[ -f "$MAGISKBIN/magiskpolicy" ] || return 1
|
[ -f "$MAGISKBIN/magiskpolicy" ] || return 1
|
||||||
fi
|
fi
|
||||||
grep -xqF "MAGISK_VER='$1'" "$MAGISKBIN/util_functions.sh" || return 1
|
grep -xqF "MAGISK_VER='$1'" "$MAGISKBIN/util_functions.sh" || return 1
|
||||||
@@ -99,7 +99,8 @@ post_ota() {
|
|||||||
rm -f $1
|
rm -f $1
|
||||||
chmod 755 bootctl
|
chmod 755 bootctl
|
||||||
./bootctl hal-info || return
|
./bootctl hal-info || return
|
||||||
[ $(./bootctl get-current-slot) -eq 0 ] && SLOT_NUM=1 || SLOT_NUM=0
|
SLOT_NUM=0
|
||||||
|
[ $(./bootctl get-current-slot) -eq 0 ] && SLOT_NUM=1
|
||||||
./bootctl set-active-boot-slot $SLOT_NUM
|
./bootctl set-active-boot-slot $SLOT_NUM
|
||||||
cat << EOF > post-fs-data.d/post_ota.sh
|
cat << EOF > post-fs-data.d/post_ota.sh
|
||||||
/data/adb/bootctl mark-boot-successful
|
/data/adb/bootctl mark-boot-successful
|
||||||
@@ -142,18 +143,16 @@ adb_pm_install() {
|
|||||||
|
|
||||||
check_boot_ramdisk() {
|
check_boot_ramdisk() {
|
||||||
# Create boolean ISAB
|
# Create boolean ISAB
|
||||||
[ -z $SLOT ] && ISAB=false || ISAB=true
|
ISAB=true
|
||||||
|
[ -z $SLOT ] && ISAB=false
|
||||||
# If we are running as recovery mode, then we do not have ramdisk
|
|
||||||
[ "$RECOVERYMODE" = "true" ] && return 1
|
|
||||||
|
|
||||||
# If we are A/B, then we must have ramdisk
|
# If we are A/B, then we must have ramdisk
|
||||||
$ISAB && return 0
|
$ISAB && return 0
|
||||||
|
|
||||||
# If we are using legacy SAR, but not A/B, assume we do not have ramdisk
|
# If we are using legacy SAR, but not A/B, assume we do not have ramdisk
|
||||||
if grep ' / ' /proc/mounts | grep -q '/dev/root'; then
|
if grep ' / ' /proc/mounts | grep -q '/dev/root'; then
|
||||||
# Override recovery mode to true if not set
|
# Override recovery mode to true
|
||||||
[ -z $RECOVERYMODE ] && RECOVERYMODE=true
|
RECOVERYMODE=true
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -173,7 +172,8 @@ check_encryption() {
|
|||||||
CRYPTOTYPE="file"
|
CRYPTOTYPE="file"
|
||||||
else
|
else
|
||||||
# We are either FDE or metadata encryption (which is also FBE)
|
# We are either FDE or metadata encryption (which is also FBE)
|
||||||
grep -q ' /metadata ' /proc/mounts && CRYPTOTYPE="file" || CRYPTOTYPE="block"
|
CRYPTOTYPE="block"
|
||||||
|
grep -q ' /metadata ' /proc/mounts && CRYPTOTYPE="file"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -189,12 +189,14 @@ check_encryption() {
|
|||||||
mount_partitions() {
|
mount_partitions() {
|
||||||
[ "$(getprop ro.build.ab_update)" = "true" ] && SLOT=$(getprop ro.boot.slot_suffix)
|
[ "$(getprop ro.build.ab_update)" = "true" ] && SLOT=$(getprop ro.boot.slot_suffix)
|
||||||
# Check whether non rootfs root dir exists
|
# Check whether non rootfs root dir exists
|
||||||
grep ' / ' /proc/mounts | grep -qv 'rootfs' && SYSTEM_ROOT=true || SYSTEM_ROOT=false
|
SYSTEM_ROOT=false
|
||||||
|
grep ' / ' /proc/mounts | grep -qv 'rootfs' && SYSTEM_ROOT=true
|
||||||
}
|
}
|
||||||
|
|
||||||
get_flags() {
|
get_flags() {
|
||||||
KEEPVERITY=$SYSTEM_ROOT
|
KEEPVERITY=$SYSTEM_ROOT
|
||||||
[ "$(getprop ro.crypto.state)" = "encrypted" ] && ISENCRYPTED=true || ISENCRYPTED=false
|
ISENCRYPTED=false
|
||||||
|
[ "$(getprop ro.crypto.state)" = "encrypted" ] && ISENCRYPTED=true
|
||||||
KEEPFORCEENCRYPT=$ISENCRYPTED
|
KEEPFORCEENCRYPT=$ISENCRYPTED
|
||||||
# Although this most certainly won't work without root, keep it just in case
|
# Although this most certainly won't work without root, keep it just in case
|
||||||
if [ -e /dev/block/by-name/vbmeta_a ] || [ -e /dev/block/by-name/vbmeta ]; then
|
if [ -e /dev/block/by-name/vbmeta_a ] || [ -e /dev/block/by-name/vbmeta ]; then
|
||||||
@@ -204,7 +206,8 @@ get_flags() {
|
|||||||
fi
|
fi
|
||||||
# Preset PATCHVBMETAFLAG to false in the non-root case
|
# Preset PATCHVBMETAFLAG to false in the non-root case
|
||||||
PATCHVBMETAFLAG=false
|
PATCHVBMETAFLAG=false
|
||||||
# Do NOT preset RECOVERYMODE here
|
# Make sure RECOVERYMODE has value
|
||||||
|
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
|
||||||
}
|
}
|
||||||
|
|
||||||
run_migrations() { return; }
|
run_migrations() { return; }
|
||||||
@@ -217,13 +220,12 @@ grep_prop() { return; }
|
|||||||
|
|
||||||
app_init() {
|
app_init() {
|
||||||
mount_partitions
|
mount_partitions
|
||||||
|
RAMDISKEXIST=false
|
||||||
|
check_boot_ramdisk && RAMDISKEXIST=true
|
||||||
get_flags
|
get_flags
|
||||||
run_migrations
|
run_migrations
|
||||||
SHA1=$(grep_prop SHA1 $MAGISKTMP/config)
|
SHA1=$(grep_prop SHA1 $MAGISKTMP/config)
|
||||||
check_boot_ramdisk && RAMDISKEXIST=true || RAMDISKEXIST=false
|
|
||||||
check_encryption
|
check_encryption
|
||||||
# Make sure RECOVERYMODE has value
|
|
||||||
[ -z $RECOVERYMODE ] && RECOVERYMODE=false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export BOOTMODE=true
|
export BOOTMODE=true
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<string name="no_connection">L\'accesu a internet nun ta disponible</string>
|
<string name="no_connection">L\'accesu a internet nun ta disponible</string>
|
||||||
<string name="app_changelog">Rexistru de cambeos</string>
|
<string name="app_changelog">Rexistru de cambeos</string>
|
||||||
<string name="loading">Cargando…</string>
|
<string name="loading">Cargando…</string>
|
||||||
<string name="update">Anovamienu</string>
|
<string name="update">Anovar</string>
|
||||||
<string name="not_available">N/D</string>
|
<string name="not_available">N/D</string>
|
||||||
<string name="hide">Anubrir</string>
|
<string name="hide">Anubrir</string>
|
||||||
<string name="home_package">Paquete</string>
|
<string name="home_package">Paquete</string>
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
<string name="home_follow_title">Redes sociales</string>
|
<string name="home_follow_title">Redes sociales</string>
|
||||||
<string name="home_item_source">Códigu fonte</string>
|
<string name="home_item_source">Códigu fonte</string>
|
||||||
<string name="home_support_content">Magisk ye y va ser de códigu abiertu y gratuitu. Sicasí, pues ayudanos faciendo una donación o collaborando.</string>
|
<string name="home_support_content">Magisk ye y va ser de códigu abiertu y gratuitu. Sicasí, pues ayudanos faciendo una donación o collaborando.</string>
|
||||||
<string name="home_installed_version">V. instalada</string>
|
<string name="home_installed_version">Versión instalada</string>
|
||||||
<string name="home_latest_version">Última v.</string>
|
<string name="home_latest_version">Última versión</string>
|
||||||
<string name="invalid_update_channel">La canal d\'anovamientu nun ye válida</string>
|
<string name="invalid_update_channel">La canal d\'anovamientu nun ye válida</string>
|
||||||
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
<string name="uninstall_magisk_title">Desinstalar Magisk</string>
|
||||||
<string name="uninstall_magisk_msg">¡Van quitase y desactivase tolos módulos y l\'accesu root!\nCualesquier almacenamientu internu ensin cifrar pente l\'usu de Magisk va volver cifrase.</string>
|
<string name="uninstall_magisk_msg">¡Van quitase y desactivase tolos módulos y l\'accesu root!\nCualesquier almacenamientu internu ensin cifrar pente l\'usu de Magisk va volver cifrase.</string>
|
||||||
@@ -37,13 +37,13 @@
|
|||||||
<string name="install_method_title">Métodu</string>
|
<string name="install_method_title">Métodu</string>
|
||||||
<string name="install_next">Siguiente</string>
|
<string name="install_next">Siguiente</string>
|
||||||
<string name="install_start">Siguir</string>
|
<string name="install_start">Siguir</string>
|
||||||
<string name="manager_download_install">Primi pa baxar ya instalar</string>
|
<string name="manager_download_install">Primi equí pa baxalu ya instalalu</string>
|
||||||
<string name="direct_install">Instalación direuta (aconséyase)</string>
|
<string name="direct_install">Instalación direuta (aconséyase)</string>
|
||||||
<string name="install_inactive_slot">Instalar na ralura inactiva (darréu del OTA)</string>
|
<string name="install_inactive_slot">Instalar na ralura inactiva (darréu del OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">¡El preséu va arrincar OBLIGATORIAMENTE na ralura inactiva darréu de reaniciar!\nUsa esta opción namás dempués d\'acabar l\'anovamientu per OTA.\n¿Quies siguir?</string>
|
<string name="install_inactive_slot_msg">¡El preséu va arrincar OBLIGATORIAMENTE na ralura inactiva darréu de reaniciar!\nUsa esta opción namás dempués d\'acabar l\'anovamientu per OTA.\n¿Quies siguir?</string>
|
||||||
<string name="setup_title">Configuración adicional</string>
|
<string name="setup_title">Configuración adicional</string>
|
||||||
<string name="select_patch_file">Esbillar y parchiar un ficheru</string>
|
<string name="select_patch_file">Seleicionar y parchiar un ficheru</string>
|
||||||
<string name="patch_file_msg">Esbilla una imaxe en bruto (*.img) o un archivu d\'ODIN (*.tar)</string>
|
<string name="patch_file_msg">Seleiciona una imaxe en bruto (*.img) o un archivu d\'ODIN (*.tar)</string>
|
||||||
<string name="reboot_delay_toast">Reaniciando en 5 segundos…</string>
|
<string name="reboot_delay_toast">Reaniciando en 5 segundos…</string>
|
||||||
<string name="flash_screen_title">Instalación</string>
|
<string name="flash_screen_title">Instalación</string>
|
||||||
<!--Superuser-->
|
<!--Superuser-->
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
<string name="module_empty">Nun hai nengún módulu instaláu</string>
|
<string name="module_empty">Nun hai nengún módulu instaláu</string>
|
||||||
<!--Settings-->
|
<!--Settings-->
|
||||||
<string name="settings_dark_mode_title">Mou del estilu</string>
|
<string name="settings_dark_mode_title">Mou del estilu</string>
|
||||||
<string name="settings_dark_mode_message">¡Esbilla\'l mou que meyor s\'adaute al to estilu!</string>
|
<string name="settings_dark_mode_message">¡Seleiciona\'l mou que meyor s\'adaute al to estilu!</string>
|
||||||
<string name="settings_dark_mode_light">Claridá</string>
|
<string name="settings_dark_mode_light">Claridá</string>
|
||||||
<string name="settings_dark_mode_system">L\'estilu del sistema</string>
|
<string name="settings_dark_mode_system">L\'estilu del sistema</string>
|
||||||
<string name="settings_dark_mode_dark">Escuridá</string>
|
<string name="settings_dark_mode_dark">Escuridá</string>
|
||||||
@@ -130,7 +130,7 @@
|
|||||||
<string name="settings_denylist_summary">Los procesos de la llista d\'esclusión tienen toles modificaciones de Magisk anulaes</string>
|
<string name="settings_denylist_summary">Los procesos de la llista d\'esclusión tienen toles modificaciones de Magisk anulaes</string>
|
||||||
<string name="settings_denylist_error">Esta función rique l\'activación de: %1$s</string>
|
<string name="settings_denylist_error">Esta función rique l\'activación de: %1$s</string>
|
||||||
<string name="settings_denylist_config_title">Configurar la llista d\'esclusión</string>
|
<string name="settings_denylist_config_title">Configurar la llista d\'esclusión</string>
|
||||||
<string name="settings_denylist_config_summary">Esbilla los procesos que s\'inclúin na llista d\'esclusión</string>
|
<string name="settings_denylist_config_summary">Seleiciona los procesos que s\'inclúin na llista d\'esclusión</string>
|
||||||
<string name="settings_hosts_title">Módulu «Systemless Hosts»</string>
|
<string name="settings_hosts_title">Módulu «Systemless Hosts»</string>
|
||||||
<string name="settings_hosts_summary">Un módulu pa les aplicaciones que bloquien anuncios</string>
|
<string name="settings_hosts_summary">Un módulu pa les aplicaciones que bloquien anuncios</string>
|
||||||
<string name="settings_hosts_toast">Amestóse\'l módulu «Systemless Hosts»</string>
|
<string name="settings_hosts_toast">Amestóse\'l módulu «Systemless Hosts»</string>
|
||||||
|
|||||||
@@ -5,44 +5,49 @@
|
|||||||
<string name="superuser">Superuser</string>
|
<string name="superuser">Superuser</string>
|
||||||
<string name="logs">Log</string>
|
<string name="logs">Log</string>
|
||||||
<string name="settings">Setelan</string>
|
<string name="settings">Setelan</string>
|
||||||
<string name="install">Instal</string>
|
<string name="install">Pasang</string>
|
||||||
<string name="section_home">Beranda</string>
|
<string name="section_home">Beranda</string>
|
||||||
<string name="section_theme">Tema</string>
|
<string name="section_theme">Tema</string>
|
||||||
|
<string name="denylist">DenyList</string>
|
||||||
|
|
||||||
<!--Home-->
|
<!--Home-->
|
||||||
<string name="no_connection">Koneksi tidak tersedia</string>
|
<string name="no_connection">Koneksi tidak tersedia</string>
|
||||||
<string name="app_changelog">Catatan perubahan</string>
|
<string name="app_changelog">Catatan perubahan</string>
|
||||||
<string name="loading">Memuat…</string>
|
<string name="loading">Memuat…</string>
|
||||||
<string name="update">Update</string>
|
<string name="update">Perbarui</string>
|
||||||
<string name="not_available">N/A</string>
|
<string name="not_available">N/A</string>
|
||||||
<string name="hide">Tutup</string>
|
<string name="hide">Tutup</string>
|
||||||
<string name="home_package">Paket</string>
|
<string name="home_package">Paket</string>
|
||||||
|
<string name="home_app_title">Aplikasi</string>
|
||||||
|
|
||||||
|
<string name="home_notice_content">Unduh Magisk HANYA dari halaman GitHub resmi kami. File dari sumber yang tidak dikenal bisa berbahaya!</string>
|
||||||
<string name="home_support_title">Dukung kami</string>
|
<string name="home_support_title">Dukung kami</string>
|
||||||
|
<string name="home_follow_title">Ikuti Kami</string>
|
||||||
<string name="home_item_source">Sumber</string>
|
<string name="home_item_source">Sumber</string>
|
||||||
<string name="home_support_content">Magisk gratis dan bersumber terbuka, dan akan selalu seperti itu. Bagaimanapun juga Anda dapat menunjukan kepedulian Anda kepada kami dengan mengirimkan sedikit donasi.</string>
|
<string name="home_support_content">Magisk gratis dan bersumber terbuka, dan akan selalu seperti itu. Bagaimanapun juga Anda dapat menunjukan kepedulian Anda kepada kami dengan mengirimkan sedikit donasi.</string>
|
||||||
<string name="home_installed_version">Terinstal</string>
|
<string name="home_installed_version">Terpasang</string>
|
||||||
<string name="home_latest_version">Terbaru</string>
|
<string name="home_latest_version">Terbaru</string>
|
||||||
<string name="invalid_update_channel">Kanal update tidak valid</string>
|
<string name="invalid_update_channel">Saluran pembaruan tidak valid</string>
|
||||||
<string name="uninstall_magisk_title">Uninstal Magisk</string>
|
<string name="uninstall_magisk_title">Copot Magisk</string>
|
||||||
<string name="uninstall_magisk_msg">Semua modul akan dinonaktifkan/dihapus!\nRoot akan dihapus!\nData Anda berpotensi terenkripsi jika belum!</string>
|
<string name="uninstall_magisk_msg">Semua modul akan dinonaktifkan/dihapus!\nRoot akan dihapus!\nData Anda berpotensi terenkripsi jika belum!</string>
|
||||||
|
|
||||||
<!--Install-->
|
<!--Install-->
|
||||||
<string name="keep_force_encryption">Pertahankan enkripsi paksa</string>
|
<string name="keep_force_encryption">Pertahankan enkripsi paksa</string>
|
||||||
<string name="keep_dm_verity">Pertahankan AVB 2.0/dm-verity</string>
|
<string name="keep_dm_verity">Pertahankan AVB 2.0/dm-verity</string>
|
||||||
|
<string name="patch_vbmeta">Tambal vbmeta dalam boot image</string>
|
||||||
<string name="recovery_mode">Mode Recovery</string>
|
<string name="recovery_mode">Mode Recovery</string>
|
||||||
<string name="install_options_title">Opsi</string>
|
<string name="install_options_title">Opsi</string>
|
||||||
<string name="install_method_title">Metode</string>
|
<string name="install_method_title">Metode</string>
|
||||||
<string name="install_next">Berikutnya</string>
|
<string name="install_next">Berikutnya</string>
|
||||||
<string name="install_start">Mulai</string>
|
<string name="install_start">Mulai</string>
|
||||||
<string name="manager_download_install">Sentuh untuk download dan instal</string>
|
<string name="manager_download_install">Sentuh untuk unduh dan pasang</string>
|
||||||
<string name="direct_install">Langsung instal (Disarankan)</string>
|
<string name="direct_install">Langsung pasang (Disarankan)</string>
|
||||||
<string name="install_inactive_slot">Instal pada slot nonaktif (Setelah OTA)</string>
|
<string name="install_inactive_slot">Pasang pada slot nonaktif (Setelah OTA)</string>
|
||||||
<string name="install_inactive_slot_msg">Perangkat Anda akan DIPAKSA boot ke slot yang saat ini tidak aktif setelah perangkat dinyalakan ulang!\nGunakan opsi ini hanya setelah proses OTA selesai.\nLanjutkan?</string>
|
<string name="install_inactive_slot_msg">Perangkat Anda akan DIPAKSA boot ke slot yang saat ini tidak aktif setelah perangkat dinyalakan ulang!\nGunakan opsi ini hanya setelah proses OTA selesai.\nLanjutkan?</string>
|
||||||
<string name="setup_title">Penyiapan tambahan</string>
|
<string name="setup_title">Penyiapan tambahan</string>
|
||||||
<string name="select_patch_file">Pilih dan tambal file</string>
|
<string name="select_patch_file">Pilih dan tambal file</string>
|
||||||
<string name="patch_file_msg">Pilih mentahan image (*.img) atau file tar ODIN (*.tar)</string>
|
<string name="patch_file_msg">Pilih mentahan image (*.img) atau file tar ODIN (*.tar)</string>
|
||||||
<string name="reboot_delay_toast">Memulai kembali dalam 5 detik…</string>
|
<string name="reboot_delay_toast">Memulai ulang dalam 5 detik…</string>
|
||||||
<string name="flash_screen_title">Instalasi</string>
|
<string name="flash_screen_title">Instalasi</string>
|
||||||
|
|
||||||
<!--Superuser-->
|
<!--Superuser-->
|
||||||
@@ -94,16 +99,20 @@
|
|||||||
|
|
||||||
<!--Module-->
|
<!--Module-->
|
||||||
<string name="no_info_provided">(Info tidak tersedia)</string>
|
<string name="no_info_provided">(Info tidak tersedia)</string>
|
||||||
<string name="reboot_userspace">Nyalakan ulang secara halus</string>
|
<string name="reboot_userspace">Mulai ulang secara halus</string>
|
||||||
<string name="reboot_recovery">Nyalakan ke mode Recovery</string>
|
<string name="reboot_recovery">Mulai ulang ke mode Recovery</string>
|
||||||
<string name="reboot_bootloader">Nyalakan ke mode Bootloader</string>
|
<string name="reboot_bootloader">Mulai ulang ke mode Bootloader</string>
|
||||||
<string name="reboot_download">Nyalakan ke mode Download</string>
|
<string name="reboot_download">Mulai ulang ke mode Download</string>
|
||||||
<string name="reboot_edl">Nyalakan ke mode EDL</string>
|
<string name="reboot_edl">Mulai ulang ke mode EDL</string>
|
||||||
<string name="module_version_author">%1$s oleh %2$s</string>
|
<string name="module_version_author">%1$s oleh %2$s</string>
|
||||||
<string name="module_state_remove">Hapus</string>
|
<string name="module_state_remove">Hapus</string>
|
||||||
<string name="module_state_restore">Pulihkan</string>
|
<string name="module_state_restore">Pulihkan</string>
|
||||||
<string name="module_action_install_external">Instal dari penyimpanan</string>
|
<string name="module_action_install_external">Pasang dari penyimpanan</string>
|
||||||
<string name="update_available">Update tersedia</string>
|
<string name="update_available">Pembaruan tersedia</string>
|
||||||
|
<string name="suspend_text_riru">Modul ditangguhkan karena %1$s diaktifkan</string>
|
||||||
|
<string name="suspend_text_zygisk">Modul ditangguhkan karena %1$s tidak diaktifkan</string>
|
||||||
|
<string name="zygisk_module_unloaded">Modul Zygisk tidak dimuat karena ketidakcocokan</string>
|
||||||
|
<string name="module_empty">Tidak ada modul terpasang</string>
|
||||||
|
|
||||||
<!--Settings-->
|
<!--Settings-->
|
||||||
<string name="settings_dark_mode_title">Mode tema</string>
|
<string name="settings_dark_mode_title">Mode tema</string>
|
||||||
@@ -111,17 +120,27 @@
|
|||||||
<string name="settings_dark_mode_light">Selalu terang</string>
|
<string name="settings_dark_mode_light">Selalu terang</string>
|
||||||
<string name="settings_dark_mode_system">Ikuti sistem</string>
|
<string name="settings_dark_mode_system">Ikuti sistem</string>
|
||||||
<string name="settings_dark_mode_dark">Selalu gelap</string>
|
<string name="settings_dark_mode_dark">Selalu gelap</string>
|
||||||
<string name="settings_download_path_title">Lokasi download</string>
|
<string name="settings_download_path_title">Lokasi unduhan</string>
|
||||||
<string name="settings_download_path_message">File akan disimpan ke %1$s</string>
|
<string name="settings_download_path_message">File akan disimpan ke %1$s</string>
|
||||||
|
<string name="settings_hide_app_title">Sembunyikan aplikasi Magisk</string>
|
||||||
|
<string name="settings_hide_app_summary">Pasang aplikasi proxy dengan ID paket acak dan label aplikasi khusus</string>
|
||||||
|
<string name="settings_restore_app_title">Pulihkan aplikasi Magisk</string>
|
||||||
|
<string name="settings_restore_app_summary">Tampilkan aplikasi and pulihkan APK asli</string>
|
||||||
<string name="language">Bahasa</string>
|
<string name="language">Bahasa</string>
|
||||||
<string name="system_default">(Default sistem)</string>
|
<string name="system_default">(Bawaan sistem)</string>
|
||||||
<string name="settings_check_update_title">Periksa update</string>
|
<string name="settings_check_update_title">Periksa pembaruan</string>
|
||||||
<string name="settings_check_update_summary">Periksa update secara berkala di latar belakang</string>
|
<string name="settings_check_update_summary">Periksa pembaruan secara berkala di latar belakang</string>
|
||||||
<string name="settings_update_channel_title">Kanal update</string>
|
<string name="settings_update_channel_title">Saluran pembaruan</string>
|
||||||
<string name="settings_update_stable">Stabil</string>
|
<string name="settings_update_stable">Stabil</string>
|
||||||
<string name="settings_update_beta">Beta</string>
|
<string name="settings_update_beta">Beta</string>
|
||||||
<string name="settings_update_custom">Kanal khusus</string>
|
<string name="settings_update_custom">Saluran khusus</string>
|
||||||
<string name="settings_update_custom_msg">Masukkan URL khusus</string>
|
<string name="settings_update_custom_msg">Masukkan URL khusus</string>
|
||||||
|
<string name="settings_zygisk_summary">Jalankan bagian-bagian Magisk dalam zygote daemon</string>
|
||||||
|
<string name="settings_denylist_title">Paksa DenyList</string>
|
||||||
|
<string name="settings_denylist_summary">Proses pada denylist akan mengembalikan semua modifikasi Magisk</string>
|
||||||
|
<string name="settings_denylist_error">Fitur ini membutuhkan %1$s untuk diaktifkan</string>
|
||||||
|
<string name="settings_denylist_config_title">Konfigurasi DenyList</string>
|
||||||
|
<string name="settings_denylist_config_summary">Pilih proses yang akan disertakan pada denylist</string>
|
||||||
<string name="settings_hosts_title">Host systemless</string>
|
<string name="settings_hosts_title">Host systemless</string>
|
||||||
<string name="settings_hosts_summary">Dukungan host secara systemless untuk aplikasi pemblokir iklan</string>
|
<string name="settings_hosts_summary">Dukungan host secara systemless untuk aplikasi pemblokir iklan</string>
|
||||||
<string name="settings_hosts_toast">Menambahkan modul host systemless</string>
|
<string name="settings_hosts_toast">Menambahkan modul host systemless</string>
|
||||||
@@ -142,8 +161,8 @@
|
|||||||
<string name="auto_response">Respons otomatis</string>
|
<string name="auto_response">Respons otomatis</string>
|
||||||
<string name="request_timeout">Batas waktu permintaan</string>
|
<string name="request_timeout">Batas waktu permintaan</string>
|
||||||
<string name="superuser_notification">Notifikasi superuser</string>
|
<string name="superuser_notification">Notifikasi superuser</string>
|
||||||
<string name="settings_su_reauth_title">Autentikasi ulang setelah upgrade</string>
|
<string name="settings_su_reauth_title">Autentikasi ulang setelah peningkatan</string>
|
||||||
<string name="settings_su_reauth_summary">Autentikasi ulang izin akses superuser setelah aplikasi diupgrade</string>
|
<string name="settings_su_reauth_summary">Autentikasi ulang izin akses superuser setelah aplikasi ditingkatkan</string>
|
||||||
<string name="settings_su_tapjack_title">Aktifkan perlindungan tapjacking</string>
|
<string name="settings_su_tapjack_title">Aktifkan perlindungan tapjacking</string>
|
||||||
<string name="settings_su_tapjack_summary">Dialog permintaan superuser tidak akan menanggapi masukan saat terhalangi oleh lapisan atau jendela lainnya</string>
|
<string name="settings_su_tapjack_summary">Dialog permintaan superuser tidak akan menanggapi masukan saat terhalangi oleh lapisan atau jendela lainnya</string>
|
||||||
<string name="settings_su_biometric_title">Aktifkan autentikasi biometrik</string>
|
<string name="settings_su_biometric_title">Aktifkan autentikasi biometrik</string>
|
||||||
@@ -171,35 +190,51 @@
|
|||||||
<string name="isolate_summary">Setiap sesi root akan memiliki ruang-nama tersendiri</string>
|
<string name="isolate_summary">Setiap sesi root akan memiliki ruang-nama tersendiri</string>
|
||||||
|
|
||||||
<!--Notifications-->
|
<!--Notifications-->
|
||||||
<string name="update_channel">Update Magisk</string>
|
<string name="update_channel">Pembaruan Magisk</string>
|
||||||
<string name="progress_channel">Notifikasi Kemajuan</string>
|
<string name="progress_channel">Notifikasi Kemajuan</string>
|
||||||
<string name="download_complete">Download selesai</string>
|
<string name="updated_channel">Pembaruan Selesai</string>
|
||||||
<string name="download_file_error">Kesalahan saat mendownload file</string>
|
<string name="download_complete">Unduhan selesai</string>
|
||||||
<string name="magisk_update_title">Update Magisk tersedia!</string>
|
<string name="download_file_error">Kesalahan saat mengunduh file</string>
|
||||||
|
<string name="magisk_update_title">Pembaruan Magisk tersedia!</string>
|
||||||
|
<string name="updated_title">Magisk Diperbarui</string>
|
||||||
|
<string name="updated_text">Ketuk untuk buka aplikasi</string>
|
||||||
|
|
||||||
<!--Toasts, Dialogs-->
|
<!--Toasts, Dialogs-->
|
||||||
<string name="yes">Ya</string>
|
<string name="yes">Ya</string>
|
||||||
<string name="no">Tidak</string>
|
<string name="no">Tidak</string>
|
||||||
<string name="repo_install_title">Instal %1$s %2$s(%3$d)</string>
|
<string name="repo_install_title">Pasang %1$s %2$s(%3$d)</string>
|
||||||
<string name="download">Download</string>
|
<string name="download">Unduh</string>
|
||||||
<string name="reboot">Nyalakan ulang</string>
|
<string name="reboot">Mulai ulang</string>
|
||||||
<string name="release_notes">Catatan rilis</string>
|
<string name="release_notes">Catatan rilis</string>
|
||||||
<string name="flashing">Memasang…</string>
|
<string name="flashing">Memasang…</string>
|
||||||
<string name="done">Selesai!</string>
|
<string name="done">Selesai!</string>
|
||||||
<string name="failure">Gagal!</string>
|
<string name="failure">Gagal!</string>
|
||||||
|
<string name="hide_app_title">Menyembunyikan aplikasi Magisk…</string>
|
||||||
<string name="open_link_failed_toast">Tidak ditemukan aplikasi untuk membuka link ini</string>
|
<string name="open_link_failed_toast">Tidak ditemukan aplikasi untuk membuka link ini</string>
|
||||||
<string name="complete_uninstall">Uninstal penuh</string>
|
<string name="complete_uninstall">Pencopotan penuh</string>
|
||||||
<string name="restore_img">Pulihkan image</string>
|
<string name="restore_img">Pulihkan image</string>
|
||||||
<string name="restore_img_msg">Memulihkan…</string>
|
<string name="restore_img_msg">Memulihkan…</string>
|
||||||
<string name="restore_done">Pemulihan selesai!</string>
|
<string name="restore_done">Pemulihan selesai!</string>
|
||||||
<string name="restore_fail">Cadangan stock tidak ada!</string>
|
<string name="restore_fail">Cadangan stock tidak ada!</string>
|
||||||
<string name="setup_fail">Penyiapan gagal</string>
|
<string name="setup_fail">Penyiapan gagal</string>
|
||||||
<string name="env_fix_title">Perlu penyiapan tambahan</string>
|
<string name="env_fix_title">Perlu penyiapan tambahan</string>
|
||||||
|
<string name="env_fix_msg">Perangkat Anda membutuhkan pengaturan tambahan untuk Magisk agar berfungsi dengan benar. Apakah Anda ingin melanjutkan dan Menyalakan ulang?</string>
|
||||||
<string name="setup_msg">Memproses penyiapan lingkungan…</string>
|
<string name="setup_msg">Memproses penyiapan lingkungan…</string>
|
||||||
<string name="authenticate">Autentikasi</string>
|
<string name="authenticate">Autentikasi</string>
|
||||||
<string name="unsupport_magisk_title">Versi Magisk tidak didukung</string>
|
<string name="unsupport_magisk_title">Versi Magisk tidak didukung</string>
|
||||||
|
<string name="unsupport_magisk_msg">Versi aplikasi ini tidak mendukung versi Magisk yang lebih rendah dari %1$s.\n\nAplikasi akan berperilaku seolah-olah tidak ada Magisk yang dipasang, harap tingkatkan Magisk sesegera mungkin.</string>
|
||||||
|
<string name="unsupport_general_title">Keadaan tidak normal</string>
|
||||||
|
<string name="unsupport_system_app_msg">Menjalankan aplikasi ini sebagai aplikasi sistem tidak didukung. Harap kembalikan aplikasi ke aplikasi pengguna.</string>
|
||||||
|
<string name="unsupport_other_su_msg">Sebuah \"su\" biner bukan dari Magisk telah terdeteksi. Hapus semua solusi root yang bersaing dan/atau pasang ulang Magisk.</string>
|
||||||
|
<string name="unsupport_external_storage_msg">Magisk dipasang ke penyimpanan eksternal. Harap pindahkan aplikasi ke penyimpanan internal.</string>
|
||||||
|
<string name="unsupport_nonroot_stub_msg">Aplikasi Magisk yang tersembunyi tidak dapat terus berfungsi karena root hilang. Tolong pulihkan APK asli.</string>
|
||||||
|
<string name="unsupport_nonroot_stub_title">@string/settings_restore_app_title</string>
|
||||||
<string name="external_rw_permission_denied">Berikan izin akses ke penyimpanan untuk mengaktifkan fungsi ini</string>
|
<string name="external_rw_permission_denied">Berikan izin akses ke penyimpanan untuk mengaktifkan fungsi ini</string>
|
||||||
|
<string name="install_unknown_denied">Izinkan "Sumber tidak dikenal" untuk mengaktifkan fungsi ini</string>
|
||||||
<string name="add_shortcut_title">Tambahkan pintasan ke layar utama</string>
|
<string name="add_shortcut_title">Tambahkan pintasan ke layar utama</string>
|
||||||
|
<string name="add_shortcut_msg">Setelah menyembunyikan aplikasi ini, nama dan ikonnya mungkin sulit dikenali. Apakah Anda ingin menambahkan pintasan cantik ke layar utama?</string>
|
||||||
<string name="app_not_found">Tidak ditemukan aplikasi untuk menangani tindakan ini</string>
|
<string name="app_not_found">Tidak ditemukan aplikasi untuk menangani tindakan ini</string>
|
||||||
|
<string name="reboot_apply_change">Mulai ulang untuk menerapkan perubahan</string>
|
||||||
|
<string name="restore_app_confirmation">Ini akan mengembalikan aplikasi tersembunyi kembali ke aplikasi asli. Apakah Anda benar-benar ingin melakukan ini?</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -234,7 +234,7 @@
|
|||||||
<string name="add_shortcut_title">Добавление ярлыка</string>
|
<string name="add_shortcut_title">Добавление ярлыка</string>
|
||||||
<string name="add_shortcut_msg">После скрытия приложения Magisk его название и иконка могут быть неудобны для восприятия. Хотите создать ярлык на рабочем столе?</string>
|
<string name="add_shortcut_msg">После скрытия приложения Magisk его название и иконка могут быть неудобны для восприятия. Хотите создать ярлык на рабочем столе?</string>
|
||||||
<string name="app_not_found">Приложение для обработки этого действия не найдено</string>
|
<string name="app_not_found">Приложение для обработки этого действия не найдено</string>
|
||||||
<string name="reboot_apply_change">Перезагрузить для применения изменений</string>
|
<string name="reboot_apply_change">Перезагрузите устройство для применения изменений</string>
|
||||||
<string name="restore_app_confirmation">Это действие восстановит пересобранное для скрытия приложение к исходному состоянию. Вы действительно хотите продолжить?</string>
|
<string name="restore_app_confirmation">Это действие восстановит пересобранное для скрытия приложение к исходному состоянию. Вы действительно хотите продолжить?</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -130,7 +130,7 @@
|
|||||||
<string name="system_default">(Mặc định hệ thống)</string>
|
<string name="system_default">(Mặc định hệ thống)</string>
|
||||||
<string name="settings_check_update_title">Kiểm tra cập nhật</string>
|
<string name="settings_check_update_title">Kiểm tra cập nhật</string>
|
||||||
<string name="settings_check_update_summary">Kiểm tra định kỳ các bản cập nhật trong nền</string>
|
<string name="settings_check_update_summary">Kiểm tra định kỳ các bản cập nhật trong nền</string>
|
||||||
<string name="settings_update_channel_title">Cập nhật kênh</string>
|
<string name="settings_update_channel_title">Kênh cập nhật</string>
|
||||||
<string name="settings_update_stable">Ổn định</string>
|
<string name="settings_update_stable">Ổn định</string>
|
||||||
<string name="settings_update_beta">Beta</string>
|
<string name="settings_update_beta">Beta</string>
|
||||||
<string name="settings_update_custom">Kênh tùy chỉnh</string>
|
<string name="settings_update_custom">Kênh tùy chỉnh</string>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user