Merge remote-tracking branch 'john/master' into development
This commit is contained in:
commit
1b4ae70a43
21
README.MD
21
README.MD
@ -38,6 +38,27 @@ Default string resources for Magisk Manager are scattered throughout
|
||||
|
||||
Translate each and place them in the respective locations (`<module>/src/main/res/values-<lang>/strings.xml`).
|
||||
|
||||
## Signature Verification
|
||||
|
||||
Official release zips and APKs are signed with my personal private key. You can verify the key certificate to make sure the binaries you downloaded are not manipulated in anyway.
|
||||
|
||||
``` bash
|
||||
# Use the keytool command from JDK to print certificates
|
||||
keytool -printcert -jarfile <APK or Magisk zip>
|
||||
|
||||
# The output should contain the following signature
|
||||
Owner: CN=John Wu, L=Taipei, C=TW
|
||||
Issuer: CN=John Wu, L=Taipei, C=TW
|
||||
Serial number: 50514879
|
||||
Valid from: Sun Aug 14 13:23:44 EDT 2016 until: Tue Jul 21 13:23:44 EDT 2116
|
||||
Certificate fingerprints:
|
||||
MD5: CE:DA:68:C1:E1:74:71:0A:EF:58:89:7D:AE:6E:AB:4F
|
||||
SHA1: DC:0F:2B:61:CB:D7:E9:D3:DB:BE:06:0B:2B:87:0D:46:BB:06:02:11
|
||||
SHA256: B4:CB:83:B4:DA:D9:9F:99:7D:BE:87:2F:01:3A:A1:6C:14:EE:C4:1D:16:70:21:F3:71:F7:E1:33:0F:27:3E:E6
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Version: 3
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Magisk, including all git submodules are free software:
|
||||
|
@ -59,10 +59,6 @@ dependencies {
|
||||
implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
|
||||
implementation "com.github.topjohnwu.libsu:io:${libsuVersion}"
|
||||
|
||||
def butterKnifeVersion = '10.1.0'
|
||||
implementation "com.jakewharton:butterknife-runtime:${butterKnifeVersion}"
|
||||
kapt "com.jakewharton:butterknife-compiler:${butterKnifeVersion}"
|
||||
|
||||
def koin = "2.0.0-rc-2"
|
||||
implementation "org.koin:koin-core:${koin}"
|
||||
implementation "org.koin:koin-android:${koin}"
|
||||
|
@ -1,6 +1,5 @@
|
||||
package com.topjohnwu.magisk.di
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.topjohnwu.magisk.ui.MainViewModel
|
||||
import com.topjohnwu.magisk.ui.flash.FlashViewModel
|
||||
@ -10,7 +9,6 @@ import com.topjohnwu.magisk.ui.log.LogViewModel
|
||||
import com.topjohnwu.magisk.ui.module.ModuleViewModel
|
||||
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
|
||||
import com.topjohnwu.magisk.ui.surequest.SuRequestViewModel
|
||||
import com.topjohnwu.magisk.ui.surequest._SuRequestViewModel
|
||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
|
||||
@ -23,8 +21,5 @@ val viewModelModules = module {
|
||||
viewModel { ModuleViewModel(get(), get()) }
|
||||
viewModel { LogViewModel(get(), get()) }
|
||||
viewModel { (action: String, uri: Uri?) -> FlashViewModel(action, uri, get()) }
|
||||
viewModel { (intent: Intent, action: String?) ->
|
||||
_SuRequestViewModel(intent, action.orEmpty(), get(), get())
|
||||
}
|
||||
viewModel { SuRequestViewModel(get(), get(), get(SUTimeout), get()) }
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.topjohnwu.magisk.model.entity.state
|
||||
|
||||
enum class IndeterminateState {
|
||||
INDETERMINATE, CHECKED, UNCHECKED
|
||||
}
|
||||
CHECKED, INDETERMINATE, UNCHECKED
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.topjohnwu.magisk.model.navigation
|
||||
|
||||
import com.topjohnwu.magisk.ui.hide.MagiskHideFragment
|
||||
import com.topjohnwu.magisk.ui.home.MagiskFragment
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragment
|
||||
import com.topjohnwu.magisk.ui.log.LogFragment
|
||||
import com.topjohnwu.magisk.ui.module.ModulesFragment
|
||||
import com.topjohnwu.magisk.ui.module.ReposFragment
|
||||
@ -12,8 +12,8 @@ import com.topjohnwu.magisk.ui.superuser.SuperuserFragment
|
||||
object Navigation {
|
||||
|
||||
fun home() = MagiskNavigationEvent {
|
||||
navDirections { destination = MagiskFragment::class }
|
||||
navOptions { popUpTo = MagiskFragment::class }
|
||||
navDirections { destination = HomeFragment::class }
|
||||
navOptions { popUpTo = HomeFragment::class }
|
||||
}
|
||||
|
||||
fun superuser() = MagiskNavigationEvent {
|
||||
|
@ -12,6 +12,7 @@ import com.topjohnwu.magisk.databinding.ActivityMainBinding
|
||||
import com.topjohnwu.magisk.model.navigation.Navigation
|
||||
import com.topjohnwu.magisk.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.ui.hide.MagiskHideFragment
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragment
|
||||
import com.topjohnwu.magisk.ui.log.LogFragment
|
||||
import com.topjohnwu.magisk.ui.module.ModulesFragment
|
||||
import com.topjohnwu.magisk.ui.module.ReposFragment
|
||||
@ -22,7 +23,6 @@ import com.topjohnwu.net.Networking
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import kotlin.reflect.KClass
|
||||
import com.topjohnwu.magisk.ui.home.MagiskFragment as HomeFragment
|
||||
|
||||
|
||||
open class MainActivity : MagiskActivity<MainViewModel, ActivityMainBinding>() {
|
||||
|
@ -14,6 +14,7 @@ import com.topjohnwu.magisk.model.entity.HideAppInfo
|
||||
import com.topjohnwu.magisk.model.entity.HideTarget
|
||||
import com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem
|
||||
import com.topjohnwu.magisk.model.entity.recycler.HideRvItem
|
||||
import com.topjohnwu.magisk.model.entity.state.IndeterminateState
|
||||
import com.topjohnwu.magisk.model.events.HideProcessEvent
|
||||
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
@ -72,7 +73,8 @@ class HideViewModel(
|
||||
.filter { it.processes.isNotEmpty() }
|
||||
.map { HideRvItem(it, hideTargets.blockingGet()) }
|
||||
.toList()
|
||||
.map { it.sortBy { it.item.info.name }; it }
|
||||
.map { it.sortWith(compareBy(
|
||||
{it.isHiddenState.value}, {it.item.info.name}, {it.packageName})); it }
|
||||
.doOnSuccess { allItems.update(it) }
|
||||
.flatMap { queryRaw() }
|
||||
.applyViewModel(this)
|
||||
@ -94,7 +96,10 @@ class HideViewModel(
|
||||
it.item.name.contains(query, ignoreCase = true) ||
|
||||
it.item.processes.any { it.contains(query, ignoreCase = true) }
|
||||
}
|
||||
.filter { if (showSystem) true else it.item.info.flags and ApplicationInfo.FLAG_SYSTEM == 0 }
|
||||
.filter {
|
||||
showSystem || (it.isHiddenState.value != IndeterminateState.UNCHECKED) ||
|
||||
(it.item.info.flags and ApplicationInfo.FLAG_SYSTEM == 0)
|
||||
}
|
||||
.toList()
|
||||
.map { it to items.calculateDiff(it) }
|
||||
|
||||
|
@ -1,24 +1,22 @@
|
||||
package com.topjohnwu.magisk.ui.home
|
||||
|
||||
import android.app.Activity
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.databinding.FragmentMagiskBinding
|
||||
import com.topjohnwu.magisk.model.events.*
|
||||
import com.topjohnwu.magisk.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.ui.base.MagiskFragment
|
||||
import com.topjohnwu.magisk.utils.ISafetyNetHelper
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import com.topjohnwu.magisk.view.SafetyNet
|
||||
import com.topjohnwu.magisk.view.SafetyNet.EXT_APK
|
||||
import com.topjohnwu.magisk.view.dialogs.*
|
||||
import com.topjohnwu.net.Networking
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import dalvik.system.DexClassLoader
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import com.topjohnwu.magisk.ui.base.MagiskFragment as NewMagiskFragment
|
||||
import java.io.File
|
||||
|
||||
class MagiskFragment : NewMagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
||||
ISafetyNetHelper.Callback {
|
||||
|
||||
override val layoutRes: Int = R.layout.fragment_magisk
|
||||
@ -83,7 +81,16 @@ class MagiskFragment : NewMagiskFragment<HomeViewModel, FragmentMagiskBinding>()
|
||||
|
||||
private fun updateSafetyNet(dieOnError: Boolean) {
|
||||
try {
|
||||
SafetyNet.dyRun(requireActivity(), this)
|
||||
val loader = DexClassLoader(EXT_APK.path, EXT_APK.parent, null,
|
||||
ISafetyNetHelper::class.java.classLoader)
|
||||
val clazz = loader.loadClass("com.topjohnwu.snet.Snet")
|
||||
val helper = clazz.getMethod("newHelper",
|
||||
Class::class.java, String::class.java, Activity::class.java, Any::class.java)
|
||||
.invoke(null, ISafetyNetHelper::class.java, EXT_APK.path,
|
||||
requireActivity(), this) as ISafetyNetHelper
|
||||
if (helper.version < Const.SNET_EXT_VER)
|
||||
throw Exception()
|
||||
helper.attest()
|
||||
} catch (e: Exception) {
|
||||
if (dieOnError) {
|
||||
viewModel.finishSafetyNetCheck(-1)
|
||||
@ -94,5 +101,9 @@ class MagiskFragment : NewMagiskFragment<HomeViewModel, FragmentMagiskBinding>()
|
||||
downloadSafetyNet(!dieOnError)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EXT_APK = File("${App.self.filesDir.parent}/snet", "snet.apk")
|
||||
}
|
||||
}
|
||||
|
@ -1,166 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.surequest
|
||||
|
||||
import android.hardware.fingerprint.FingerprintManager
|
||||
import android.os.CountDownTimer
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.widget.Toast
|
||||
import androidx.core.text.bold
|
||||
import com.skoumal.teanity.viewevents.ViewEvent
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.ActivitySuRequestBinding
|
||||
import com.topjohnwu.magisk.model.entity.Policy
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.events.SuDialogEvent
|
||||
import com.topjohnwu.magisk.ui.base.MagiskActivity
|
||||
import com.topjohnwu.magisk.utils.FingerprintHelper
|
||||
import com.topjohnwu.magisk.utils.feature.WIP
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
|
||||
@WIP
|
||||
open class _SuRequestActivity : MagiskActivity<_SuRequestViewModel, ActivitySuRequestBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_su_request
|
||||
override val viewModel: _SuRequestViewModel by viewModel {
|
||||
parametersOf(intent, intent.action)
|
||||
}
|
||||
|
||||
//private val timeoutPrefs: SharedPreferences by inject(SUTimeout)
|
||||
private val canUseFingerprint get() = FingerprintHelper.useFingerprint()
|
||||
|
||||
private val countdown by lazy {
|
||||
val seconds = Config.get<Int>(Config.Key.SU_REQUEST_TIMEOUT).toLong()
|
||||
val millis = SECONDS.toMillis(seconds)
|
||||
object : CountDownTimer(millis, 1000) {
|
||||
override fun onFinish() {
|
||||
viewModel.deny()
|
||||
}
|
||||
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
dialog.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
Timber.e("Tick, tock")
|
||||
title = "%s (%d)".format(
|
||||
getString(R.string.deny),
|
||||
MILLISECONDS.toSeconds(millisUntilFinished)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var fingerprintHelper: SuFingerprint? = null
|
||||
|
||||
private lateinit var dialog: MagiskDialog
|
||||
|
||||
override fun onEventDispatched(event: ViewEvent) {
|
||||
super.onEventDispatched(event)
|
||||
when (event) {
|
||||
is SuDialogEvent -> showDialog(event.policy)
|
||||
is DieEvent -> finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (::dialog.isInitialized && dialog.isShowing) {
|
||||
return
|
||||
}
|
||||
super.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (this::dialog.isInitialized && dialog.isShowing) {
|
||||
dialog.dismiss()
|
||||
}
|
||||
fingerprintHelper?.cancel()
|
||||
countdown.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun showDialog(policy: Policy) {
|
||||
val titleText = SpannableStringBuilder("Allow ")
|
||||
.bold { append(policy.appName) }
|
||||
.append(" to access superuser rights?")
|
||||
|
||||
val messageText = StringBuilder()
|
||||
.appendln(policy.packageName)
|
||||
.append(getString(R.string.su_warning))
|
||||
|
||||
dialog = MagiskDialog(this)
|
||||
.applyIcon(policy.info.loadIcon(packageManager))
|
||||
.applyTitle(titleText)
|
||||
.applyMessage(messageText)
|
||||
//.applyView()) {} //todo add a spinner
|
||||
.cancellable(false)
|
||||
.applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
titleRes = R.string.grant
|
||||
onClick { viewModel.grant() }
|
||||
if (canUseFingerprint) {
|
||||
icon = R.drawable.ic_fingerprint
|
||||
}
|
||||
}
|
||||
.applyButton(MagiskDialog.ButtonType.NEUTRAL) {
|
||||
title = "%s %s".format(getString(R.string.grant), getString(R.string.once))
|
||||
onClick { viewModel.grant(-1) }
|
||||
}
|
||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = R.string.deny
|
||||
onClick { viewModel.deny() }
|
||||
}
|
||||
.onDismiss { finish() }
|
||||
.onShow {
|
||||
startTimer().also { Timber.e("Starting timer") }
|
||||
if (canUseFingerprint) {
|
||||
startFingerprintQuery()
|
||||
}
|
||||
}
|
||||
.reveal()
|
||||
}
|
||||
|
||||
private fun startTimer() {
|
||||
countdown.start()
|
||||
}
|
||||
|
||||
private fun startFingerprintQuery() {
|
||||
val result = runCatching {
|
||||
fingerprintHelper = SuFingerprint().apply { authenticate() }
|
||||
}
|
||||
|
||||
if (result.isFailure) {
|
||||
dialog.applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
icon = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SuFingerprint @Throws(Exception::class)
|
||||
internal constructor() : FingerprintHelper() {
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
Toast.makeText(this@_SuRequestActivity, errString, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun onAuthenticationHelp(helpCode: Int, helpString: CharSequence) {
|
||||
Toast.makeText(this@_SuRequestActivity, helpString, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) {
|
||||
viewModel.grant()
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
Toast.makeText(this@_SuRequestActivity, R.string.auth_fail, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val REQUEST = "request"
|
||||
const val LOG = "log"
|
||||
const val NOTIFY = "notify"
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.surequest
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import com.skoumal.teanity.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.data.database.MagiskDB
|
||||
import com.topjohnwu.magisk.model.entity.Policy
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.events.SuDialogEvent
|
||||
import com.topjohnwu.magisk.ui.base.MagiskViewModel
|
||||
import com.topjohnwu.magisk.utils.SuConnector
|
||||
import com.topjohnwu.magisk.utils.SuLogger
|
||||
import com.topjohnwu.magisk.utils.feature.WIP
|
||||
import com.topjohnwu.magisk.utils.now
|
||||
import io.reactivex.Single
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit.MILLISECONDS
|
||||
import java.util.concurrent.TimeUnit.MINUTES
|
||||
|
||||
@WIP
|
||||
class _SuRequestViewModel(
|
||||
intent: Intent,
|
||||
action: String,
|
||||
private val packageManager: PackageManager,
|
||||
private val database: MagiskDB
|
||||
) : MagiskViewModel() {
|
||||
|
||||
private val connector: Single<SuConnector> = Single.fromCallable {
|
||||
val socketName = intent.extras?.getString("socket") ?: let {
|
||||
deny()
|
||||
throw IllegalStateException("Socket is empty or null")
|
||||
}
|
||||
object : SuConnector(socketName) {
|
||||
override fun onResponse() {
|
||||
policy.subscribeK { out.writeInt(it.policy) } //this just might be incorrect, lol
|
||||
}
|
||||
} as SuConnector
|
||||
}.cache()
|
||||
|
||||
private val policy: Single<Policy> = connector.map {
|
||||
val bundle = it.readSocketInput() ?: throw IllegalStateException("Socket bundle is null")
|
||||
val uid = bundle.getString("uid")?.toIntOrNull() ?: let {
|
||||
deny()
|
||||
throw IllegalStateException("UID is empty or null")
|
||||
}
|
||||
database.clearOutdated()
|
||||
database.getPolicy(uid) ?: Policy(uid, packageManager)
|
||||
}.cache()
|
||||
|
||||
init {
|
||||
when (action) {
|
||||
SuRequestActivity.LOG -> SuLogger.handleLogs(intent).also { die() }
|
||||
SuRequestActivity.NOTIFY -> SuLogger.handleNotify(intent).also { die() }
|
||||
SuRequestActivity.REQUEST -> process()
|
||||
else -> back() // invalid action, should ignore
|
||||
}
|
||||
}
|
||||
|
||||
private fun process() {
|
||||
policy.subscribeK(onError = ::deny) { process(it) }
|
||||
}
|
||||
|
||||
private fun process(policy: Policy) {
|
||||
if (policy.packageName == BuildConfig.APPLICATION_ID)
|
||||
deny().also { return }
|
||||
|
||||
if (policy.policy != Policy.INTERACTIVE)
|
||||
grant().also { return }
|
||||
|
||||
when (Config.get<Int>(Config.Key.SU_AUTO_RESPONSE)) {
|
||||
Config.Value.SU_AUTO_DENY -> deny().also { return }
|
||||
Config.Value.SU_AUTO_ALLOW -> grant().also { return }
|
||||
}
|
||||
|
||||
requestDialog(policy)
|
||||
}
|
||||
|
||||
fun deny(e: Throwable? = null) = updatePolicy(Policy.DENY, 0).also { Timber.e(e) }
|
||||
fun grant(time: Long = 0) = updatePolicy(Policy.ALLOW, time)
|
||||
|
||||
private fun updatePolicy(action: Int, time: Long) {
|
||||
|
||||
fun finish(e: Throwable? = null) = die().also { Timber.e(e) }
|
||||
|
||||
policy
|
||||
.map { it.policy = action; it }
|
||||
.doOnSuccess {
|
||||
if (time >= 0) {
|
||||
it.until = if (time == 0L) {
|
||||
0
|
||||
} else {
|
||||
MILLISECONDS.toSeconds(now) + MINUTES.toSeconds(time)
|
||||
}
|
||||
database.updatePolicy(it)
|
||||
}
|
||||
}
|
||||
.flatMap { connector }
|
||||
.subscribeK(onError = ::finish) {
|
||||
it.response()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestDialog(policy: Policy) {
|
||||
SuDialogEvent(policy).publish()
|
||||
}
|
||||
|
||||
private fun die() = DieEvent().publish()
|
||||
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
package com.topjohnwu.magisk.view;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.Const;
|
||||
import com.topjohnwu.magisk.R;
|
||||
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
|
||||
import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog;
|
||||
import com.topjohnwu.net.Networking;
|
||||
import com.topjohnwu.superuser.Shell;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import butterknife.BindColor;
|
||||
import butterknife.BindView;
|
||||
import butterknife.OnClick;
|
||||
import butterknife.Unbinder;
|
||||
import dalvik.system.DexClassLoader;
|
||||
|
||||
public class SafetyNet implements ISafetyNetHelper.Callback {
|
||||
|
||||
public static final File EXT_APK =
|
||||
new File(App.self.getFilesDir().getParent() + "/snet", "snet.apk");
|
||||
|
||||
/*@BindView(R.id.safetyNet_card) */ CardView safetyNetCard;
|
||||
@BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon;
|
||||
@BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
|
||||
@BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
|
||||
@BindView(R.id.safetyNet_expand) ViewGroup expandLayout;
|
||||
@BindView(R.id.cts_status_icon) ImageView ctsStatusIcon;
|
||||
@BindView(R.id.cts_status) TextView ctsStatusText;
|
||||
@BindView(R.id.basic_status_icon) ImageView basicStatusIcon;
|
||||
@BindView(R.id.basic_status) TextView basicStatusText;
|
||||
|
||||
@BindColor(R.color.red500) int colorBad;
|
||||
@BindColor(R.color.green500) int colorOK;
|
||||
|
||||
public Unbinder unbinder;
|
||||
private final ExpandableViewHolder expandable;
|
||||
|
||||
public SafetyNet(View v) {
|
||||
unbinder = new SafetyNet_ViewBinding(this, v);
|
||||
expandable = new ExpandableViewHolder(expandLayout);
|
||||
Context context = v.getContext();
|
||||
safetyNetCard.setVisibility(hasGms(context) && Networking.checkNetworkStatus(context) ?
|
||||
View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
public static void dyRun(Activity activity, Object callback) throws Exception {
|
||||
DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(),
|
||||
null, ISafetyNetHelper.class.getClassLoader());
|
||||
Class<?> clazz = loader.loadClass("com.topjohnwu.snet.Snet");
|
||||
ISafetyNetHelper helper = (ISafetyNetHelper) clazz.getMethod("newHelper",
|
||||
Class.class, String.class, Activity.class, Object.class)
|
||||
.invoke(null, ISafetyNetHelper.class, EXT_APK.getPath(), activity, callback);
|
||||
if (helper.getVersion() < Const.SNET_EXT_VER)
|
||||
throw new Exception();
|
||||
helper.attest();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
safetyNetStatusText.setText(R.string.safetyNet_check_text);
|
||||
expandable.setExpanded(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(int response) {
|
||||
safetyNetProgress.setVisibility(View.GONE);
|
||||
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
|
||||
if ((response & 0x0F) == 0) {
|
||||
safetyNetStatusText.setText(R.string.safetyNet_check_success);
|
||||
|
||||
boolean b;
|
||||
b = (response & ISafetyNetHelper.CTS_PASS) != 0;
|
||||
ctsStatusText.setText("ctsProfile: " + b);
|
||||
ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
|
||||
ctsStatusIcon.setColorFilter(b ? colorOK : colorBad);
|
||||
|
||||
b = (response & ISafetyNetHelper.BASIC_PASS) != 0;
|
||||
basicStatusText.setText("basicIntegrity: " + b);
|
||||
basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
|
||||
basicStatusIcon.setColorFilter(b ? colorOK : colorBad);
|
||||
|
||||
expandable.expand();
|
||||
} else {
|
||||
@StringRes int resid;
|
||||
switch (response) {
|
||||
case ISafetyNetHelper.RESPONSE_ERR:
|
||||
resid = R.string.safetyNet_res_invalid;
|
||||
break;
|
||||
case ISafetyNetHelper.CONNECTION_FAIL:
|
||||
default:
|
||||
resid = R.string.safetyNet_api_error;
|
||||
break;
|
||||
}
|
||||
safetyNetStatusText.setText(resid);
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.safetyNet_refresh)
|
||||
void safetyNet(View v) {
|
||||
Runnable task = () -> {
|
||||
safetyNetProgress.setVisibility(View.VISIBLE);
|
||||
safetyNetRefreshIcon.setVisibility(View.INVISIBLE);
|
||||
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
|
||||
check((Activity) v.getContext());
|
||||
expandable.collapse();
|
||||
};
|
||||
if (!EXT_APK.exists()) {
|
||||
// Show dialog
|
||||
new CustomAlertDialog(v.getContext())
|
||||
.setTitle(R.string.proprietary_title)
|
||||
.setMessage(R.string.proprietary_notice)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.yes, (d, i) -> task.run())
|
||||
.setNegativeButton(R.string.no_thanks, null)
|
||||
.show();
|
||||
} else {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void check(Activity activity) {
|
||||
try {
|
||||
dyRun(activity, this);
|
||||
} catch (Exception ignored) {
|
||||
Shell.sh("rm -rf " + EXT_APK.getParent()).exec();
|
||||
EXT_APK.getParentFile().mkdir();
|
||||
Networking.get(Const.Url.SNET_URL).getAsFile(EXT_APK, f -> {
|
||||
try {
|
||||
dyRun(activity, this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
onResponse(-1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasGms(Context context) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
PackageInfo info;
|
||||
try {
|
||||
info = pm.getPackageInfo("com.google.android.gms", 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
return info.applicationInfo.enabled;
|
||||
}
|
||||
}
|
@ -4,18 +4,14 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.topjohnwu.magisk.R;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import butterknife.BindView;
|
||||
|
||||
import com.topjohnwu.magisk.databinding.AlertDialogBinding;
|
||||
|
||||
public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
|
||||
@ -24,32 +20,16 @@ public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
private DialogInterface.OnClickListener neutralListener;
|
||||
|
||||
protected AlertDialog dialog;
|
||||
protected ViewHolder vh;
|
||||
|
||||
public class ViewHolder {
|
||||
@BindView(R.id.dialog_layout) public LinearLayout dialogLayout;
|
||||
@BindView(R.id.button_panel) public LinearLayout buttons;
|
||||
|
||||
@BindView(R.id.message) public TextView messageView;
|
||||
@BindView(R.id.negative) public Button negative;
|
||||
@BindView(R.id.positive) public Button positive;
|
||||
@BindView(R.id.neutral) public Button neutral;
|
||||
|
||||
ViewHolder(View v) {
|
||||
new CustomAlertDialog$ViewHolder_ViewBinding(this, v);
|
||||
messageView.setVisibility(View.GONE);
|
||||
negative.setVisibility(View.GONE);
|
||||
positive.setVisibility(View.GONE);
|
||||
neutral.setVisibility(View.GONE);
|
||||
buttons.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
protected AlertDialogBinding binding;
|
||||
|
||||
{
|
||||
View v = LayoutInflater.from(getContext()).inflate(R.layout.alert_dialog, null);
|
||||
vh = new ViewHolder(v);
|
||||
super.setView(v);
|
||||
|
||||
binding = AlertDialogBinding.inflate(LayoutInflater.from(getContext()));
|
||||
super.setView(binding.getRoot());
|
||||
binding.message.setVisibility(View.GONE);
|
||||
binding.negative.setVisibility(View.GONE);
|
||||
binding.positive.setVisibility(View.GONE);
|
||||
binding.neutral.setVisibility(View.GONE);
|
||||
binding.buttonPanel.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public CustomAlertDialog(@NonNull Context context) {
|
||||
@ -60,10 +40,6 @@ public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
super(context, themeResId);
|
||||
}
|
||||
|
||||
public ViewHolder getViewHolder() {
|
||||
return vh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomAlertDialog setView(int layoutResId) { return this; }
|
||||
|
||||
@ -72,8 +48,8 @@ public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
|
||||
@Override
|
||||
public CustomAlertDialog setMessage(@Nullable CharSequence message) {
|
||||
vh.messageView.setVisibility(View.VISIBLE);
|
||||
vh.messageView.setText(message);
|
||||
binding.message.setVisibility(View.VISIBLE);
|
||||
binding.message.setText(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -84,11 +60,11 @@ public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
|
||||
@Override
|
||||
public CustomAlertDialog setPositiveButton(CharSequence text, DialogInterface.OnClickListener listener) {
|
||||
vh.buttons.setVisibility(View.VISIBLE);
|
||||
vh.positive.setVisibility(View.VISIBLE);
|
||||
vh.positive.setText(text);
|
||||
binding.buttonPanel.setVisibility(View.VISIBLE);
|
||||
binding.positive.setVisibility(View.VISIBLE);
|
||||
binding.positive.setText(text);
|
||||
positiveListener = listener;
|
||||
vh.positive.setOnClickListener(v -> {
|
||||
binding.positive.setOnClickListener(v -> {
|
||||
if (positiveListener != null) {
|
||||
positiveListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
|
||||
}
|
||||
@ -104,11 +80,11 @@ public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
|
||||
@Override
|
||||
public CustomAlertDialog setNegativeButton(CharSequence text, DialogInterface.OnClickListener listener) {
|
||||
vh.buttons.setVisibility(View.VISIBLE);
|
||||
vh.negative.setVisibility(View.VISIBLE);
|
||||
vh.negative.setText(text);
|
||||
binding.buttonPanel.setVisibility(View.VISIBLE);
|
||||
binding.negative.setVisibility(View.VISIBLE);
|
||||
binding.negative.setText(text);
|
||||
negativeListener = listener;
|
||||
vh.negative.setOnClickListener(v -> {
|
||||
binding.negative.setOnClickListener(v -> {
|
||||
if (negativeListener != null) {
|
||||
negativeListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE);
|
||||
}
|
||||
@ -124,11 +100,11 @@ public class CustomAlertDialog extends AlertDialog.Builder {
|
||||
|
||||
@Override
|
||||
public CustomAlertDialog setNeutralButton(CharSequence text, DialogInterface.OnClickListener listener) {
|
||||
vh.buttons.setVisibility(View.VISIBLE);
|
||||
vh.neutral.setVisibility(View.VISIBLE);
|
||||
vh.neutral.setText(text);
|
||||
binding.buttonPanel.setVisibility(View.VISIBLE);
|
||||
binding.neutral.setVisibility(View.VISIBLE);
|
||||
binding.neutral.setText(text);
|
||||
neutralListener = listener;
|
||||
vh.neutral.setOnClickListener(v -> {
|
||||
binding.neutral.setOnClickListener(v -> {
|
||||
if (neutralListener != null) {
|
||||
neutralListener.onClick(dialog, DialogInterface.BUTTON_NEUTRAL);
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ public class FingerprintAuthDialog extends CustomAlertDialog {
|
||||
TypedArray ta = theme.obtainStyledAttributes(new int[] {R.attr.imageColorTint});
|
||||
fingerprint.setTint(ta.getColor(0, Color.GRAY));
|
||||
ta.recycle();
|
||||
vh.messageView.setCompoundDrawables(null, null, null, fingerprint);
|
||||
vh.messageView.setCompoundDrawablePadding(Utils.dpInPx(20));
|
||||
vh.messageView.setGravity(Gravity.CENTER);
|
||||
binding.message.setCompoundDrawables(null, null, null, fingerprint);
|
||||
binding.message.setCompoundDrawablePadding(Utils.dpInPx(20));
|
||||
binding.message.setGravity(Gravity.CENTER);
|
||||
setMessage(R.string.auth_fingerprint);
|
||||
setNegativeButton(R.string.close, (d, w) -> {
|
||||
helper.cancel();
|
||||
@ -81,20 +81,20 @@ public class FingerprintAuthDialog extends CustomAlertDialog {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, CharSequence errString) {
|
||||
vh.messageView.setTextColor(Color.RED);
|
||||
vh.messageView.setText(errString);
|
||||
binding.message.setTextColor(Color.RED);
|
||||
binding.message.setText(errString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
|
||||
vh.messageView.setTextColor(Color.RED);
|
||||
vh.messageView.setText(helpString);
|
||||
binding.message.setTextColor(Color.RED);
|
||||
binding.message.setText(helpString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
vh.messageView.setTextColor(Color.RED);
|
||||
vh.messageView.setText(R.string.auth_fail);
|
||||
binding.message.setTextColor(Color.RED);
|
||||
binding.message.setText(R.string.auth_fail);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,63 +1,65 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/dialog_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message"
|
||||
style="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="25dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="25dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<LinearLayout
|
||||
android:id="@+id/button_panel"
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:id="@+id/dialog_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:measureWithLargestChild="true"
|
||||
android:minHeight="54dp"
|
||||
android:orientation="horizontal"
|
||||
android:padding="2dp">
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="5dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/negative"
|
||||
style="@style/Widget.Button.Text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
tools:text="Negative" />
|
||||
<TextView
|
||||
android:id="@+id/message"
|
||||
style="?android:attr/textAppearanceMedium"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="25dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="25dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/neutral"
|
||||
style="@style/Widget.Button.Text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
tools:text="Neutral" />
|
||||
<LinearLayout
|
||||
android:id="@+id/button_panel"
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:measureWithLargestChild="true"
|
||||
android:minHeight="54dp"
|
||||
android:orientation="horizontal"
|
||||
android:padding="2dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/positive"
|
||||
style="@style/Widget.Button.Text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
tools:text="Positive" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/negative"
|
||||
style="@style/Widget.Button.Text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
tools:text="Negative" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/neutral"
|
||||
style="@style/Widget.Button.Text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
tools:text="Neutral" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/positive"
|
||||
style="@style/Widget.Button.Text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
tools:text="Positive" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
||||
|
@ -1,9 +1,3 @@
|
||||
# 7.1.1
|
||||
- Fix a bug that causes some modules using new format not showing up
|
||||
|
||||
# v7.1.0
|
||||
- Support the new module format
|
||||
- Support per-application component granularity MagiskHide targets (only on v19+)
|
||||
- Ask for fingerprint before deleting rules if enabled
|
||||
- Fix the bug that causes repackaging to lose settings
|
||||
- Several UI fixes
|
||||
# v7.1.2
|
||||
- Support patching Samsung AP firmware
|
||||
- Much better module downloading mechanism
|
||||
|
@ -160,7 +160,7 @@
|
||||
<string name="auto_response">Automatická odezva</string>
|
||||
<string name="request_timeout">Časový limit požadavku</string>
|
||||
<string name="superuser_notification">Oznámení Superuser</string>
|
||||
<string name="request_timeout_summary">%1$s sekund</string>
|
||||
<string name="request_timeout_summary">%1$d sekund</string>
|
||||
<string name="settings_su_reauth_title">Opětovné ověření po aktualizaci</string>
|
||||
<string name="settings_su_reauth_summary">Opětovné ověření oprávnění Superuser po aktualizaci aplikace</string>
|
||||
<string name="settings_su_fingerprint_title">Povolit ověřování otisky prstů</string>
|
||||
|
225
app/src/main/res/values-mk/strings.xml
Normal file
225
app/src/main/res/values-mk/strings.xml
Normal file
@ -0,0 +1,225 @@
|
||||
<resources>
|
||||
|
||||
<!--Welcome Activity-->
|
||||
<string name="modules">Модули</string>
|
||||
<string name="downloads">Преземања</string>
|
||||
<string name="superuser">Супер-корисник</string>
|
||||
<string name="log">Записник</string>
|
||||
<string name="settings">Поставки</string>
|
||||
<string name="install">Инсталирај</string>
|
||||
<string name="unsupport_magisk_title">Неподдржана верзија на Magisk</string>
|
||||
<string name="unsupport_magisk_message">Оваа верзија на Magisk Manager не ја поддржува верзијата на Magisk пониска од v18.0.\n\nМожно е да рачно да го надградите Magisk или да ја вратите апликацијата на постара верзија.</string>
|
||||
|
||||
<!--Status Fragment-->
|
||||
<string name="magisk_version_error">Magisk не е инсталиран.</string>
|
||||
<string name="checking_for_updates">Проверка за ажурирања…</string>
|
||||
<string name="invalid_update_channel">Невалиден канал за ажурирања</string>
|
||||
<string name="safetyNet_check_text">Притисни за проверка на SafetyNet статус</string>
|
||||
<string name="checking_safetyNet_status">Проверка на SafetyNet статус…</string>
|
||||
<string name="safetyNet_check_success">SafetyNet проверката е успешна</string>
|
||||
<string name="safetyNet_api_error">Грешка со SafetyNet API</string>
|
||||
<string name="safetyNet_res_invalid">Одговорот е невалиден.</string>
|
||||
<string name="magisk_up_to_date">Magisk е ажуриран</string>
|
||||
<string name="manager_up_to_date">Magisk Manager е ажуриран</string>
|
||||
<string name="advanced_settings_title">Напредни поставки</string>
|
||||
<string name="keep_force_encryption">Задржи ја присилната енкрипција</string>
|
||||
<string name="keep_dm_verity">Задржи AVB 2.0/dm-verity</string>
|
||||
<string name="current_installed">Инсталирано: %1$s</string>
|
||||
<string name="latest_version">Најново: %1$s</string>
|
||||
<string name="uninstall">Деинсталирај</string>
|
||||
<string name="uninstall_magisk_title">Деинсталирај го Magisk</string>
|
||||
<string name="uninstall_magisk_msg">Сите модули ќе бидат оневозможени/oтстранети. Рут привилегиите ќе бидат отстранети, а вашите податоци може да се енкриптираат ако моментално не се.</string>
|
||||
<string name="update">Ажурирај</string>
|
||||
<string name="core_only_enabled">(Овозможен е само основен режим)</string>
|
||||
|
||||
<!--Module Fragment-->
|
||||
<string name="no_info_provided">(Нема информации)</string>
|
||||
<string name="no_modules_found">Не се пронајдени модули.</string>
|
||||
<string name="update_file_created">Модулот ќе се ажурира при следното рестартирање.</string>
|
||||
<string name="remove_file_created">Модулот ќе биде отстранет при следното рестартирање.</string>
|
||||
<string name="remove_file_deleted">Модулот нема да биде отстранет при следното рестартирање.</string>
|
||||
<string name="disable_file_created">Модулот ќе биде оневозможен при следното рестартирање.</string>
|
||||
<string name="disable_file_removed">Модулот ќе биде овозможен при следното рестартирање.</string>
|
||||
<string name="author">Направено од %1$s</string>
|
||||
<string name="reboot_recovery">Рестартирај во Recovery режим</string>
|
||||
<string name="reboot_bootloader">Рестартирај во Bootloader режим</string>
|
||||
<string name="reboot_download">Рестартирај во Download режим</string>
|
||||
|
||||
<!--Repo Fragment-->
|
||||
<string name="update_available">Достапно е ажурирање</string>
|
||||
<string name="installed">Инсталирано</string>
|
||||
<string name="not_installed">Не е инсталирано</string>
|
||||
<string name="updated_on">Ажурирано на: %1$s</string>
|
||||
<string name="sorting_order">Начин на подредување</string>
|
||||
<string name="sort_by_name">Подреди по име</string>
|
||||
<string name="sort_by_update">Подреди според последното ажурирање</string>
|
||||
|
||||
<!--Log Fragment-->
|
||||
<string name="menuSaveLog">Зачувај записник</string>
|
||||
<string name="menuReload">Вчитај повторно</string>
|
||||
<string name="menuClearLog">Исчисти го записникот сега</string>
|
||||
<string name="logs_cleared">Записникот е успешно исчистен.</string>
|
||||
<string name="log_is_empty">Записникот е празен.</string>
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="app_changelog">Листа на промени</string>
|
||||
<string name="translators">davidtrpcevski</string>
|
||||
<string name="app_translators">Преведувачи</string>
|
||||
|
||||
<!-- System Components, Notifications -->
|
||||
<string name="update_channel">Magisk Ажурирања</string>
|
||||
<string name="progress_channel">Известувања за прогресот</string>
|
||||
<string name="download_complete">Преземањето е завршено</string>
|
||||
<string name="download_file_error">Грешка при преземање на фајлот</string>
|
||||
<string name="magisk_update_title">Достапно е ажурирање на Magisk!</string>
|
||||
<string name="manager_update_title">Достапно е ажурирање на Magisk Manager!</string>
|
||||
|
||||
<!-- Installation -->
|
||||
<string name="manager_download_install">Притисни за преземање и инсталирање.</string>
|
||||
<string name="download_zip_only">Преземи само Zip датотека</string>
|
||||
<string name="direct_install">Директна инсталација (Препорачано)</string>
|
||||
<string name="install_inactive_slot">Инсталирај во неактивен слот (по ОТА)</string>
|
||||
<string name="install_inactive_slot_msg">Вашиот уред ќе биде ПРИНУДЕН да се подигне на тековниот неактивен слот по рестартирањето!\nОваа опција користете ја само откако OTA ажурирање е направено.\nПродолжи?</string>
|
||||
<string name="select_method">Избери метод</string>
|
||||
<string name="setup_title">Дополнителни подесувања</string>
|
||||
<string name="select_patch_file">Избери и обнови ја датотеката</string>
|
||||
<string name="patch_file_msg">Избери само image датотека (*.img) или ODIN tar датотека (*.tar)</string>
|
||||
<string name="reboot_delay_toast">Рестартирање за 5 секунди…</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Затвори</string>
|
||||
<string name="repo_install_title">Инсталирај %1$s</string>
|
||||
<string name="repo_install_msg">Дали сакате да го инсталирате %1$s сега?</string>
|
||||
<string name="download">Преземи</string>
|
||||
<string name="reboot">Рестартирај</string>
|
||||
<string name="settings_reboot_toast">Рестартирајте за да ги примените поставките.</string>
|
||||
<string name="release_notes">Белешки за изданието</string>
|
||||
<string name="repo_cache_cleared">Кешот од репозиториумот е исчистен</string>
|
||||
<string name="internal_storage">Zip датотеката е сместена во:\n[Внатрешна меморија]%1$s</string>
|
||||
|
||||
<string name="dtbo_patched_title">DTBO е обновено!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager ја обнови dtbo.img датотеката. Ве молиме, рестартирајте.</string>
|
||||
<string name="flashing">Применувам</string>
|
||||
<string name="hide_manager_title">Сокриј го Magisk Manager…</string>
|
||||
<string name="hide_manager_fail_toast">Сокривањето на Magisk Manager е неуспешно.</string>
|
||||
<string name="open_link_failed_toast">Не е пронајдена апликација за отворање на врската.</string>
|
||||
<string name="warning">Внимание</string>
|
||||
<string name="complete_uninstall">Целосно деинсталирање</string>
|
||||
<string name="restore_img">Врати image датотеки</string>
|
||||
<string name="restore_img_msg">Враќање…</string>
|
||||
<string name="restore_done">Враќањето заврши!</string>
|
||||
<string name="restore_fail">Не постои оригинална резервна копија!</string>
|
||||
<string name="proprietary_title">Превземи патентиран код</string>
|
||||
<string name="proprietary_notice">Magisk Manager е FOSS апликација и затоа не содржи код од SafetyNet API кој е во сопственост на Google.\n\nДали ќе дозволите Magisk Manager да преземе проширување (содржи GoogleApiClient) за SafetyNet проверка?</string>
|
||||
<string name="setup_fail">Поставувањето е неуспешно.</string>
|
||||
<string name="env_fix_title">Потребни е дополнително поставување</string>
|
||||
<string name="env_fix_msg">На Вашиот уред му е потребно дополнително поставување за Magisk да работи нормално. Ќе се преземе ZIP фајлот за поставување на Magisk, дали сакате да продолжите?</string>
|
||||
<string name="setup_msg">Надградба на работната околина…</string>
|
||||
<string name="downloading_toast">Преземање %1$s</string>
|
||||
<string name="no_rw_storage">Оваа функција нема да работи без дозвола за запис на надворешната меморија.</string>
|
||||
<string name="dl_one_module">Преземај модули еден по друг.</string>
|
||||
|
||||
<!--Settings Activity -->
|
||||
<string name="settings_general_category">Општо</string>
|
||||
<string name="settings_dark_theme_title">Темна тема</string>
|
||||
<string name="settings_dark_theme_summary">Овозможи темна тема.</string>
|
||||
<string name="settings_clear_cache_title">Исчисти го кешот од репозиториумот</string>
|
||||
<string name="settings_clear_cache_summary">Исчисти ги кешираните информации за онлајн репозиториумот. Ова ја принудува апликацијата да се освежи онлајн.</string>
|
||||
<string name="settings_hide_manager_title">Сокриј го Magisk Manager</string>
|
||||
<string name="settings_hide_manager_summary">Препакувај го Magisk Manager со случајно име на пакет.</string>
|
||||
<string name="settings_restore_manager_title">Врати го Magisk Manager</string>
|
||||
<string name="settings_restore_manager_summary">Врати го Magisk Manager со оригиналното име на пакет</string>
|
||||
<string name="language">Јазик</string>
|
||||
<string name="system_default">(Стандарден системски)</string>
|
||||
<string name="settings_update">Поставки за ажурирање</string>
|
||||
<string name="settings_check_update_title">Провери за ажурирања</string>
|
||||
<string name="settings_check_update_summary">Периодично проверувај за ажурирања во позадина.</string>
|
||||
<string name="settings_update_channel_title">Канал за ажурирања</string>
|
||||
<string name="settings_update_stable">Стабилен</string>
|
||||
<string name="settings_update_beta">Бета</string>
|
||||
<string name="settings_update_custom">Прилагодено</string>
|
||||
<string name="settings_update_custom_msg">Внеси прилагоден URL линк</string>
|
||||
<string name="settings_core_only_title">Само Magisk Core основен режим</string>
|
||||
<string name="settings_core_only_summary">Овозможи ги само основните функционалности. MagiskSU и MagiskHide ќе бидет овозможени, но нема да се вчитаат модули.</string>
|
||||
<string name="settings_magiskhide_summary">Сокриј го Magisk од различни форми на откривање.</string>
|
||||
<string name="settings_hosts_title">Несистемски хостови</string>
|
||||
<string name="settings_hosts_summary">Поддршка за несистемски хостови за Adblock апликации.</string>
|
||||
<string name="settings_hosts_toast">Додаден е модул за несистемски хостови</string>
|
||||
|
||||
<string name="settings_su_app_adb">Апликации и АДБ</string>
|
||||
<string name="settings_su_app">Само апликации</string>
|
||||
<string name="settings_su_adb">Само АДБ</string>
|
||||
<string name="settings_su_disable">Оневозможено</string>
|
||||
<string name="settings_su_request_10">10 секунди</string>
|
||||
<string name="settings_su_request_15">15 секунди</string>
|
||||
<string name="settings_su_request_20">20 секунди</string>
|
||||
<string name="settings_su_request_30">30 секунди</string>
|
||||
<string name="settings_su_request_45">45 секунди</string>
|
||||
<string name="settings_su_request_60">60 секунди</string>
|
||||
<string name="superuser_access">Пристап за супер-корисник</string>
|
||||
<string name="auto_response">Автоматски одговор</string>
|
||||
<string name="request_timeout">Временско ограничување на барање</string>
|
||||
<string name="superuser_notification">Супер-корисник известување</string>
|
||||
<string name="request_timeout_summary">%1$d секунди</string>
|
||||
<string name="settings_su_reauth_title">Повторна автентикација по надградба</string>
|
||||
<string name="settings_su_reauth_summary">Повторна автентикација за супер-корисник дозвола по надградбата на апликацијата</string>
|
||||
<string name="settings_su_fingerprint_title">Овозможи автентикација на отпечатоци</string>
|
||||
<string name="settings_su_fingerprint_summary">Користете скенер за отпечатоци за да дозволите супер-корисник барања</string>
|
||||
<string name="auth_fingerprint">Автентикација на отпечатоци</string>
|
||||
|
||||
<string name="multiuser_mode">Режим на повеќе корисници</string>
|
||||
<string name="settings_owner_only">Само сопственикот на уредот</string>
|
||||
<string name="settings_owner_manage">Управувано од сопственикот на уредот</string>
|
||||
<string name="settings_user_independent">Независно од корисникот</string>
|
||||
<string name="owner_only_summary">Само сопственикот има рут пристап.</string>
|
||||
<string name="owner_manage_summary">Само сопственикот може да управува со рут пристапот и да ги прима барања за рут пристап.</string>
|
||||
<string name="user_indepenent_summary">Секој корисник има сопствени рут правила.</string>
|
||||
|
||||
<string name="mount_namespace_mode">Поставете го режимот на именски простор</string>
|
||||
<string name="settings_ns_global">Глобален именски простор</string>
|
||||
<string name="settings_ns_requester">Наследи именски простор</string>
|
||||
<string name="settings_ns_isolate">Изолиран именски простор</string>
|
||||
<string name="global_summary">Сите рут сесии го користат глобалниот именски простор.</string>
|
||||
<string name="requester_summary">Рут сесиите ќе го наследат именскиот простор на нивниот барател.</string>
|
||||
<string name="isolate_summary">Секоја рут сесија ќе има свој изолиран именски простор.</string>
|
||||
<string name="android_o_not_support">Не е поддржано на Android 8.0+.</string>
|
||||
<string name="disable_fingerprint">Нема регистрирано отпечатоци од прсти или уредот не ја поддржува оваа функција.</string>
|
||||
|
||||
<!--Superuser-->
|
||||
<string name="su_request_title">Супер-корисник барање</string>
|
||||
<string name="deny_with_str">Одбиј%1$s</string>
|
||||
<string name="deny">Одбиј</string>
|
||||
<string name="prompt">Прашај</string>
|
||||
<string name="grant">Одобри</string>
|
||||
<string name="su_warning">Дава целосен пристап на вашиот уред.\nОдбијте ако не сте сигурни!</string>
|
||||
<string name="forever">Засекогаш</string>
|
||||
<string name="once">Еднаш</string>
|
||||
<string name="tenmin">10 минути</string>
|
||||
<string name="twentymin">20 минути</string>
|
||||
<string name="thirtymin">30 минути</string>
|
||||
<string name="sixtymin">60 минути</string>
|
||||
<string name="su_allow_toast">На %1$s се доделени правата на супер-корисник</string>
|
||||
<string name="su_deny_toast">На %1$s се одбиени правата на супер-корисник</string>
|
||||
<string name="no_apps_found">Не се пронајдени апликации</string>
|
||||
<string name="su_snack_grant">Правата за супер-корисник од %1$s се одобрени</string>
|
||||
<string name="su_snack_deny">Правата за супер-корисник од %1$s се одбиени</string>
|
||||
<string name="su_snack_notif_on">Известувањата од %1$s се овозможени</string>
|
||||
<string name="su_snack_notif_off">Известувањата од %1$s се оневозможени</string>
|
||||
<string name="su_snack_log_on">Записникот на настани е овозможен за %1$s</string>
|
||||
<string name="su_snack_log_off">Записникот на настани е оневозможен %1$s</string>
|
||||
<string name="su_snack_revoke">Правата за %1$s се анулирани</string>
|
||||
<string name="su_revoke_title">Анулирај?</string>
|
||||
<string name="su_revoke_msg">Дали потврдувате анулирање на поставките за пристап на %1$s?</string>
|
||||
<string name="toast">Тост</string>
|
||||
<string name="none">Ниеден</string>
|
||||
<string name="auth_fail">Неуспешна автентикација</string>
|
||||
|
||||
<!--Superuser logs-->
|
||||
<string name="pid">PID: %1$d</string>
|
||||
<string name="target_uid">Целен UID: %1$d</string>
|
||||
<string name="command">Команда: %1$s</string>
|
||||
|
||||
<!-- MagiskHide -->
|
||||
<string name="show_system_app">Прикажи ги системските апликации</string>
|
||||
|
||||
</resources>
|
@ -63,7 +63,7 @@
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="app_changelog">Список изменений</string>
|
||||
<string name="translators">Displax [4PDA], igor-dyatlov, zertyuiop</string>
|
||||
<string name="translators" />
|
||||
<string name="app_translators">Переводчики</string>
|
||||
|
||||
<!-- System Components, Notifications -->
|
||||
@ -74,6 +74,18 @@
|
||||
<string name="magisk_update_title">Доступно обновление Magisk!</string>
|
||||
<string name="manager_update_title">Доступно обновление Magisk Manager!</string>
|
||||
|
||||
<!-- Installation -->
|
||||
<string name="manager_download_install">Нажмите, чтобы загрузить и установить.</string>
|
||||
<string name="download_zip_only">Загрузка установочного ZIP</string>
|
||||
<string name="direct_install">Прямая установка (Рекомендуется)</string>
|
||||
<string name="install_inactive_slot">Установка в неактивный слот (После OTA)</string>
|
||||
<string name="install_inactive_slot_msg">Ваше устройство будет принудительно перезагружено в неактивный слот!\nИспользуйте эту опцию только при установке OTA.\nПродолжить?</string>
|
||||
<string name="select_method">Выбор способа</string>
|
||||
<string name="setup_title">Дополнительная установка</string>
|
||||
<string name="select_patch_file">Выбрать и пропатчить файл</string>
|
||||
<string name="patch_file_msg">Выберите образ ядра (*.img) или архив ODIN (*.tar)</string>
|
||||
<string name="reboot_delay_toast">Перезагрузка через 5 секунд…</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Закрыть</string>
|
||||
<string name="repo_install_title">Установка %1$s</string>
|
||||
@ -84,19 +96,14 @@
|
||||
<string name="release_notes">О версии</string>
|
||||
<string name="repo_cache_cleared">Кэш репозитория очищен</string>
|
||||
<string name="internal_storage">Расположение архива:\n[Внутреннее Хранилище]%1$s</string>
|
||||
<string name="manager_download_install">Нажмите, чтобы загрузить и установить.</string>
|
||||
|
||||
<string name="dtbo_patched_title">DTBO пропатчен!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager пропатчил dtbo.img. Перезагрузите устройство.</string>
|
||||
<string name="flashing">Прошивка</string>
|
||||
<string name="hide_manager_title">Маскировка Magisk Manager…</string>
|
||||
<string name="hide_manager_fail_toast">Не удалось замаскировать Magisk Manager</string>
|
||||
<string name="open_link_failed_toast">Не найдено приложений для открытия ссылки.</string>
|
||||
<string name="download_zip_only">Загрузка установочного ZIP</string>
|
||||
<string name="direct_install">Прямая установка (Рекомендуется)</string>
|
||||
<string name="install_inactive_slot">Установка в неактивный слот (После OTA)</string>
|
||||
<string name="open_link_failed_toast">Не найдено приложений для открытия ссылки.</string>
|
||||
<string name="warning">Предупреждение</string>
|
||||
<string name="install_inactive_slot_msg">Ваше устройство будет принудительно перезагружено в неактивный слот!\nИспользуйте эту опцию только при установке OTA.\nПродолжить?</string>
|
||||
<string name="select_method">Выбор способа</string>
|
||||
<string name="complete_uninstall">Полное удаление</string>
|
||||
<string name="restore_img">Восстановить разделы</string>
|
||||
<string name="restore_img_msg">Восстановление…</string>
|
||||
@ -107,7 +114,6 @@
|
||||
<string name="setup_fail">Ошибка установки.</string>
|
||||
<string name="env_fix_title">Требуется дополнительная установка</string>
|
||||
<string name="env_fix_msg">Вашему устройству требуется дополнительная установка Magisk для корректной работы. Будет загружен установочный ZIP Magisk, продолжить?</string>
|
||||
<string name="setup_title">Дополнительная установка</string>
|
||||
<string name="setup_msg">Настройка рабочей среды…</string>
|
||||
<string name="downloading_toast">Загрузка %1$s</string>
|
||||
<string name="no_rw_storage">Требуется разрешение на запись во внешнее хранилище.</string>
|
||||
|
@ -63,7 +63,7 @@
|
||||
|
||||
<!--About Activity-->
|
||||
<string name="app_changelog">Uygulama değişiklikleri</string>
|
||||
<string name="translators">Mevlüt TOPÇU - Muhammet Emin TURGUT</string>
|
||||
<string name="translators">Mevlüt TOPÇU - Muhammet Emin TURGUT - XORCAN</string>
|
||||
<string name="app_translators">Çevirmenler</string>
|
||||
|
||||
<!-- System Components, Notifications -->
|
||||
@ -74,6 +74,18 @@
|
||||
<string name="magisk_update_title">Yeni Magisk Güncellemesi Mevcut!</string>
|
||||
<string name="manager_update_title">Yeni Magisk Manager Güncellemesi Mevcut!</string>
|
||||
|
||||
<!-- Installation -->
|
||||
<string name="manager_download_install">İndirmek ve yüklemek için tıklayın.</string>
|
||||
<string name="download_zip_only">Sadece Zip\'i indir</string>
|
||||
<string name="direct_install">Doğrudan kurulum (Önerilen)</string>
|
||||
<string name="install_inactive_slot">İnaktif slota yükle (OTA\'dan sonra)</string>
|
||||
<string name="install_inactive_slot_msg">Cihazınız, yeniden başlatmanın ardından inaktif slota ön yüklemek için ZORUNLU olacaktır!\nBu seçeneği yalnızca OTA yapıldıktan sonra kullanın.\nDevam?</string>
|
||||
<string name="select_method">Yöntem seçin</string>
|
||||
<string name="setup_title">Ek kurulum</string>
|
||||
<string name="select_patch_file">Dosya seçin ve yamalayın</string>
|
||||
<string name="patch_file_msg">Bir raw yansısı (*.img) ya da ODIN tarfile dosyası (*.tar) seçin</string>
|
||||
<string name="reboot_delay_toast">5 saniye içinde yeniden başlatılacak...</string>
|
||||
|
||||
<!--Toasts, Dialogs-->
|
||||
<string name="close">Kapat</string>
|
||||
<string name="repo_install_title">%1$s yükle</string>
|
||||
@ -84,19 +96,14 @@
|
||||
<string name="release_notes">Sürüm notları</string>
|
||||
<string name="repo_cache_cleared">Repo önbelleği temizlendi</string>
|
||||
<string name="internal_storage">Zip şuraya depolandı:\n[Dahili Hafıza]%1$s</string>
|
||||
<string name="manager_download_install">İndirmek ve yüklemek için dokunun</string>
|
||||
|
||||
<string name="dtbo_patched_title">DTBO yamalandı!</string>
|
||||
<string name="dtbo_patched_reboot">Magisk Manager dtbo.img\'yi yamaladı, lütfen yeniden başlatın</string>
|
||||
<string name="flashing">Yükleniyor</string>
|
||||
<string name="hide_manager_title">Magisk Manager Gizleniyor…</string>
|
||||
<string name="hide_manager_fail_toast">Magisk Manager\'ı Gizleme başarısız oldu…</string>
|
||||
<string name="open_link_failed_toast">Bağlantıyı açabilecek uygulama bulunamadı…</string>
|
||||
<string name="download_zip_only">Yalnızca Zip Dosyasını İndir</string>
|
||||
<string name="direct_install">Doğrudan Yükle (Önerilen)</string>
|
||||
<string name="install_inactive_slot">Pasif yuvaya yükle (OTA\'dan sonra)</string>
|
||||
<string name="warning">Uyarı</string>
|
||||
<string name="install_inactive_slot_msg">Cihazınız yeniden başlatıldıktan sonra mevcut pasif yuvaya ZORLA önyüklenecek!\nBu seçeneği yalnızca OTA tamamlandıktan sonra kullanın.\nDevam mı?</string>
|
||||
<string name="select_method">Yöntem Seçin</string>
|
||||
<string name="complete_uninstall">Tamamen Kaldır</string>
|
||||
<string name="restore_img">Önyükleme İmajını Geri Yükle</string>
|
||||
<string name="restore_img_msg">Geri Yükleniyor…</string>
|
||||
@ -106,8 +113,7 @@
|
||||
<string name="proprietary_notice">Magisk Yöneticisi, FOSS olduğundan Google\'ın tescilli olduğu SafetyNet API kodunu içermez.\n\nMagisk Manager\'ın SafetyNet kontrolü için bir uzantıyı (GoogleApiClient içeriyor) indirmesine izin veriyor musunuz?</string>
|
||||
<string name="setup_fail">Kurulum başarısız</string>
|
||||
<string name="env_fix_title">Ek Kurulum Gerekli</string>
|
||||
<string name="env_fix_msg">Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz?</string>
|
||||
<string name="setup_title">Ek Kurulum</string>
|
||||
<string name="env_fix_msg">Cihazınızın Magisk\'in düzgün çalışması için ek kuruluma ihtiyacı var. Bu Magisk kurulum zip dosyasını indirecektir, şimdi devam etmek istiyor musunuz?</string>
|
||||
<string name="setup_msg">Ortam kurulumu çalışıyor…</string>
|
||||
<string name="downloading_toast">%1$s indiriliyor</string>
|
||||
<string name="no_rw_storage">Bu özellik harici depolamaya yazma izni olmadan çalışmaz.</string>
|
||||
@ -127,7 +133,7 @@
|
||||
<string name="system_default">(Sistem Varsayılanı)</string>
|
||||
<string name="settings_update">Güncelleme Ayarları</string>
|
||||
<string name="settings_check_update_title">Güncellemeleri denetle</string>
|
||||
<string name="settings_check_update_summary">Düzenli aralıklarla arka planda güncellemeleri denetle</string>
|
||||
<string name="settings_check_update_summary">Düzenli aralıklarla arka planda güncellemeleri denetle</string>
|
||||
<string name="settings_update_channel_title">Güncelleme Kanalı</string>
|
||||
<string name="settings_update_stable">Kararlı</string>
|
||||
<string name="settings_update_beta">Beta</string>
|
||||
@ -188,10 +194,10 @@
|
||||
<string name="su_warning">Cihazınıza tam erişim izni verir.\nEmin değilseniz, reddedin!</string>
|
||||
<string name="forever">Daima</string>
|
||||
<string name="once">Bir kere</string>
|
||||
<string name="tenmin">10 dakika</string>
|
||||
<string name="twentymin">20 dakika</string>
|
||||
<string name="thirtymin">30 dakika</string>
|
||||
<string name="sixtymin">60 dakika</string>
|
||||
<string name="tenmin">10 dakika</string>
|
||||
<string name="twentymin">20 dakika</string>
|
||||
<string name="thirtymin">30 dakika</string>
|
||||
<string name="sixtymin">60 dakika</string>
|
||||
<string name="su_allow_toast">%1$s için yetkili kullanıcı hakları verildi</string>
|
||||
<string name="su_deny_toast">%1$s için yetkili kullanıcı hakları reddedildi</string>
|
||||
<string name="no_apps_found">Hiçbir uygulama bulunamadı</string>
|
||||
|
@ -12,11 +12,12 @@ buildscript {
|
||||
google()
|
||||
jcenter()
|
||||
maven { url 'http://storage.googleapis.com/r8-releases/raw' }
|
||||
maven { url 'https://kotlin.bintray.com/kotlinx' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools:r8:1.4.79'
|
||||
classpath 'com.android.tools:r8:1.4.93'
|
||||
classpath 'com.android.tools.build:gradle:3.5.0-alpha13'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.30"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31"
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
@ -1,10 +1,11 @@
|
||||
# Magisk Documentations
|
||||
(Updated on 2019.3.28)
|
||||
(Updated on 2019.5.1)
|
||||
|
||||
- [Installation](install.md)
|
||||
- [Prerequisite](install.md#prerequisite)
|
||||
- [Custom Recovery](install.md#custom-recovery)
|
||||
- [Boot Image Patching](install.md#boot-image-patching)
|
||||
- [Samsung (System-as-root)](install.md#samsung-system-as-root)
|
||||
- [Huawei](install.md#huawei)
|
||||
- [Tutorials](tutorials.md)
|
||||
- [OTA Installation](tutorials.md#ota-installation)
|
||||
|
119
docs/install.md
119
docs/install.md
@ -1,6 +1,8 @@
|
||||
# Installation
|
||||
If you already have Magisk installed, it is **strongly recommended to upgrade directly via Magisk Manager**.
|
||||
The following tutorial is for first time users. For Huawei users, please check the specific section for more information.
|
||||
If you already have Magisk installed, it is **strongly recommended to upgrade directly via Magisk Manager**. The following tutorial is for first time users.
|
||||
|
||||
- If you are using a Huawei device running **EMUI 8 and higher**, please check its own section.
|
||||
- If you are using a Samsung device that is **launched with Android 9.0** (new devices in 2019), please check its own section.
|
||||
|
||||
## Prerequisite
|
||||
- If you plan to install custom kernels, flash the zip **AFTER** installing Magisk
|
||||
@ -17,43 +19,102 @@ If your device have custom recovery support, the easiest way is to install it th
|
||||
## Boot Image Patching
|
||||
This is the "cool" way to install Magisk on your device. Either your device does not have proper custom recoveries, your device is using the A/B partition scheme and you don't want to mix recovery and boot images together, or you have other concerns (e.g. [OTA Installation](tutorials.md#ota-installation)), you should use this method instead.
|
||||
|
||||
In order to use this method, you are required to obtain a copy of the stock boot image, which can be found by extracting OEM provided factory images, or extracted from OTA update zips. If you are unable to obtain one yourself, someone on the Internet might share it somewhere. The following instructions will guide you through the process after you have the copy of boot image.
|
||||
In order to use this method, you are required to obtain a copy of the stock boot image, which can be found by extracting OEM provided factory images or extracting from OTA update zips. If you are unable to obtain one yourself, someone on the Internet might share it somewhere. The following instructions will guide you through the process after you have the copy of boot image.
|
||||
|
||||
- Copy the boot image to your device
|
||||
- Download and install the latest Magisk Manager
|
||||
- If you're planning to flash the patched boot image through ODIN (Samsung only), go to **Settings > Update Settings > Patched Boot Output Format**, and select *.img.tar*, or else leave it as the default (*.img*)
|
||||
- Press **Install > Install > Patch Boot Image File**, and select your stock boot image file
|
||||
- Magisk Manager will install Magisk to your boot image, and store it in
|
||||
`[Internal Storage]/Download/patched_boot.img[.tar]`
|
||||
- Copy the patched boot image from your device to your PC. If you can't find it via MTP, you can pull the file with ADB:
|
||||
`adb pull /sdcard/Download/patched_boot.img[.tar]`
|
||||
- Flash the patched boot image to your device and reboot. Here is the command if using fastboot on most devices:
|
||||
`fastboot flash boot /path/to/patched_boot.img`
|
||||
- Press **Install → Install → Select and Patch a File**, and select your stock boot image file
|
||||
- Magisk Manager will install Magisk to your boot image, and store it in `[Internal Storage]/Download/magisk_patched.img`
|
||||
- Copy the patched boot image from your device to your PC. If you can't find it via MTP, you can pull the file with ADB: <br>
|
||||
`adb pull /sdcard/Download/magisk_patched.img`
|
||||
- Flash the patched boot image to your device and reboot. Here is the command if using fastboot on most devices: <br>
|
||||
`fastboot flash boot /path/to/magisk_patched.img`
|
||||
|
||||
## Magisk in Recovery
|
||||
Due to the fact that some devices no longer uses ramdisk in boot images, Magisk has no choice but to be installed in the recovery partition. For these devices, you will have to **boot to recovery every time** if you want Magisk. Since both Magisk and recovery lives in the same partition, what you actually end up getting when you choose to boot to recovery will be determined by **how long you press volume up**.
|
||||
|
||||
Each OEM has its own key combo to boot into recovery. For example on Samsung it is **(Power + Bixby + Volume Up)**, and for Huawei it is **(Power + Volume Up)**. As soon as you press the combo and the device vibrates with a splash screen, the bootloader has already chosen which mode it is booting, either it be `boot`, `recovery`, or some OEM specific modes like `download`, `fastboot`, or `erecovery`. After the splash screen, release all buttons to boot into Magisk, since by default `recovery` mode will boot to the system with Magisk enabled. If you decide to boot to actual recovery, continue to press volume up until you see the recovery screen.
|
||||
|
||||
**In summary, after installing Magisk:**
|
||||
- **(Powering up normally) → (System with NO Magisk)**
|
||||
- **(OEM Recovery Key Combo) → (Splash screen) → (Release all buttons) → (System with Magisk)**
|
||||
- **(OEM Recovery Key Combo) → (Splash screen) → (Keep pressing volume up) → (Actual recovery)**
|
||||
|
||||
## Samsung (System-as-root)
|
||||
**If your device is NOT launched with Android 9.0 or higher (released after 2019), follow the normal tutorial**
|
||||
|
||||
### Before Installing Magisk
|
||||
- Installing Magisk **WILL** trip KNOX
|
||||
- Installing Magisk for the first time **REQUIRES** a full data wipe, backup before continue
|
||||
- You have to have your bootloader unlocked before following the instructions
|
||||
- Magisk will be installed to the **recovery** partition of your device. **Please read the Magisk in Recovery section before following the instructions below!**
|
||||
- After installing Magisk, you can directly upgrade Magisk within Magisk Manager without an issue. **Flashing in custom recovery is not supported for now.**
|
||||
|
||||
### Unlocking Bootloader
|
||||
Normally I won't provide instructions for this, but since things had changed drastically from previous Samsung devices, and there are some details that many might not know, I figure this would be helpful.
|
||||
- Allow bootloader unlocking in Developer options → OEM unlocking
|
||||
- Power off your device. Press *Bixby + Volume Down* and plug in your device to a PC to boot into download mode
|
||||
- Long press volume up to unlock the bootloader. **This will wipe your data and automatically reboot.**
|
||||
|
||||
Just when you think the bootloader is unlocked, surprise surprise, it is *actually* not! Samsung introduced `VaultKeeper` in the system, meaning the bootloader will reject any unofficial partitions before `VaultKeeper` explicitly allows it.
|
||||
|
||||
- Go through the initial setup. Skip through all the steps since data will be wiped again later when we are installing Magisk. **Connect the device to internet in the setup!**
|
||||
- Enable developer options, and **confirm that the OEM unlocking option exists and grayed out!** The `VaultKeeper` service will unleash the bootloader after it confirms that the user has the OEM unlocking option enabled. This step is to simply make sure the service gets the correct info, and also double check that our device is in a correct state
|
||||
- Your bootloader now accepts unofficial images in download mode.
|
||||
|
||||
### Instructions
|
||||
1. Download the firmware for your device.
|
||||
2. Unzip the firmware and copy the **AP** tar file to your device. It is normally named as `AP_[device_model_sw_ver].tar.md5`
|
||||
3. Install the latest Magisk Manager
|
||||
4. In Magisk Manager: **Install → Install → Select and Patch a File** and select the AP tar file.
|
||||
5. Magisk Manager will patch the whole firmware file and store the output to
|
||||
`[Internal Storage]/Download/magisk_patched.tar`
|
||||
6. Copy the tar file to your PC, and boot your device to download mode.
|
||||
7. Flash `magisk_patched.tar` as AP in ODIN <br> **Important: Uncheck "Auto Reboot" in Options!!!!**
|
||||
8. Magisk is now successfully flashed to your device! But there are still several steps before you can properly use the device.
|
||||
9. We now want to boot into the stock recovery to factory reset our device. <br>
|
||||
**Full data wipe is mandatory! Do not skip this step.** <br>
|
||||
Press *Power + Volume Down* to exit download mode. As soon as the screen turns off, immediately press *Power + Bixby + Volume Up* to boot to recovery partition. Just as mentioned in the previous section, since we want to boot into stock recovery, **continue pressing the volume up button until you see the stock recovery screen**.
|
||||
10. In the stock recovery menu, use volume buttons to navigate through menus, and the power button to select the option. Select *Wipe data/factory reset* to wipe the data of the device.
|
||||
11. This time, we can finally boot to the system with Magisk. Select *Reboot system now*, and immediately press *Power + Bixby + Volume Up*. After seeing the bootloader warning screen, release all buttons so it can boot to the system.
|
||||
12. The device will automatically reboot for the first time it boots. This is completely normal and done by design.
|
||||
13. After the device is booted up, do the usual initial setup. **The following steps will need internet connection.**
|
||||
14. You shall see Magisk Manager in your app drawer; if not, manually install the APK you downloaded in step 3 and continue to the next step. The app would be a stub and it shall automatically upgrade to the full Magisk Manager when you open it.
|
||||
15. Magisk Manager will ask to do additional setups. Let it do its job and the app will automatically reboot your device.
|
||||
16. Voila! Enjoy Magisk :)
|
||||
|
||||
### Additional Info
|
||||
- Magisk actually patches 3 partitions on your device:
|
||||
- `vbmeta`: replace with empty vbmeta image to disable partition verification
|
||||
- `boot`: remove the signature of the image to prevent soft bricks
|
||||
- `recovery`: this is where Magisk is actually installed
|
||||
- **Never, ever** try to restore either of the 3 images mentioned back to stock! You can easily brick your device by doing so, and the only way out is to do full ODIN restore following with factory reset. Just don't do it.
|
||||
- If you want to upgrade your device, **never** flash the stock **AP** tar file with reasons mentioned above. **Always** pre-patch the firmware before flashing in ODIN.
|
||||
- If you don't need to patch the full firmware, you can manually create a tar file with **at least** `vbmeta.img`, `boot.img`, and `recovery.img` to let Magisk Manager patch your images in the proper way.
|
||||
|
||||
## Huawei
|
||||
Huawei devices using Kirin processors have a different partitioning method from most common devices. Magisk is usually installed to the `boot` partition of the device, however Huawei devices does not have this partition. Depending on what EMUI version your device is running the instructions are slightly different. Even if you have switched to a custom ROM, you shall still know which version of EMUI you are running before switching.
|
||||
Huawei devices using Kirin processors have a different partitioning method from most common devices. Magisk is usually installed to the `boot` partition of the device, however Huawei devices does not have this partition. Depending on what EMUI version your device is running, the instructions will be slightly different.
|
||||
|
||||
### Obtain Stock Images
|
||||
Huawei does not release official factory images, however most firmware zips can be downloaded from the [Huawei Firmware Database](http://pro-teammt.ru/firmware-database/). To extract the images from `UPDATE.APP` in the zip, you have to use [Huawei Update Extractor](https://forum.xda-developers.com/showthread.php?t=2433454) (Windows only!)
|
||||
Huawei does not release official factory images, however most firmware zips can be downloaded from the [Huawei Firmware Database](http://pro-teammt.ru/firmware-database/). To extract images from `UPDATE.APP` in the zip, you have to use [Huawei Update Extractor](https://forum.xda-developers.com/showthread.php?t=2433454) (Windows only!)
|
||||
|
||||
### EMUI 8
|
||||
For EMUI 8 devices, your device have a partition named `ramdisk`, which will be where Magisk is going to be installed.
|
||||
For EMUI 8 devices, your device have a partition named `ramdisk`, which is where Magisk is going to be installed.
|
||||
|
||||
- If you plan to use custom recoveries, simply follow the instructions for custom recovery above.
|
||||
Note that to install TWRP, you will first download the TWRP recovery image, and use
|
||||
`fastboot flash recovery_ramdisk /path/to/twrp.img` to install the custom recovery.
|
||||
- If you plan not to use custom recoveries, you will have to extract `RAMDISK.img` from your firmware. Follow the instructions for boot image patching above, but use the `RAMDISK.img` file instead of a boot image. To install the patched image back to your device, here is the fastboot command:
|
||||
`fastboot flash ramdisk /path/to/patched_boot.img`.
|
||||
- If you plan to use custom recoveries, simply follow the instructions for custom recovery and you're all set.
|
||||
- If you plan not to use custom recoveries, you will have to extract `RAMDISK.img` from your firmware. Follow the instructions for boot image patching above, but use the `RAMDISK.img` file instead of a boot image.
|
||||
- To flash the patched image to your device, here is the fastboot command: <br>
|
||||
`fastboot flash ramdisk /path/to/magisk_patched.img` <br>
|
||||
Be aware you are flashing to `ramdisk`, not `boot`!
|
||||
|
||||
### EMUI 9
|
||||
For EMUI 9 devices, the `ramdisk` partition no longer exists. As a workaround, Magisk will be installed to the `recovery_ramdisk` partition. **This means that you HAVE TO boot to recovery every time you reboot.** To boot to recovery, press **Power + Volume Up** when booting your device.
|
||||
### EMUI 9 or Higher
|
||||
For EMUI 9+ devices, the `ramdisk` partition no longer exists. As a workaround, Magisk will be installed to the `recovery_ramdisk` partition. **Please read the Magisk in Recovery section before following the instructions below!**
|
||||
|
||||
- If you plan to use custom recoveries, simply follow the instructions for custom recovery above.
|
||||
Note that to install TWRP, you will first download the TWRP recovery image, and use
|
||||
`fastboot flash recovery_ramdisk /path/to/twrp.img` to install the custom recovery.
|
||||
**Magisk will overwrite the custom recovery.**
|
||||
- If you plan not to use custom recoveries, you will have to extract `RECOVERY_RAMDIS.img` from your firmware. Follow the instructions for boot image patching above, but use the `RECOVERY_RAMDIS.img` file instead of a boot image. To install the patched image back to your device, here is the fastboot command:
|
||||
`fastboot flash recovery_ramdisk /path/to/patched_boot.img`.
|
||||
Be aware you are flashing to `recovery_ramdisk`, not `boot` nor `ramdisk`!
|
||||
- You can still install custom recoveries to the `erecovery_ramdisk` partition. Boot to erecovery mode to boot into custom recovery in this case
|
||||
*Note: As I tested on my Honor View 10, Huawei's kernel does not seem to be able to capture key button press events in early boot, so long pressing Volume Up does **NOT** boot to recovery on my device. Your experience may vary.*
|
||||
|
||||
- If you plan to use custom recoveries, simply follow the instructions for custom recovery and you're all set. <br>
|
||||
**Warning: Magisk will overwrite the custom recovery.**
|
||||
- If you plan not to use custom recoveries, you will have to extract `RECOVERY_RAMDIS.img` from your firmware. Follow the instructions for boot image patching above, but use the `RECOVERY_RAMDIS.img` file instead of a boot image.
|
||||
- To flash the patched image to your device, here is the fastboot command: <br>
|
||||
`fastboot flash recovery_ramdisk /path/to/magisk_patched.img` <br>
|
||||
Be aware you are flashing to `recovery_ramdisk`, not `boot`!
|
||||
|
@ -609,10 +609,8 @@ void MagiskInit::setup_rootfs() {
|
||||
sprintf(path, "/sbin/%s", applet_names[i]);
|
||||
xsymlink("/sbin/magisk", path);
|
||||
}
|
||||
for (int i = 0; init_applet[i]; ++i) {
|
||||
sprintf(path, "/sbin/%s", init_applet[i]);
|
||||
xsymlink("/sbin/magiskinit", path);
|
||||
}
|
||||
xsymlink("/sbin/magiskinit", "/sbin/magiskpolicy");
|
||||
xsymlink("/sbin/magiskinit", "/sbin/supolicy");
|
||||
|
||||
close(rootdir);
|
||||
close(sbin);
|
||||
|
13
shared/src/main/res/values-mk/strings.xml
Normal file
13
shared/src/main/res/values-mk/strings.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<resources>
|
||||
<!--Not translatable-->
|
||||
<string name="app_name" translatable="false">Magisk Manager</string>
|
||||
<string name="re_app_name" translatable="false">Manager</string>
|
||||
<string name="magisk" translatable="false">Magisk</string>
|
||||
<string name="magiskhide" translatable="false">Magisk Hide</string>
|
||||
<string name="empty" translatable="false"/>
|
||||
|
||||
<!--Used in both stub and full app-->
|
||||
<string name="no_thanks">Не, благодарам</string>
|
||||
<string name="yes">Да</string>
|
||||
<string name="ok">ОК</string>
|
||||
</resources>
|
@ -1,5 +1,5 @@
|
||||
<resources>
|
||||
<string name="no_thanks">Hayır teşekkürler</string>
|
||||
<string name="no_thanks">Hayır, teşekkürler</string>
|
||||
<string name="yes">Evet</string>
|
||||
<string name="ok">Tamam</string>
|
||||
</resources>
|
||||
|
4
stub/src/main/res/values-mk/strings.xml
Normal file
4
stub/src/main/res/values-mk/strings.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<resources>
|
||||
<string name="upgrade_msg">Надградете до целосната верзија на Magisk Manager за да го завршите поставувањето. Преземете и инсталирајте?</string>
|
||||
<string name="no_internet_msg">Ве молиме поврзете се на интернет бидејќи е потребна надградба на целосната верзија на Magisk Manager.</string>
|
||||
</resources>
|
Loading…
Reference in New Issue
Block a user