Merge remote-tracking branch 'john/master' into feature/redesign

# Conflicts:
#	app/build.gradle
#	app/src/main/java/com/topjohnwu/magisk/ClassMap.kt
#	app/src/main/java/com/topjohnwu/magisk/Info.kt
#	app/src/main/java/com/topjohnwu/magisk/extensions/XAndroid.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
#	app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
#	app/src/main/java/com/topjohnwu/magisk/utils/DataBindingAdapters.kt
This commit is contained in:
Viktor De Pasquale 2019-10-29 15:53:53 +01:00
commit f11bb609c9
190 changed files with 2204 additions and 1615 deletions

4
.gitignore vendored
View File

@ -2,8 +2,8 @@ out
*.zip
*.jks
*.apk
config.prop
update.sh
/config.prop
/update.sh
# Built binaries
native/out

View File

@ -30,12 +30,12 @@ Furthermore, Magisk provides a **Systemless Interface** to alter the system (or
## Translations
Default string resources for Magisk Manager are scattered throughout
Default string resources for Magisk Manager and its stub APK are located here:
- `app/src/main/res/values/strings.xml`
- `shared/src/main/res/values/strings.xml`
- `stub/src/main/res/values/strings.xml`
Translate each and place them in the respective locations (`<module>/src/main/res/values-<lang>/strings.xml`).
Translate each and place them in the respective locations (`[module]/src/main/res/values-[lang]/strings.xml`).
## Signature Verification

View File

@ -75,7 +75,7 @@ dependencies {
implementation "${bindingAdapter}:${vBAdapt}"
implementation "${bindingAdapter}-recyclerview:${vBAdapt}"
def vMarkwon = '4.1.1'
def vMarkwon = '4.1.2'
implementation "io.noties.markwon:core:${vMarkwon}"
implementation "io.noties.markwon:html:${vMarkwon}"
implementation "io.noties.markwon:image:${vMarkwon}"
@ -112,7 +112,7 @@ dependencies {
replacedBy('com.github.topjohnwu:room-runtime')
}
}
def vRoom = "2.2.0"
def vRoom = "2.2.1"
implementation "com.github.topjohnwu:room-runtime:${vRoom}"
kapt "androidx.room:room-compiler:${vRoom}"
@ -124,9 +124,10 @@ dependencies {
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03'
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0-rc01'
implementation 'androidx.fragment:fragment-ktx:1.2.0-rc01'
implementation 'androidx.work:work-runtime:2.2.0'
implementation 'androidx.transition:transition:1.2.0'
implementation 'androidx.transition:transition:1.3.0-rc01'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'com.google.android.material:material:1.1.0-beta01'

View File

@ -32,7 +32,11 @@
-keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker
# BootSigner
-keepclassmembers class com.topjohnwu.signing.BootSigner { *; }
-keep class a.a { *; }
# Workaround R8 bug
-keep,allowobfuscation class com.topjohnwu.magisk.model.receiver.GeneralReceiver
-keepclassmembers class a.e { *; }
# Strip logging
-assumenosideeffects class timber.log.Timber.Tree { *; }

5
app/res-ids.txt Normal file
View File

@ -0,0 +1,5 @@
com.topjohnwu.magisk:color/xxxxxxxx = 0x7f010000
com.topjohnwu.magisk:drawable/xxxxxxxx = 0x7f020000
com.topjohnwu.magisk:string/xxxxxxxx = 0x7f030000
com.topjohnwu.magisk:style/xxxxxxxx = 0x7f040000
com.topjohnwu.magisk:xml/xxxxxxxx = 0x7f050000

View File

@ -78,6 +78,7 @@
<activity
android:name="a.m"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:directBootAware="true"
android:excludeFromRecents="true"
android:exported="false" />
@ -88,6 +89,7 @@
android:name="a.h"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter>
@ -110,6 +112,12 @@
android:name="com.google.android.gms.version"
android:value="12451000" />
<!-- Initialize WorkManager on-demand -->
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
</application>
</manifest>

View File

@ -1,18 +1,21 @@
package a;
import androidx.annotation.Keep;
import androidx.core.app.AppComponentFactory;
import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.signing.BootSigner;
@Keep
public class a extends AppComponentFactory {
@Deprecated
public static boolean patchAPK(String in, String out, String pkg) {
return PatchAPK.patch(in, out, pkg);
}
public static boolean patchAPK(String in, String out, String pkg, String label) {
return PatchAPK.patch(in, out, pkg, label);
}
public static void main(String[] args) throws Exception {
BootSigner.main(args);
}

View File

@ -3,5 +3,11 @@ package a;
import com.topjohnwu.magisk.App;
public class e extends App {
/* stub */
public e() {
super();
}
public e(Object o) {
super(o);
}
}

View File

@ -7,7 +7,6 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.topjohnwu.magisk.base.DelegateWorker;
import com.topjohnwu.magisk.utils.ResourceMgrKt;
import java.lang.reflect.ParameterizedType;
@ -19,7 +18,7 @@ public abstract class w<T extends DelegateWorker> extends Worker {
@SuppressWarnings("unchecked")
w(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(ResourceMgrKt.wrap(context, false), workerParams);
super(context, workerParams);
try {
base = ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0]).newInstance();

View File

@ -6,6 +6,7 @@ import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex
import androidx.room.Room
import androidx.work.WorkManager
import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkDatabase_Impl
import com.topjohnwu.magisk.data.database.RepoDatabase
@ -14,16 +15,17 @@ import com.topjohnwu.magisk.di.ActivityTracker
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.unwrap
import com.topjohnwu.magisk.utils.ResourceMgr
import com.topjohnwu.magisk.utils.RootInit
import com.topjohnwu.magisk.utils.isRunningAsStub
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
import timber.log.Timber
open class App : Application() {
open class App() : Application() {
constructor(o: Any) : this() {
Info.stub = DynAPK.load(o)
}
init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
@ -50,7 +52,6 @@ open class App : Application() {
val app: Application
val impl: Context
if (base is Application) {
isRunningAsStub = true
app = base
impl = base.baseContext
} else {
@ -67,6 +68,7 @@ open class App : Application() {
}
ResourceMgr.reload()
app.registerActivityLifecycleCallbacks(get<ActivityTracker>())
WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build())
}
// This is required as some platforms expect ContextImpl

View File

@ -1,29 +0,0 @@
package com.topjohnwu.magisk
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.model.update.UpdateCheckService
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.magisk.redesign.MainActivity as RedesignActivity
object ClassMap {
private val map = mapOf(
App::class.java to a.e::class.java,
MainActivity::class.java to a.b::class.java,
SplashActivity::class.java to a.c::class.java,
FlashActivity::class.java to a.f::class.java,
UpdateCheckService::class.java to a.g::class.java,
GeneralReceiver::class.java to a.h::class.java,
DownloadService::class.java to a.j::class.java,
SuRequestActivity::class.java to a.m::class.java,
//redesign
RedesignActivity::class.java to a.i::class.java
)
operator fun <T : Class<*>>get(c: Class<*>): T {
return map.getOrElse(c) { throw IllegalArgumentException() } as T
}
}

View File

@ -33,8 +33,9 @@ object Config : PreferenceModel, DBConfig {
const val ROOT_ACCESS = "root_access"
const val SU_MULTIUSER_MODE = "multiuser_mode"
const val SU_MNT_NS = "mnt_ns"
const val SU_MANAGER = "requester"
const val SU_FINGERPRINT = "su_fingerprint"
const val SU_MANAGER = "requester"
const val KEYSTORE = "keystore"
// prefs
const val SU_REQUEST_TIMEOUT = "su_request_timeout"
@ -100,7 +101,12 @@ object Config : PreferenceModel, DBConfig {
}
private val defaultChannel =
if (Utils.isCanary) Value.CANARY_DEBUG_CHANNEL
if (Utils.isCanary) {
if (BuildConfig.DEBUG)
Value.CANARY_DEBUG_CHANNEL
else
Value.CANARY_CHANNEL
}
else Value.DEFAULT_CHANNEL
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
@ -133,6 +139,7 @@ object Config : PreferenceModel, DBConfig {
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
var suFingerprint by dbSettings(Key.SU_FINGERPRINT, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true)
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
// Always return a path in external storage where we can write
val downloadDirectory get() =
@ -141,9 +148,6 @@ object Config : PreferenceModel, DBConfig {
fun initialize() = prefs.edit {
parsePrefs(this)
if (!prefs.contains(Key.UPDATE_CHANNEL))
putString(Key.UPDATE_CHANNEL, defaultChannel.toString())
// Get actual state
putBoolean(Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
@ -152,6 +156,9 @@ object Config : PreferenceModel, DBConfig {
putString(Key.SU_MNT_NS, suMntNamespaceMode.toString())
putString(Key.SU_MULTIUSER_MODE, suMultiuserMode.toString())
putBoolean(Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint())
}.also {
if (!prefs.contains(Key.UPDATE_CHANNEL))
prefs.edit().putString(Key.UPDATE_CHANNEL, defaultChannel.toString()).apply()
}
private fun parsePrefs(editor: SharedPreferences.Editor) = editor.apply {
@ -215,4 +222,4 @@ object Config : PreferenceModel, DBConfig {
Shell.su("cat $xml > /data/adb/${Const.MANAGER_CONFIGS}").exec()
}
}
}

View File

@ -22,8 +22,9 @@ object Const {
const val MANAGER_CONFIGS = ".tmp.magisk.config"
val USER_ID = Process.myUid() / 100000
object MagiskVersion {
object Version {
const val MIN_SUPPORT = 18000
const val CONNECT_MODE = 20002
}
object ID {

View File

@ -0,0 +1,224 @@
@file:Suppress("DEPRECATION")
package com.topjohnwu.magisk
import android.annotation.SuppressLint
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.app.job.JobWorkItem
import android.content.ComponentName
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.res.AssetManager
import android.content.res.Configuration
import android.content.res.Resources
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import com.topjohnwu.magisk.extensions.langTagToLocale
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.model.update.UpdateCheckService
import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.ui.surequest.SuRequestActivity
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.utils.defaultLocale
import java.util.*
fun AssetManager.addAssetPath(path: String) {
DynAPK.addAssetPath(this, path)
}
fun Context.wrap(global: Boolean = true): Context
= if (global) GlobalResContext(this) else ResContext(this)
fun Context.wrapJob(): Context = object : GlobalResContext(this) {
override fun getApplicationContext(): Context {
return this
}
@SuppressLint("NewApi")
override fun getSystemService(name: String): Any? {
return if (!isRunningAsStub) super.getSystemService(name) else
when (name) {
Context.JOB_SCHEDULER_SERVICE ->
JobSchedulerWrapper(super.getSystemService(name) as JobScheduler)
else -> super.getSystemService(name)
}
}
}
// Override locale and inject resources from dynamic APK
private fun Resources.patch(config: Configuration = Configuration(configuration)): Resources {
config.setLocale(currentLocale)
updateConfiguration(config, displayMetrics)
if (isRunningAsStub)
assets.addAssetPath(ResourceMgr.resApk)
return this
}
fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName {
val name = ClassMap[this].name
return ComponentName(pkg, Info.stub?.componentMap?.get(name) ?: name)
}
fun Context.intent(c: Class<*>): Intent {
val cls = ClassMap[c]
return Info.stub?.let {
val className = it.componentMap.getOrElse(cls.name) { cls.name }
Intent().setComponent(ComponentName(this, className))
} ?: Intent(this, cls)
}
fun resolveRes(idx: Int): Int {
return Info.stub?.resourceMap?.get(idx) ?: when(idx) {
DynAPK.NOTIFICATION -> R.drawable.ic_magisk_outline
DynAPK.DOWNLOAD -> R.drawable.sc_cloud_download
DynAPK.SUPERUSER -> R.drawable.sc_superuser
DynAPK.MODULES -> R.drawable.sc_extension
DynAPK.MAGISKHIDE -> R.drawable.sc_magiskhide
else -> -1
}
}
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
open val mRes: Resources get() = ResourceMgr.resource
private val loader by lazy { javaClass.classLoader!! }
override fun getResources(): Resources {
return mRes
}
override fun getClassLoader(): ClassLoader {
return loader
}
override fun createConfigurationContext(config: Configuration): Context {
return ResContext(super.createConfigurationContext(config))
}
}
private class ResContext(base: Context) : GlobalResContext(base) {
override val mRes by lazy { base.resources.patch() }
}
object ResourceMgr {
internal lateinit var resource: Resources
internal lateinit var resApk: String
fun init(context: Context) {
resource = context.resources
if (isRunningAsStub)
resApk = DynAPK.current(context).path
}
fun reload(config: Configuration = Configuration(resource.configuration)) {
val localeConfig = Config.locale
currentLocale = when {
localeConfig.isEmpty() -> defaultLocale
else -> localeConfig.langTagToLocale()
}
Locale.setDefault(currentLocale)
resource.patch(config)
}
fun getString(locale: Locale, @StringRes id: Int): String {
val config = Configuration()
config.setLocale(locale)
return Resources(resource.assets, resource.displayMetrics, config).getString(id)
}
}
@RequiresApi(api = 28)
private class JobSchedulerWrapper(private val base: JobScheduler) : JobScheduler() {
override fun schedule(job: JobInfo): Int {
return base.schedule(job.patch())
}
override fun enqueue(job: JobInfo, work: JobWorkItem): Int {
return base.enqueue(job.patch(), work)
}
override fun cancel(jobId: Int) {
base.cancel(jobId)
}
override fun cancelAll() {
base.cancelAll()
}
override fun getAllPendingJobs(): List<JobInfo> {
return base.allPendingJobs
}
override fun getPendingJob(jobId: Int): JobInfo? {
return base.getPendingJob(jobId)
}
private fun JobInfo.patch(): JobInfo {
// We need to patch the component of JobInfo to access WorkManager SystemJobService
val name = service.className
val component = ComponentName(
service.packageName,
Info.stub!!.componentMap[name] ?: name)
// Clone the JobInfo except component
val builder = JobInfo.Builder(id, component)
.setExtras(extras)
.setTransientExtras(transientExtras)
.setClipData(clipData, clipGrantFlags)
.setRequiredNetwork(requiredNetwork)
.setEstimatedNetworkBytes(estimatedNetworkDownloadBytes, estimatedNetworkUploadBytes)
.setRequiresCharging(isRequireCharging)
.setRequiresDeviceIdle(isRequireDeviceIdle)
.setRequiresBatteryNotLow(isRequireBatteryNotLow)
.setRequiresStorageNotLow(isRequireStorageNotLow)
.also {
triggerContentUris?.let { uris ->
for (uri in uris)
it.addTriggerContentUri(uri)
}
}
.setTriggerContentUpdateDelay(triggerContentUpdateDelay)
.setTriggerContentMaxDelay(triggerContentMaxDelay)
.setImportantWhileForeground(isImportantWhileForeground)
.setPrefetch(isPrefetch)
.setPersisted(isPersisted)
if (isPeriodic) {
builder.setPeriodic(intervalMillis, flexMillis)
} else {
if (minLatencyMillis > 0)
builder.setMinimumLatency(minLatencyMillis)
if (maxExecutionDelayMillis > 0)
builder.setOverrideDeadline(maxExecutionDelayMillis)
}
if (!isRequireDeviceIdle)
builder.setBackoffCriteria(initialBackoffMillis, backoffPolicy)
return builder.build()
}
}
object ClassMap {
private val map = mapOf(
App::class.java to a.e::class.java,
MainActivity::class.java to a.b::class.java,
SplashActivity::class.java to a.c::class.java,
FlashActivity::class.java to a.f::class.java,
UpdateCheckService::class.java to a.g::class.java,
GeneralReceiver::class.java to a.h::class.java,
DownloadService::class.java to a.j::class.java,
SuRequestActivity::class.java to a.m::class.java
)
operator fun get(c: Class<*>) = map.getOrElse(c) { throw IllegalArgumentException() }
}

View File

@ -1,18 +1,24 @@
package com.topjohnwu.magisk
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.UpdateInfo
import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
val isRunningAsStub get() = Info.stub != null
object Info {
@JvmStatic
var magiskVersionCode = -1
val envRef = CachedValue { loadState() }
@JvmStatic
var magiskVersionString = ""
var remote = UpdateInfo()
val env by envRef // Local
var remote = UpdateInfo() // Remote
var stub: DynAPK.Data? = null // Stub
@JvmStatic
var keepVerity = false
@ -21,11 +27,40 @@ object Info {
@JvmStatic
var recovery = false
fun loadMagiskInfo() {
runCatching {
magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0]
magiskVersionCode = ShellUtils.fastCmd("magisk -V").toInt()
Config.magiskHide = Shell.su("magiskhide --status").exec().isSuccess
val isConnected by lazy {
KObservableField(false).also { field ->
ReactiveNetwork.observeNetworkConnectivity(get())
.subscribeK {
field.value = it.available()
}
}
}
private fun loadState() = runCatching {
val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0]
val code = ShellUtils.fastCmd("magisk -V").toInt()
val hide = Shell.su("magiskhide --status").exec().isSuccess
var mode = -1
if (code >= Const.Version.CONNECT_MODE) {
mode = Shell.su("magisk --connect-mode").exec().code
if (mode == 0) {
// Manually trigger broadcast test
Shell.su("magisk --broadcast-test").exec()
}
}
Env(code, str, hide, mode)
}.getOrElse { Env() }
class Env(
val magiskVersionCode: Int = -1,
val magiskVersionString: String = "",
hide: Boolean = false,
var connectionMode: Int = -1
) {
val magiskHide get() = Config.magiskHide
init {
Config.magiskHide = hide
}
}
}

View File

@ -21,7 +21,7 @@ import com.topjohnwu.magisk.extensions.set
import com.topjohnwu.magisk.model.events.EventHandler
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.magisk.wrap
import kotlin.random.Random
typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit

View File

@ -4,7 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent
abstract class BaseReceiver : BroadcastReceiver(), KoinComponent {

View File

@ -2,7 +2,7 @@ package com.topjohnwu.magisk.base
import android.app.Service
import android.content.Context
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent
abstract class BaseService : Service(), KoinComponent {

View File

@ -1,28 +1,24 @@
package com.topjohnwu.magisk.base.viewmodel
import android.app.Activity
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.topjohnwu.magisk.extensions.doOnSubscribeUi
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.ViewActionEvent
import com.topjohnwu.magisk.utils.KObservableField
import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject
import com.topjohnwu.magisk.Info.isConnected as gIsConnected
abstract class BaseViewModel(
initialState: State = State.LOADING
) : LoadingViewModel(initialState) {
val isConnected = KObservableField(false)
init {
ReactiveNetwork.observeNetworkConnectivity(get())
.subscribeK { isConnected.value = it.available() }
.add()
val isConnected = object : KObservableField<Boolean>(gIsConnected.value, gIsConnected) {
override fun get(): Boolean {
return gIsConnected.value
}
}
fun withView(action: Activity.() -> Unit) {

View File

@ -29,7 +29,7 @@ class MagiskRepository(
else -> throw IllegalArgumentException()
}.flatMap {
// If remote version is lower than current installed, try switching to beta
if (it.magisk.versionCode < Info.magiskVersionCode
if (it.magisk.versionCode < Info.env.magiskVersionCode
&& Config.updateChannel == Config.Value.DEFAULT_CHANNEL) {
Config.updateChannel = Config.Value.BETA_CHANNEL
apiRaw.fetchBetaUpdate()
@ -74,4 +74,4 @@ class MagiskRepository(
) }
}
}
}

View File

@ -20,15 +20,18 @@ import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.FileProvider
import com.topjohnwu.magisk.utils.DynamicClassLoader
import com.topjohnwu.magisk.utils.FileProvider
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.Shell
import java.io.File
import java.io.FileNotFoundException
import java.text.SimpleDateFormat
import java.util.*
import java.lang.reflect.Array as JArray
val packageName: String get() = get<Context>().packageName
@ -99,33 +102,38 @@ fun Context.readUri(uri: Uri) =
fun Intent.startActivity(context: Context) = context.startActivity(this)
fun Intent.toCommand(args: MutableList<String>) {
if (action != null) {
fun Intent.startActivityWithRoot() {
val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString())
val cmd = toCommand(args).joinToString(" ")
Shell.su(cmd).submit()
}
fun Intent.toCommand(args: MutableList<String> = mutableListOf()): MutableList<String> {
action?.also {
args.add("-a")
args.add(action!!)
args.add(it)
}
if (component != null) {
component?.also {
args.add("-n")
args.add(component!!.flattenToString())
args.add(it.flattenToString())
}
if (data != null) {
data?.also {
args.add("-d")
args.add(dataString!!)
args.add(it.toString())
}
if (categories != null) {
for (cat in categories) {
categories?.also {
for (cat in it) {
args.add("-c")
args.add(cat)
}
}
if (type != null) {
type?.also {
args.add("-t")
args.add(type!!)
args.add(it)
}
val extras = extras
if (extras != null) {
loop@ for (key in extras.keySet()) {
val v = extras.get(key) ?: continue
extras?.also {
loop@ for (key in it.keySet()) {
val v = it[key] ?: continue
var value: Any = v
val arg: String
when {
@ -139,9 +147,8 @@ fun Intent.toCommand(args: MutableList<String>) {
arg = "--ecn"
value = v.flattenToString()
}
v is ArrayList<*> -> {
if (v.size <= 0)
/* Impossible to know the type due to type erasure */
v is List<*> -> {
if (v.isEmpty())
continue@loop
arg = if (v[0] is Int)
@ -177,11 +184,9 @@ fun Intent.toCommand(args: MutableList<String>) {
continue@loop /* Unsupported */
val sb = StringBuilder()
val len = java.lang.reflect.Array.getLength(v)
val len = JArray.getLength(v)
for (i in 0 until len) {
sb.append(
java.lang.reflect.Array.get(v, i)!!.toString().replace(",", "\\,")
)
sb.append(JArray.get(v, i)!!.toString().replace(",", "\\,"))
sb.append(',')
}
// Remove trailing comma
@ -198,6 +203,7 @@ fun Intent.toCommand(args: MutableList<String>) {
}
args.add("-f")
args.add(flags.toString())
return args
}
fun File.provide(context: Context = get()): Uri {

View File

@ -33,3 +33,5 @@ fun String.trimEmptyToNull(): String? = if (isBlank()) null else this
fun String.legalFilename() = replace(" ", "_").replace("'", "").replace("\"", "")
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
.replace("#", "").replace("@", "").replace("\\", "_")
fun String.isEmptyInternal() = isNullOrBlank()

View File

@ -7,11 +7,11 @@ import android.content.Intent
import android.os.Build
import android.webkit.MimeTypeMap
import androidx.core.app.NotificationCompat
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.chooser
import com.topjohnwu.magisk.extensions.exists
import com.topjohnwu.magisk.extensions.provide
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.entity.internal.Configuration.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
@ -63,7 +63,7 @@ open class DownloadService : RemoteFileService() {
remove(id)
when (subject.configuration) {
is APK.Upgrade -> APKInstall.install(this, subject.file)
else -> Unit
is APK.Restore -> Unit
}
}
@ -140,8 +140,7 @@ open class DownloadService : RemoteFileService() {
inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) {
val app = context.applicationContext
val builder = Builder().apply(argBuilder)
val intent = Intent(app, ClassMap[DownloadService::class.java])
.putExtra(ARG_URL, builder.subject)
val intent = app.intent(DownloadService::class.java).putExtra(ARG_URL, builder.subject)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
app.startForegroundService(intent)
@ -152,4 +151,4 @@ open class DownloadService : RemoteFileService() {
}
}
}

View File

@ -1,43 +1,47 @@
package com.topjohnwu.magisk.model.download
import android.content.ComponentName
import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.DynamicClassLoader
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.utils.PatchAPK
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell
import timber.log.Timber
import java.io.File
private fun RemoteFileService.patchPackage(apk: File, id: Int) {
if (packageName != BuildConfig.APPLICATION_ID) {
update(id) { notification ->
notification.setProgress(0, 0, true)
.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_manager_title))
.setContentText("")
}
val patched = File(apk.parent, "patched.apk")
try {
// Try using the new APK to patch itself
val loader = DynamicClassLoader(apk)
loader.loadClass("a.a")
.getMethod("patchAPK", String::class.java, String::class.java, String::class.java)
.invoke(null, apk.path, patched.path, packageName)
} catch (e: Exception) {
Timber.e(e)
// Fallback to use the current implementation
PatchAPK.patch(apk.path, patched.path, packageName)
}
private fun RemoteFileService.patch(apk: File, id: Int) {
if (packageName == BuildConfig.APPLICATION_ID)
return
update(id) { notification ->
notification.setProgress(0, 0, true)
.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_manager_title))
.setContentText("")
}
val patched = File(apk.parent, "patched.apk")
PatchAPK.patch(apk, patched, packageName, applicationInfo.nonLocalizedLabel.toString())
apk.delete()
patched.renameTo(apk)
}
private fun RemoteFileService.upgrade(apk: File, id: Int) {
if (isRunningAsStub) {
// Move to upgrade location
apk.copyTo(DynAPK.update(this), overwrite = true)
apk.delete()
patched.renameTo(apk)
if (Info.stub!!.version < Info.remote.stub.versionCode) {
// We also want to upgrade stub
service.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use {
it.writeTo(apk)
}
patch(apk, id)
} else {
// Simply relaunch the app
ProcessPhoenix.triggerRebirth(this)
}
} else {
patch(apk, id)
}
}
@ -51,15 +55,11 @@ private fun RemoteFileService.restore(apk: File, id: Int) {
Config.export()
// Make it world readable
apk.setReadable(true, false)
if (Shell.su("pm install $apk").exec().isSuccess) {
val component = ComponentName(BuildConfig.APPLICATION_ID,
ClassMap.get<Class<*>>(SplashActivity::class.java).name)
Utils.rmAndLaunch(packageName, component)
}
Shell.su("pm install $apk && pm uninstall $packageName").exec()
}
fun RemoteFileService.handleAPK(subject: DownloadSubject.Manager)
= when (subject.configuration) {
is Upgrade -> patchPackage(subject.file, subject.hashCode())
is Upgrade -> upgrade(subject.file, subject.hashCode())
is Restore -> restore(subject.file, subject.hashCode())
}

View File

@ -25,7 +25,7 @@ import java.io.InputStream
abstract class RemoteFileService : NotificationService() {
private val service: GithubRawServices by inject()
val service: GithubRawServices by inject()
override val defaultNotification: NotificationCompat.Builder
get() = Notifications.progress(this, "")
@ -134,4 +134,4 @@ abstract class RemoteFileService : NotificationService() {
}
}
}
}

View File

@ -8,7 +8,8 @@ import se.ansman.kotshi.JsonSerializable
data class UpdateInfo(
val app: ManagerJson = ManagerJson(),
val uninstaller: UninstallerJson = UninstallerJson(),
val magisk: MagiskJson = MagiskJson()
val magisk: MagiskJson = MagiskJson(),
val stub: StubJson = StubJson()
)
@JsonSerializable
@ -33,3 +34,9 @@ data class ManagerJson(
val link: String = "",
val note: String = ""
) : Parcelable
@JsonSerializable
data class StubJson(
val versionCode: Int = -1,
val link: String = ""
)

View File

@ -2,14 +2,14 @@ package com.topjohnwu.magisk.model.receiver
import android.content.ContextWrapper
import android.content.Intent
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import android.os.Build.VERSION.SDK_INT
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.base.BaseReceiver
import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.data.database.base.su
import com.topjohnwu.magisk.extensions.reboot
import com.topjohnwu.magisk.extensions.startActivity
import com.topjohnwu.magisk.extensions.startActivityWithRoot
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.entity.ManagerJson
import com.topjohnwu.magisk.model.entity.internal.Configuration
@ -20,6 +20,7 @@ import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
import org.koin.core.inject
import timber.log.Timber
open class GeneralReceiver : BaseReceiver() {
@ -38,6 +39,17 @@ open class GeneralReceiver : BaseReceiver() {
override fun onReceive(context: ContextWrapper, intent: Intent?) {
intent ?: return
// Debug messages
if (BuildConfig.DEBUG) {
Timber.d(intent.action)
intent.extras?.let { bundle ->
bundle.keySet().forEach {
Timber.d("[%s]=[%s]", it, bundle[it])
}
}
}
when (intent.action ?: return) {
Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> {
val action = intent.getStringExtra("action")
@ -51,16 +63,26 @@ open class GeneralReceiver : BaseReceiver() {
}
when (action) {
REQUEST -> {
val i = Intent(context, ClassMap[SuRequestActivity::class.java])
val i = context.intent(SuRequestActivity::class.java)
.setAction(action)
.putExtra("socket", intent.getStringExtra("socket"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
context.startActivity(i)
if (SDK_INT >= 29) {
// Android Q does not allow starting activity from background
i.startActivityWithRoot()
} else {
i.startActivity(context)
}
}
LOG -> SuLogger.handleLogs(context, intent)
NOTIFY -> SuLogger.handleNotify(context, intent)
TEST -> {
val mode = intent.getIntExtra("mode", 1 shl 1)
if (mode > Info.env.connectionMode)
Info.env.connectionMode = mode
Shell.su("magisk --connect-mode $mode").submit()
}
LOG -> SuLogger.handleLogs(intent)
NOTIFY -> SuLogger.handleNotify(intent)
TEST -> Shell.su("magisk --use-broadcast").submit()
}
}
Intent.ACTION_PACKAGE_REPLACED ->

View File

@ -20,7 +20,7 @@ class UpdateCheckService : DelegateWorker() {
magiskRepo.fetchUpdate().blockingGet()
if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode)
Notifications.managerUpdate(applicationContext)
else if (Info.magiskVersionCode < Info.remote.magisk.versionCode)
else if (Info.env.magiskVersionCode < Info.remote.magisk.versionCode)
Notifications.magiskUpdate(applicationContext)
ListenableWorker.Result.success()
}.getOrElse {

View File

@ -7,8 +7,6 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavTransactionOptions
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const.Key.OPEN_SECTION
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
@ -17,6 +15,7 @@ import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.databinding.ActivityMainBinding
import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
@ -61,7 +60,7 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
override fun onCreate(savedInstanceState: Bundle?) {
if (!SplashActivity.DONE) {
startActivity(Intent(this, ClassMap[SplashActivity::class.java]))
startActivity(intent(SplashActivity::class.java))
finish()
}
@ -155,11 +154,11 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
private fun checkHideSection() {
val menu = binding.navView.menu
menu.findItem(R.id.magiskHideFragment).isVisible =
Shell.rootAccess() && Config.magiskHide
Shell.rootAccess() && Info.env.magiskHide
menu.findItem(R.id.modulesFragment).isVisible =
Shell.rootAccess() && Info.magiskVersionCode >= 0
Shell.rootAccess() && Info.env.magiskVersionCode >= 0
menu.findItem(R.id.reposFragment).isVisible =
(viewModel.isConnected.value && Shell.rootAccess() && Info.magiskVersionCode >= 0)
(viewModel.isConnected.value && Shell.rootAccess() && Info.env.magiskVersionCode >= 0)
menu.findItem(R.id.logFragment).isVisible =
Shell.rootAccess()
menu.findItem(R.id.superuserFragment).isVisible =

View File

@ -2,14 +2,12 @@ package com.topjohnwu.magisk.ui
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AlertDialog
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
@ -24,11 +22,11 @@ open class SplashActivity : Activity() {
super.onCreate(savedInstanceState)
Shell.getShell {
if (Info.magiskVersionCode > 0 && Info.magiskVersionCode < Const.MagiskVersion.MIN_SUPPORT) {
if (Info.env.magiskVersionCode > 0 && Info.env.magiskVersionCode < Const.Version.MIN_SUPPORT) {
AlertDialog.Builder(this)
.setTitle(R.string.unsupport_magisk_title)
.setMessage(R.string.unsupport_magisk_message)
.setNegativeButton(R.string.ok, null)
.setNegativeButton(android.R.string.ok, null)
.setOnDismissListener { finish() }
.show()
} else {

View File

@ -6,12 +6,12 @@ import android.net.Uri
import android.os.Bundle
import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.databinding.ActivityFlashBinding
import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.SnackbarEvent
@ -60,7 +60,7 @@ open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>()
companion object {
private fun intent(context: Context) = Intent(context, ClassMap[FlashActivity::class.java])
private fun intent(context: Context) = context.intent(FlashActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
private fun intent(context: Context, file: File) = intent(context).setData(file.toUri())

View File

@ -87,8 +87,8 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentMagiskBinding>(),
.setTitle(R.string.proprietary_title)
.setMessage(R.string.proprietary_notice)
.setCancelable(false)
.setPositiveButton(R.string.yes) { _, _ -> download() }
.setNegativeButton(R.string.no_thanks) { _, _ -> viewModel.finishSafetyNetCheck(-2) }
.setPositiveButton(android.R.string.yes) { _, _ -> download() }
.setNegativeButton(android.R.string.no) { _, _ -> viewModel.finishSafetyNetCheck(-2) }
.show()
}

View File

@ -107,10 +107,10 @@ class HomeViewModel(
Info.recovery = it ?: return@addOnPropertyChangedCallback
}
isConnected.addOnPropertyChangedCallback {
if (it == true) refresh()
if (it == true) refresh(false)
}
refresh()
refresh(false)
}
fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish()
@ -170,7 +170,11 @@ class HomeViewModel(
}
}
fun refresh() {
@JvmOverloads
fun refresh(invalidate: Boolean = true) {
if (invalidate)
Info.envRef.invalidate()
hasRoot.value = Shell.rootAccess()
val fetchUpdate = if (isConnected.value)
@ -179,7 +183,8 @@ class HomeViewModel(
Completable.complete()
Completable.fromAction {
Info.loadMagiskInfo()
// Ensure value is ready
Info.env
}.andThen(fetchUpdate)
.applyViewModel(this)
.doOnSubscribeUi {
@ -197,33 +202,40 @@ class HomeViewModel(
private fun refreshVersions() {
magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) {
version.format(Info.magiskVersionString, Info.magiskVersionCode)
VERSION_FMT.format(Info.env.magiskVersionString, Info.env.magiskVersionCode)
} else {
""
}
managerCurrentVersion.value = version
.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
managerCurrentVersion.value = if (isRunningAsStub) MGR_VER_FMT
.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, Info.stub!!.version)
else
VERSION_FMT.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
}
private fun updateSelf() {
magiskState.value = when (Info.magiskVersionCode) {
magiskState.value = when (Info.env.magiskVersionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED
!in Info.remote.magisk.versionCode..Int.MAX_VALUE -> MagiskState.OBSOLETE
in 1 until (Info.remote.magisk.versionCode - 1) -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE
}
magiskLatestVersion.value = version
.format(Info.remote.magisk.version, Info.remote.magisk.versionCode)
magiskLatestVersion.value =
VERSION_FMT.format(Info.remote.magisk.version, Info.remote.magisk.versionCode)
_managerState.value = when (Info.remote.app.versionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel
in (BuildConfig.VERSION_CODE + 1)..Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE
in (BuildConfig.VERSION_CODE + 1) until Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> {
if (isRunningAsStub && Info.stub!!.version < Info.remote.stub.versionCode)
MagiskState.OBSOLETE
else
MagiskState.UP_TO_DATE
}
}
managerLatestVersion.value = version
.format(Info.remote.app.version, Info.remote.app.versionCode)
managerLatestVersion.value = MGR_VER_FMT
.format(Info.remote.app.version, Info.remote.app.versionCode, Info.remote.stub.versionCode)
}
private fun ensureEnv() {
@ -240,7 +252,8 @@ class HomeViewModel(
}
companion object {
private const val version = "%s (%d)"
private const val VERSION_FMT = "%s (%d)"
private const val MGR_VER_FMT = "%s (%d) (%d)"
}
}

View File

@ -8,12 +8,12 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.databinding.FragmentModulesBinding
import com.topjohnwu.magisk.extensions.reboot
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.OpenFilePickerEvent
import com.topjohnwu.magisk.model.events.ViewEvent
import com.topjohnwu.magisk.ui.flash.FlashActivity
@ -28,7 +28,7 @@ class ModulesFragment : BaseFragment<ModuleViewModel, FragmentModulesBinding>()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
// Get the URI of the selected file
val intent = Intent(activity, ClassMap[FlashActivity::class.java])
val intent = activity.intent(FlashActivity::class.java)
intent.setData(data.data).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP)
startActivity(intent)
}

View File

@ -13,20 +13,17 @@ import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat
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.base.BasePreferenceFragment
import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
import com.topjohnwu.magisk.databinding.DialogCustomNameBinding
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.toLangTag
import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.observer.Observer
import com.topjohnwu.magisk.net.Networking
import com.topjohnwu.magisk.utils.*
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
import com.topjohnwu.superuser.Shell
@ -58,6 +55,7 @@ class SettingsFragment : BasePreferenceFragment() {
findPreference<PreferenceCategory>("redesign_cat")?.isVisible = BuildConfig.DEBUG
// Get preferences
updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!!
rootConfig = findPreference(Config.Key.ROOT_ACCESS)!!
autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!!
@ -71,17 +69,68 @@ class SettingsFragment : BasePreferenceFragment() {
val magiskCategory = findPreference<PreferenceCategory>("magisk")!!
val suCategory = findPreference<PreferenceCategory>("superuser")!!
val hideManager = findPreference<Preference>("hide")!!
hideManager.setOnPreferenceClickListener {
PatchAPK.hideManager(requireContext())
true
val restoreManager = findPreference<Preference>("restore")!!
// Remove/Disable entries
// Only show canary channels if user is already on canary channel
// or the user have already chosen canary channel
if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
val restoreManager = findPreference<Preference>("restore")
restoreManager?.setOnPreferenceClickListener {
DownloadService(requireContext()) {
subject = DownloadSubject.Manager(Configuration.APK.Restore)
// Remove dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Remove re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
suCategory.removePreference(reauth)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Const.USER_ID == 0 && Info.isConnected.value && Shell.rootAccess()) {
if (activity.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
hideManager.setOnPreferenceClickListener {
showManagerNameDialog {
PatchAPK.hideManager(requireContext(), it)
}
true
}
} else {
generalCatagory.removePreference(hideManager)
restoreManager.setOnPreferenceClickListener {
DownloadService(requireContext()) {
subject = DownloadSubject.Manager(Configuration.APK.Restore)
}
true
}
}
true
} else {
// Remove if not primary user, no connection, or no root
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
findPreference<Preference>("clear")?.setOnPreferenceClickListener {
Completable.fromAction { repoDB.clear() }.subscribeK {
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT)
@ -125,58 +174,7 @@ class SettingsFragment : BasePreferenceFragment() {
setLocalePreference(findPreference(Config.Key.LOCALE)!!)
/* We only show canary channels if user is already on canary channel
* or the user have already chosen canary channel */
if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
setSummary()
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.isEnabled = false
reauth.isChecked = false
reauth.setSummary(R.string.android_o_not_support)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Shell.rootAccess() && Const.USER_ID == 0) {
if (activity.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
} else {
if (!Networking.checkNetworkStatus(requireContext())) {
generalCatagory.removePreference(restoreManager)
}
generalCatagory.removePreference(hideManager)
}
} else {
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
@ -299,8 +297,8 @@ class SettingsFragment : BasePreferenceFragment() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom)
.setView(v)
.setPositiveButton(R.string.ok) { _, _ -> onSuccess(url.text.toString()) }
.setNegativeButton(R.string.close) { _, _ -> onCancel() }
.setPositiveButton(android.R.string.ok) { _, _ -> onSuccess(url.text.toString()) }
.setNegativeButton(android.R.string.cancel) { _, _ -> onCancel() }
.setOnCancelListener { onCancel() }
.show()
}
@ -324,11 +322,35 @@ class SettingsFragment : BasePreferenceFragment() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_download_path_title)
.setView(binding.root)
.setPositiveButton(R.string.ok) { _, _ ->
.setPositiveButton(android.R.string.ok) { _, _ ->
Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) }
?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT)
}
.setNegativeButton(R.string.close, null)
.setNegativeButton(android.R.string.cancel, null)
.show()
}
}
private inline fun showManagerNameDialog(
crossinline onSuccess: (String) -> Unit
) {
val data = ManagerNameData()
val view = DialogCustomNameBinding
.inflate(LayoutInflater.from(requireContext()))
.also { it.data = data }
AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_app_name)
.setView(view.root)
.setPositiveButton(android.R.string.ok) { _, _ ->
if (view.dialogNameInput.error.isNullOrBlank()) {
onSuccess(data.name.value)
}
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}
inner class ManagerNameData {
val name = KObservableField(resources.getString(R.string.re_app_name))
}
}

View File

@ -84,8 +84,8 @@ class SuperuserViewModel(
CustomAlertDialog(this)
.setTitle(R.string.su_revoke_title)
.setMessage(getString(R.string.su_revoke_msg, item.item.appName))
.setPositiveButton(R.string.yes) { _, _ -> updateState() }
.setNegativeButton(R.string.no_thanks, null)
.setPositiveButton(android.R.string.yes) { _, _ -> updateState() }
.setNegativeButton(android.R.string.no, null)
.setCancelable(true)
.show()
}
@ -144,4 +144,4 @@ class SuperuserViewModel(
private fun deletePolicy(policy: MagiskPolicy) =
policyDB.delete(policy.uid).andThen(Single.just(policy))
}
}

View File

@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.surequest
import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.view.Window
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity
@ -31,19 +30,17 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB
super.onCreate(savedInstanceState)
val intent = intent
val action = intent.action
if (TextUtils.equals(action, GeneralReceiver.REQUEST)) {
if (!viewModel.handleRequest(intent))
finish()
return
when (intent?.action) {
GeneralReceiver.REQUEST -> {
if (!viewModel.handleRequest(intent))
finish()
return
}
GeneralReceiver.LOG -> SuLogger.handleLogs(this, intent)
GeneralReceiver.NOTIFY -> SuLogger.handleNotify(this, intent)
}
if (TextUtils.equals(action, GeneralReceiver.LOG))
SuLogger.handleLogs(intent)
else if (TextUtils.equals(action, GeneralReceiver.NOTIFY))
SuLogger.handleNotify(intent)
finish()
}

View File

@ -0,0 +1,22 @@
package com.topjohnwu.magisk.utils
class CachedValue<T>(private val factory: () -> T) : Lazy<T> {
private var _val : T? = null
override val value: T
get() {
val local = _val
return local ?: synchronized(this) {
_val ?: factory().also { _val = it }
}
}
override fun isInitialized() = _val != null
fun invalidate() {
synchronized(this) {
_val = null
}
}
}

View File

@ -31,6 +31,7 @@ import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
import com.google.android.material.textfield.TextInputLayout
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.drawableCompat
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
@ -240,6 +241,13 @@ fun setEnabled(view: View, isEnabled: Boolean) {
view.isEnabled = isEnabled
}
@BindingAdapter("error")
fun TextInputLayout.setErrorString(error: String) {
val newError = error.let { if (it.isEmpty()) null else it }
if (this.error == null && newError == null) return
this.error = newError
}
// md2
@BindingAdapter("onSelectClick", "onSelectReset", requireAll = false)

View File

@ -9,15 +9,11 @@ import java.io.Serializable
* You can define if wrapped type is Nullable or not.
* You can use kotlin get/set syntax for value
*/
class KObservableField<T> : ObservableField<T>, Serializable {
open class KObservableField<T> : ObservableField<T>, Serializable {
var value: T
set(value) {
if (field != value) {
field = value
notifyChange()
}
}
get() = get()
set(value) { set(value) }
constructor(init: T) {
value = init
@ -27,23 +23,8 @@ class KObservableField<T> : ObservableField<T>, Serializable {
value = init
}
@Deprecated(
message = "Needed for data binding, use KObservableField.value syntax from code",
replaceWith = ReplaceWith("value")
)
@Suppress("UNCHECKED_CAST")
override fun get(): T {
return value
return super.get() as T
}
@Deprecated(
message = "Needed for data binding, use KObservableField.value = ... syntax from code",
replaceWith = ReplaceWith("value = newValue")
)
override fun set(newValue: T) {
value = newValue
}
override fun toString(): String {
return "KObservableField(value=$value)"
}
}
}

View File

@ -0,0 +1,132 @@
package com.topjohnwu.magisk.utils
import android.content.pm.PackageManager
import android.util.Base64
import android.util.Base64OutputStream
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.signing.CryptoUtils.readCertificate
import com.topjohnwu.signing.CryptoUtils.readPrivateKey
import com.topjohnwu.superuser.internal.InternalUtils
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder
import org.koin.core.context.GlobalContext
import org.koin.core.context.startKoin
import timber.log.Timber
import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.security.KeyPairGenerator
import java.security.KeyStore
import java.security.MessageDigest
import java.security.PrivateKey
import java.security.cert.X509Certificate
import java.util.*
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
private interface CertKeyProvider {
val cert: X509Certificate
val key: PrivateKey
}
@Suppress("DEPRECATION")
class Keygen: CertKeyProvider {
companion object {
private const val ALIAS = "magisk"
private val PASSWORD get() = "magisk".toCharArray()
private const val TESTKEY_CERT = "61ed377e85d386a8dfee6b864bd85b0bfaa5af81"
private const val DNAME = "C=US,ST=California,L=Mountain View,O=Google Inc.,OU=Android,CN=Android"
private const val BASE64_FLAG = Base64.NO_PADDING or Base64.NO_WRAP
}
private val start = Calendar.getInstance()
private val end = Calendar.getInstance().apply { add(Calendar.YEAR, 30) }
override val cert get() = provider.cert
override val key get() = provider.key
private val provider: CertKeyProvider
inner class KeyStoreProvider : CertKeyProvider {
private val ks by lazy { init() }
override val cert by lazy { ks.getCertificate(ALIAS) as X509Certificate }
override val key by lazy { ks.getKey(ALIAS, PASSWORD) as PrivateKey }
}
class TestProvider : CertKeyProvider {
override val cert by lazy {
readCertificate(javaClass.getResourceAsStream("/keys/testkey.x509.pem"))
}
override val key by lazy {
readPrivateKey(javaClass.getResourceAsStream("/keys/testkey.pk8"))
}
}
init {
// This object could possibly be accessed from an external app
// Get context from reflection into Android's framework
val context = InternalUtils.getContext()
val pm = context.packageManager
val info = pm.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES)
val sig = info.signatures[0]
val digest = MessageDigest.getInstance("SHA1")
val chksum = digest.digest(sig.toByteArray())
val sb = StringBuilder()
for (b in chksum) {
sb.append("%02x".format(0xFF and b.toInt()))
}
provider = if (sb.toString() == TESTKEY_CERT) {
// The app was signed by the test key, continue to use it (legacy mode)
TestProvider()
} else {
KeyStoreProvider()
}
}
private fun init(): KeyStore {
GlobalContext.getOrNull() ?: {
// Invoked externally, do some basic initialization
startKoin {
modules(koinModules)
}
Timber.plant(Timber.DebugTree())
}()
val raw = Config.keyStoreRaw
val ks = KeyStore.getInstance("PKCS12")
if (raw.isEmpty()) {
ks.load(null)
} else {
GZIPInputStream(Base64.decode(raw, BASE64_FLAG).inputStream()).use {
ks.load(it, PASSWORD)
}
}
// Keys already exist
if (ks.containsAlias(ALIAS))
return ks
// Generate new private key and certificate
val kp = KeyPairGenerator.getInstance("RSA").apply { initialize(4096) }.genKeyPair()
val dname = X500Name(DNAME)
val builder = JcaX509v3CertificateBuilder(dname, BigInteger(160, Random()),
start.time, end.time, dname, kp.public)
val signer = JcaContentSignerBuilder("SHA256WithRSA").build(kp.private)
val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer))
// Store them into keystore
ks.setKeyEntry(ALIAS, kp.private, PASSWORD, arrayOf(cert))
val bytes = ByteArrayOutputStream()
GZIPOutputStream(Base64OutputStream(bytes, BASE64_FLAG)).use {
ks.store(it, PASSWORD)
}
Config.keyStoreRaw = bytes.toString("UTF-8")
return ks
}
}

View File

@ -0,0 +1,49 @@
package com.topjohnwu.magisk.utils
import android.annotation.SuppressLint
import android.content.res.Configuration
import android.content.res.Resources
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.ResourceMgr
import com.topjohnwu.magisk.extensions.langTagToLocale
import io.reactivex.Single
import java.util.*
import kotlin.Comparator
var currentLocale: Locale = Locale.getDefault()
@SuppressLint("ConstantLocale")
val defaultLocale: Locale = Locale.getDefault()
@Suppress("DEPRECATION")
val availableLocales = Single.fromCallable {
val compareId = R.string.app_changelog
mutableListOf<Locale>().apply {
// Add default locale
add(Locale.ENGLISH)
// Add some special locales
add(Locale.TAIWAN)
add(Locale("pt", "BR"))
val config = Configuration()
val metrics = ResourceMgr.resource.displayMetrics
val res = Resources(ResourceMgr.resource.assets, metrics, config)
// Other locales
val otherLocales = ResourceMgr.resource.assets.locales
.map { it.langTagToLocale() }
.distinctBy {
config.setLocale(it)
res.updateConfiguration(config, metrics)
res.getString(compareId)
}
listOf("", "").toTypedArray()
addAll(otherLocales)
}.sortedWith(Comparator { a, b ->
a.getDisplayName(a).toLowerCase(a)
.compareTo(b.getDisplayName(b).toLowerCase(b))
})
}.cache()!!

View File

@ -1,11 +1,14 @@
package com.topjohnwu.magisk.utils
import android.content.ComponentName
import android.content.Context
import android.os.Build.VERSION.SDK_INT
import android.widget.Toast
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.extensions.DynamicClassLoader
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.signing.JarMap
import com.topjohnwu.signing.SignAPK
@ -47,81 +50,86 @@ object PatchAPK {
}
private fun findAndPatch(xml: ByteArray, from: String, to: String): Boolean {
if (from.length != to.length)
if (to.length > from.length)
return false
val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer()
val offList = mutableListOf<Int>()
var i = 0
while (i < buf.length - from.length) {
var match = true
for (j in 0 until from.length) {
loop@ while (i < buf.length - from.length) {
for (j in from.indices) {
if (buf.get(i + j) != from[j]) {
match = false
break
++i
continue@loop
}
}
if (match) {
offList.add(i)
i += from.length
}
++i
offList.add(i)
i += from.length
}
if (offList.isEmpty())
return false
val toBuf = to.toCharArray().copyOf(from.length)
for (off in offList) {
buf.position(off)
buf.put(to)
buf.put(toBuf)
}
return true
}
private fun findAndPatch(xml: ByteArray, a: Int, b: Int): Boolean {
val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer()
val len = xml.size / 4
for (i in 0 until len) {
if (buf.get(i) == a) {
buf.put(i, b)
return true
private fun patchAndHide(context: Context, label: String): Boolean {
// If not running as stub, and we are compatible with stub, use stub
val src = if (!isRunningAsStub && SDK_INT >= 28 && Info.env.connectionMode == 3) {
val stub = File(context.cacheDir, "stub.apk")
val svc = get<GithubRawServices>()
runCatching {
svc.fetchFile(Info.remote.stub.link).blockingGet().byteStream().use {
it.writeTo(stub)
}
}.onFailure {
Timber.e(it)
return false
}
stub.path
} else {
context.packageCodePath
}
return false
}
private fun patchAndHide(context: Context): Boolean {
// Generate a new app with random package name
val repack = File(context.filesDir, "patched.apk")
// Generate a new random package name and signature
val repack = File(context.cacheDir, "patched.apk")
val pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length)
Config.keyStoreRaw = ""
if (!patch(context.packageCodePath, repack.path, pkg))
if (!patch(src, repack.path, pkg, label))
return false
// Install the application
repack.setReadable(true, false)
if (!Shell.su("pm install $repack").exec().isSuccess)
if (!Shell.su("force_pm_install $repack").exec().isSuccess)
return false
Config.suManager = pkg
Config.export()
Utils.rmAndLaunch(BuildConfig.APPLICATION_ID,
ComponentName(pkg, ClassMap.get<Class<*>>(SplashActivity::class.java).name))
Shell.su("pm uninstall ${BuildConfig.APPLICATION_ID}").submit()
return true
}
@JvmStatic
fun patch(apk: String, out: String, pkg: String): Boolean {
@JvmOverloads
fun patch(apk: String, out: String, pkg: String, label: String = "Manager"): Boolean {
try {
val jar = JarMap(apk)
val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
val xml = jar.getRawData(je)
if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) ||
!findAndPatch(xml, R.string.app_name, R.string.re_app_name))
!findAndPatch(xml, "Magisk Manager", label))
return false
// Write apk changes
jar.getOutputStream(je).write(xml)
SignAPK.sign(jar, FileOutputStream(out).buffered())
val keys = Keygen()
SignAPK.sign(keys.cert, keys.key, jar, FileOutputStream(out).buffered())
} catch (e: Exception) {
Timber.e(e)
return false
@ -130,11 +138,36 @@ object PatchAPK {
return true
}
fun hideManager(context: Context) {
fun patch(apk: File, out: File, pkg: String, label: String): Boolean {
try {
if (apk.length() < 1 shl 18) {
// APK is smaller than 256K, must be stub
return patch(apk.path, out.path, pkg, label)
}
// Try using the new APK to patch itself
val loader = DynamicClassLoader(apk)
val cls = loader.loadClass("a.a")
for (m in cls.declaredMethods) {
val pars = m.parameterTypes
if (pars.size == 4 && pars[0] == String::class.java) {
return m.invoke(null, apk.path, out.path, pkg, label) as Boolean
}
}
throw Exception("No matching method found")
} catch (e: Exception) {
Timber.e(e)
// Fallback to use the current implementation
return patch(apk.path, out.path, pkg, label)
}
}
fun hideManager(context: Context, label: String) {
Completable.fromAction {
val progress = Notifications.progress(context, context.getString(R.string.hide_manager_title))
Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build())
if (!patchAndHide(context))
if (!patchAndHide(context, label))
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG)
Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID)
}.subscribeK()

View File

@ -1,126 +0,0 @@
@file:Suppress("DEPRECATION")
package com.topjohnwu.magisk.utils
import android.annotation.SuppressLint
import android.content.Context
import android.content.ContextWrapper
import android.content.res.AssetManager
import android.content.res.Configuration
import android.content.res.Resources
import androidx.annotation.StringRes
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.langTagToLocale
import io.reactivex.Single
import java.util.*
var isRunningAsStub = false
var currentLocale: Locale = Locale.getDefault()
private set
@SuppressLint("ConstantLocale")
val defaultLocale: Locale = Locale.getDefault()
val availableLocales = Single.fromCallable {
val compareId = R.string.app_changelog
mutableListOf<Locale>().apply {
// Add default locale
add(Locale.ENGLISH)
// Add some special locales
add(Locale.TAIWAN)
add(Locale("pt", "BR"))
val config = Configuration()
val metrics = ResourceMgr.resource.displayMetrics
val res = Resources(ResourceMgr.resource.assets, metrics, config)
// Other locales
val otherLocales = ResourceMgr.resource.assets.locales
.map { it.langTagToLocale() }
.distinctBy {
config.setLocale(it)
res.updateConfiguration(config, metrics)
res.getString(compareId)
}
listOf("", "").toTypedArray()
addAll(otherLocales)
}.sortedWith(Comparator { a, b ->
a.getDisplayName(a).toLowerCase(a)
.compareTo(b.getDisplayName(b).toLowerCase(b))
})
}.cache()!!
private val addAssetPath by lazy {
AssetManager::class.java.getMethod("addAssetPath", String::class.java)
}
fun AssetManager.addAssetPath(path: String) {
addAssetPath.invoke(this, path)
}
fun Context.wrap(global: Boolean = true): Context
= if (!global) ResourceMgr.ResContext(this) else ResourceMgr.GlobalResContext(this)
object ResourceMgr {
lateinit var resource: Resources
private lateinit var resApk: String
fun init(context: Context) {
resource = context.resources
if (isRunningAsStub)
resApk = DynAPK.current(context).path
}
// Override locale and inject resources from dynamic APK
private fun Resources.patch(config: Configuration = Configuration(configuration)): Resources {
config.setLocale(currentLocale)
updateConfiguration(config, displayMetrics)
if (isRunningAsStub)
assets.addAssetPath(resApk)
return this
}
fun reload(config: Configuration = Configuration(resource.configuration)) {
val localeConfig = Config.locale
currentLocale = when {
localeConfig.isEmpty() -> defaultLocale
else -> localeConfig.langTagToLocale()
}
Locale.setDefault(currentLocale)
resource.patch(config)
}
fun getString(locale: Locale, @StringRes id: Int): String {
val config = Configuration()
config.setLocale(locale)
return Resources(resource.assets, resource.displayMetrics, config).getString(id)
}
open class GlobalResContext(base: Context) : ContextWrapper(base) {
open val mRes: Resources get() = resource
private val loader by lazy { javaClass.classLoader!! }
override fun getResources(): Resources {
return mRes
}
override fun getClassLoader(): ClassLoader {
return loader
}
override fun createConfigurationContext(config: Configuration): Context {
return ResContext(super.createConfigurationContext(config))
}
}
class ResContext(base: Context) : GlobalResContext(base) {
override val mRes by lazy { base.resources.patch() }
}
}

View File

@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.rawResource
import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
@ -16,12 +17,14 @@ class RootInit : Shell.Initializer() {
}
fun init(context: Context, shell: Shell): Boolean {
// Invalidate env state if shell is recreated
Info.envRef.invalidate()
val job = shell.newJob()
if (shell.isRoot) {
job.add(context.rawResource(R.raw.util_functions))
.add(context.rawResource(R.raw.utils))
.add(context.rawResource(R.raw.utils))
Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk")
Info.loadMagiskInfo()
} else {
job.add(context.rawResource(R.raw.nonroot_utils))
}
@ -35,6 +38,7 @@ class RootInit : Shell.Initializer() {
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
return true
}
}

View File

@ -2,14 +2,13 @@ package com.topjohnwu.magisk.utils
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Process
import android.widget.Toast
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.data.repository.LogRepository
import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.model.entity.MagiskPolicy
import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.model.entity.toPolicy
@ -17,15 +16,13 @@ import java.util.*
object SuLogger {
private val context: Context by inject()
fun handleLogs(intent: Intent) {
fun handleLogs(context: Context, intent: Intent) {
val fromUid = intent.getIntExtra("from.uid", -1)
if (fromUid < 0) return
if (fromUid == Process.myUid()) return
val pm: PackageManager by inject()
val pm = context.packageManager
val notify: Boolean
val data = intent.extras
@ -36,7 +33,7 @@ object SuLogger {
}.getOrElse { return }
} else {
// Doesn't report whether notify or not, check database ourselves
val policyDB: PolicyDao by inject()
val policyDB = get<PolicyDao>()
val policy = policyDB.fetch(fromUid).blockingGet() ?: return
notify = policy.notification
policy
@ -46,7 +43,7 @@ object SuLogger {
return
if (notify)
handleNotify(policy)
handleNotify(context, policy)
val toUid = intent.getIntExtra("to.uid", -1)
if (toUid < 0) return
@ -62,11 +59,11 @@ object SuLogger {
date = Date()
)
val logRepo: LogRepository by inject()
val logRepo = get<LogRepository>()
logRepo.put(log).blockingGet()?.printStackTrace()
}
private fun handleNotify(policy: MagiskPolicy) {
private fun handleNotify(context: Context, policy: MagiskPolicy) {
if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) {
Utils.toast(
context.getString(
@ -80,16 +77,16 @@ object SuLogger {
}
}
fun handleNotify(intent: Intent) {
fun handleNotify(context: Context, intent: Intent) {
val fromUid = intent.getIntExtra("from.uid", -1)
if (fromUid < 0) return
if (fromUid == Process.myUid()) return
runCatching {
val packageManager: PackageManager by inject()
val policy = fromUid.toPolicy(packageManager)
val pm = context.packageManager
val policy = fromUid.toPolicy(pm)
.copy(policy = intent.getIntExtra("policy", -1))
if (policy.policy >= 0)
handleNotify(policy)
handleNotify(context, policy)
}
}
}

View File

@ -1,6 +1,5 @@
package com.topjohnwu.magisk.utils
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources
@ -46,7 +45,7 @@ object Utils {
.setRequiresDeviceIdle(true)
.build()
val request = PeriodicWorkRequest
.Builder(ClassMap[UpdateCheckService::class.java], 12, TimeUnit.HOURS)
.Builder(ClassMap[UpdateCheckService::class.java] as Class<Worker>, 12, TimeUnit.HOURS)
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
@ -73,8 +72,4 @@ object Utils {
if ((exists() && isDirectory) || mkdirs()) this else null
}
fun rmAndLaunch(rm: String, component: ComponentName) {
Shell.su("(rm_launch $rm ${component.flattenToString()})").exec()
}
}

View File

@ -48,7 +48,7 @@ object MarkDownWindow : KoinComponent {
AlertDialog.Builder(activity)
.setTitle(title)
.setView(mv)
.setNegativeButton(R.string.close) { dialog, _ -> dialog.dismiss() }
.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() }
.show()
}
}

View File

@ -4,15 +4,11 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.app.TaskStackBuilder
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.ui.SplashActivity
@ -20,6 +16,7 @@ import com.topjohnwu.magisk.ui.SplashActivity
object Notifications {
val mgr by lazy { NotificationManagerCompat.from(get()) }
private val icon by lazy { resolveRes(DynAPK.NOTIFICATION) }
fun setup(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -34,16 +31,16 @@ object Notifications {
}
fun magiskUpdate(context: Context) {
val intent = Intent(context, ClassMap[SplashActivity::class.java])
intent.putExtra(Const.Key.OPEN_SECTION, "magisk")
val intent = context.intent(SplashActivity::class.java)
.putExtra(Const.Key.OPEN_SECTION, "magisk")
val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(ClassMap.get<Class<*>>(SplashActivity::class.java))
stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName))
stackBuilder.addNextIntent(intent)
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
builder.setSmallIcon(R.drawable.ic_magisk_outline)
builder.setSmallIcon(icon)
.setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setVibrate(longArrayOf(0, 100, 100, 100))
@ -54,15 +51,15 @@ object Notifications {
}
fun managerUpdate(context: Context) {
val intent = Intent(context, ClassMap[GeneralReceiver::class.java])
intent.action = Const.Key.BROADCAST_MANAGER_UPDATE
intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
val intent = context.intent(GeneralReceiver::class.java)
.setAction(Const.Key.BROADCAST_MANAGER_UPDATE)
.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
builder.setSmallIcon(R.drawable.ic_magisk_outline)
builder.setSmallIcon(icon)
.setContentTitle(context.getString(R.string.manager_update_title))
.setContentText(context.getString(R.string.manager_download_install))
.setVibrate(longArrayOf(0, 100, 100, 100))
@ -73,13 +70,13 @@ object Notifications {
}
fun dtboPatched(context: Context) {
val intent = Intent(context, ClassMap[GeneralReceiver::class.java])
val intent = context.intent(GeneralReceiver::class.java)
.setAction(Const.Key.BROADCAST_REBOOT)
val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
builder.setSmallIcon(R.drawable.ic_magisk_outline)
builder.setSmallIcon(icon)
.setContentTitle(context.getString(R.string.dtbo_patched_title))
.setContentText(context.getString(R.string.dtbo_patched_reboot))
.setVibrate(longArrayOf(0, 100, 100, 100))

View File

@ -15,55 +15,56 @@ import com.topjohnwu.superuser.Shell
object Shortcuts {
fun setup(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
if (Build.VERSION.SDK_INT >= 25) {
val manager = context.getSystemService(ShortcutManager::class.java)
manager?.dynamicShortcuts = getShortCuts(context)
}
}
@RequiresApi(api = Build.VERSION_CODES.N_MR1)
@RequiresApi(api = 25)
private fun getShortCuts(context: Context): List<ShortcutInfo> {
val shortCuts = mutableListOf<ShortcutInfo>()
val root = Shell.rootAccess()
val intent = context.intent(SplashActivity::class.java)
if (Utils.showSuperUser()) {
shortCuts.add(ShortcutInfo.Builder(context, "superuser")
.setShortLabel(context.getString(R.string.superuser))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "superuser")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_superuser))
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.SUPERUSER)))
.setRank(0)
.build())
}
if (root && Config.magiskHide) {
if (root && Info.env.magiskHide) {
shortCuts.add(ShortcutInfo.Builder(context, "magiskhide")
.setShortLabel(context.getString(R.string.magiskhide))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "magiskhide")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_magiskhide))
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MAGISKHIDE)))
.setRank(1)
.build())
}
if (!Config.coreOnly && root && Info.magiskVersionCode >= 0) {
if (!Config.coreOnly && root && Info.env.magiskVersionCode >= 0) {
shortCuts.add(ShortcutInfo.Builder(context, "modules")
.setShortLabel(context.getString(R.string.modules))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "modules")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_extension))
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MODULES)))
.setRank(3)
.build())
shortCuts.add(ShortcutInfo.Builder(context, "downloads")
.setShortLabel(context.getString(R.string.downloads))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java])
.setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "downloads")
.setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_cloud_download))
.setIcon(Icon.createWithResource(context, resolveRes(DynAPK.DOWNLOAD)))
.setRank(2)
.build())
}

View File

@ -23,7 +23,7 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) {
setTitle(R.string.env_fix_title)
setMessage(R.string.env_fix_msg)
setCancelable(true)
setPositiveButton(R.string.yes) { _, _ ->
setPositiveButton(android.R.string.yes) { _, _ ->
val pd = ProgressDialog.show(activity,
activity.getString(R.string.setup_title),
activity.getString(R.string.setup_msg))
@ -46,6 +46,6 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) {
}
}.exec()
}
setNegativeButton(R.string.no_thanks, null)
setNegativeButton(android.R.string.no, null)
}
}

View File

@ -31,7 +31,7 @@ class FingerprintAuthDialog(activity: Activity, private val callback: () -> Unit
binding.message.compoundDrawablePadding = Utils.dpInPx(20)
binding.message.gravity = Gravity.CENTER
setMessage(R.string.auth_fingerprint)
setNegativeButton(R.string.close) { _, _ ->
setNegativeButton(android.R.string.cancel) { _, _ ->
helper?.cancel()
failureCallback?.invoke()
}

View File

@ -62,12 +62,12 @@ internal class InstallMethodDialog(activity: BaseActivity<*, *>, options: List<S
.setTitle(R.string.warning)
.setMessage(R.string.install_inactive_slot_msg)
.setCancelable(true)
.setPositiveButton(R.string.yes) { _, _ ->
.setPositiveButton(android.R.string.yes) { _, _ ->
DownloadService(activity) {
subject = DownloadSubject.Magisk(Configuration.Flash.Secondary)
}
}
.setNegativeButton(R.string.no_thanks, null)
.setNegativeButton(android.R.string.no, null)
.show()
}
}

View File

@ -32,7 +32,7 @@
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:id="@+id/main_nav_host"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.topjohnwu.magisk.extensions.XStringKt" />
<variable
name="data"
type="com.topjohnwu.magisk.ui.settings.SettingsFragment.ManagerNameData" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingStart="@dimen/margin_generic"
android:paddingTop="@dimen/margin_generic"
android:paddingEnd="@dimen/margin_generic">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/dialog_name_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_app_name_hint"
app:counterEnabled="true"
app:counterMaxLength="14"
app:counterOverflowTextColor="@color/colorError"
app:error="@{data.name.length() > 14 || data.name.empty || XStringKt.isEmptyInternal(data.name) ? @string/settings_app_name_error : @string/empty}"
app:errorEnabled="true"
app:helperText="@string/settings_app_name_helper">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={data.name}"
tools:text="@string/re_app_name" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</layout>

View File

@ -110,8 +110,12 @@ EOF
cd /
}
rm_launch() {
pm uninstall $1
am start -n $2
exit
force_pm_install() {
local APK=$1
local VERIFY=`settings get global package_verifier_enable`
[ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 0
pm install -r $APK
local res=$?
[ "$VERIFY" -eq 1 ] && settings put global package_verifier_enable 1
return $res
}

View File

@ -89,7 +89,6 @@
<string name="reboot_delay_toast">إعادة التشغيل خلال خمس ثواني…</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>
@ -184,7 +183,6 @@
<string name="global_summary">تستخدم كافة جلسات العمل للروت مساحة الاسم ذات التركيب العامة</string>
<string name="requester_summary">سترث جلسات العمل للروت مساحة الأسماء لطالبيها</string>
<string name="isolate_summary">سيكون لكل جلسة عمل للروت مساحة اسم معزولة خاصة بها </string>
<string name="android_o_not_support">لا يدعم إصدار الأندرويد +8.0</string>
<string name="disable_fingerprint">لم تُعين بصمات الأصابع أو لا يوجد قارئ بصمات</string>
<string name="settings_download_path_error">خطأ عند إنشاء مجلد. عليه أن يكون سهلا الوصول إليه من خلال مجلد التخزين للروت و ألا يكون ملفا.</string>

View File

@ -1,122 +1,70 @@
<resources>
<!--Welcome Activity-->
<string name="modules">Əlavələr</string>
<string name="downloads">Endirmələr</string>
<string name="superuser">Superuser</string>
<string name="log">Log</string>
<string name="settings">Tənzimləmələr</string>
<string name="install">Quraşdır</string>
<string name="unsupport_magisk_title">Dəstəklənməyən Magisk Versiyası</string>
<string name="unsupport_magisk_message">Magisk Manager\'in bu versiyası Magisk\'in v18.0 versiyasndan aşağısını dəstəkləmir.\n\nMagisk\'i əllə yüksəldə, yaxud tətbiqi əvvəlki versiyalarına qaytara bilərsiniz.</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk yüklənməyib.</string>
<string name="checking_for_updates">Yeniləmələr yoxlanılır…</string>
<string name="invalid_update_channel">Etibarsız Yeniləmə Kanalı</string>
<string name="safetyNet_check_text">SafetyNet vəziyətinə bax</string>
<string name="checking_safetyNet_status">SafetyNet vəziyəti yoxlanılır…</string>
<string name="safetyNet_check_success">SafetyNet Uğurla Yoxlanıldı</string>
<string name="safetyNet_api_error">SafetyNet API Xətası</string>
<string name="safetyNet_res_invalid">Cavab etibarsızdır.</string>
<string name="magisk_up_to_date">Magisk ən yenidir</string>
<string name="manager_up_to_date">Magisk Manager ən yenidir</string>
<string name="advanced_settings_title">Qabaqcıl Parametrlər</string>
<string name="keep_force_encryption">Şifrələməyə məcbur etməni qoru</string>
<string name="keep_dm_verity">AVB 2.0/dm-verity\'i qoru</string>
<string name="current_installed">Yüklənən: %1$s</string>
<string name="latest_version">Ən son: %1$s</string>
<string name="uninstall">Sil</string>
<string name="uninstall_magisk_title">Magisk\'i Sil</string>
<string name="uninstall_magisk_msg">Bütün əlavələr ləğv olunacaq/silinəcək. Root silinəcək, və əgər hal-hazırda deyilsə, bütün məlumatlarınız potensiyal olaraq şifrələnəcək.</string>
<string name="update">Yenilə</string>
<string name="core_only_enabled">(Yalnız nüvə modu qoşulub)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Məlumat təmin edilməyib)</string>
<string name="no_modules_found">Əlavələr yoxdur.</string>
<string name="update_file_created">Əlavə sonrakı yenidən başlatmada yenilənəcək.</string>
<string name="remove_file_created">Əlavə sonrakı yenidən başlatmada silinəcək.</string>
<string name="remove_file_deleted">Əlavə sonrakı yenidən başlatmada silinməyəcək.</string>
<string name="disable_file_created">Əlavə sonrakı yenidən başlatmada qapadılacaq.</string>
<string name="disable_file_removed">Əlavə sonrakı yenidən başlatmada açılacaq.</string>
<string name="author">%1$s tərəfindən yaradılıb</string>
<string name="reboot_recovery">Bərpa rejimində yenidən başlat</string>
<string name="reboot_bootloader">Bootloader\'ə yenidən başlat</string>
<string name="reboot_download">Yükləmə rejimində yenidən başlat</string>
<string name="reboot_edl">EDL\'ə yenidən başlat</string>
<!--Repo Fragment-->
<string name="update_available">Yeniləmə Var</string>
<string name="installed">Yüklənib</string>
<string name="not_installed">Yüklənməyib</string>
<string name="updated_on">Yeniləmə vaxtı: %1$s</string>
<string name="sorting_order">Nizamlama Qaydası</string>
<string name="sort_by_name">Ada görə nizamla</string>
<string name="sort_by_update">Son yeniləməyə görə nizamla</string>
<!--Log Fragment-->
<string name="menuSaveLog">Log\'u saxla</string>
<string name="menuReload">Təzələ</string>
<string name="menuClearLog">Log\'u indi təmizlə</string>
<string name="logs_cleared">Log uğurla təmizləndi.</string>
<!--About Activity-->
<string name="app_changelog">Yeniliklər</string>
<!-- System Components, Notifications -->
<string name="update_channel">Magisk Yeniləmələri</string>
<string name="progress_channel">Nəticə Bildirişləri</string>
<string name="download_complete">Yükləmə bitdi</string>
@ -127,262 +75,135 @@
<string name="manager_update_title">Magisk Manager Yeniləməsi Var!</string>
<!--Toasts, Dialogs-->
<string name="close">Qapat</string>
<string name="repo_install_title">%1$s faylını yüklə</string>
<string name="repo_install_msg">%1$s faylını indi yükləmək istəyirsiniz?</string>
<string name="download">Yüklə</string>
<string name="reboot">Yenidən Başlat</string>
<string name="settings_reboot_toast">Tənzimləmələri saxlamaq üçün yenidən başladın.</string>
<string name="release_notes">Yeniliklər</string>
<string name="repo_cache_cleared">Repo keşi silindi</string>
<string name="manager_download_install">Yükləyib quraşdırmaq üçün toxun.</string>
<string name="dtbo_patched_title">DTBO yamaqlanıb!</string>
<string name="dtbo_patched_reboot">Magisk Manager dtbo.img\'ni yamaqladı. Xahiş olunur yenidən başladın.</string>
<string name="flashing">Qurulur</string>
<string name="hide_manager_title">Magisk Manager gizlədilir…</string>
<string name="hide_manager_fail_toast">Magisk Manager\'i gizlətmək alınmadı.</string>
<string name="open_link_failed_toast">Keçid açmağa heçbir tətbiq tapılmadı.</string>
<string name="download_zip_only">Yalnız Zip yüklə</string>
<string name="direct_install">Birdəfəlik Yüklə (Tövsiyə olunur)</string>
<string name="select_patch_file">Fayl Seç və Yamaqla</string>
<string name="install_inactive_slot">Fəal olmayan slota quraşdır (OTA\'dan sonra)</string>
<string name="warning">Xəbərdarlıq</string>
<string name="install_inactive_slot_msg">Cihazınız yenidən başladıldıqdan sonra fəal olmayan slota başlamağa MƏCBUR ediləcək!\nBu seçimi yalnız OTA bitdikdən sonra istifadə edin.\nDavam edirsiniz?</string>
<string name="select_method">Üsul Seçin</string>
<string name="complete_uninstall">Silməni Bitir</string>
<string name="restore_img">Surətləri Qaytar</string>
<string name="restore_img_msg">Geri qaytarılır…</string>
<string name="restore_done">Geri qaytarma bitdi!</string>
<string name="restore_fail">Stock nüsxə mövcud deyil!</string>
<string name="proprietary_title">Özəl kodu yükləyin</string>
<string name="proprietary_notice">Magisk Manager açıq lisenziyalıdır və Google\'ın özəl SafetyNet API kodunu ehtiva etmir.\n\Magisk Managerə SafetyNet yoxlamaları üçün tərkibində GoogleApiClient olan əlavəni yükləməyə icazə verirsiniz?</string>
<string name="setup_fail">Quraşdırma alınmadı.</string>
<string name="env_fix_title">Əlavə Quraşdırma Lazımdır</string>
<string name="env_fix_msg">Cihazınızın Magisk\'in düzgün işləməsi üçün əlavə quraşdırmaya ehtiyacı var . Bu Magisk zip faylını endirəcək, davam etmək istəyirsiniz?</string>
<string name="setup_title">Əlavə quraşdırma</string>
<string name="setup_msg">Quraşdırma yerinə yetirilir…</string>
<!--Settings Activity -->
<string name="settings_general_category">Ümumi</string>
<string name="settings_dark_theme_title">Qaranlıq Mövzu</string>
<string name="settings_dark_theme_summary">Qaranlıq mövzunu aç.</string>
<string name="settings_clear_cache_title">Repo Keşini Təmizlə</string>
<string name="settings_clear_cache_summary">Onlayn repolar üçün keşlənmiş məlumatı silin. Bu tətbiqi onlayn şəkildə yenilənməyə məcbur edir.</string>
<string name="settings_hide_manager_title">Magisk Manager\'i Gizlə</string>
<string name="settings_hide_manager_summary">Magisk Manager\'i təsadüfi adla yenidən sıxışdır.</string>
<string name="settings_restore_manager_title">Magisk Manager\'i Geri Qaytar</string>
<string name="settings_restore_manager_summary">Magisk Manager\'i orjinal sıxışdırma ilə geri qaytar</string>
<string name="language">Dil</string>
<string name="system_default">(Sistem Dili)</string>
<string name="settings_update">Tənzimləmələri Yenilə</string>
<string name="settings_check_update_title">Yeniləmələri Yoxla</string>
<string name="settings_check_update_summary">Axraplanda vaxtaşırı yeniləmələri yoxla.</string>
<string name="settings_update_channel_title">Kanalı Yenilə</string>
<string name="settings_update_stable">Stabil</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Özəl</string>
<string name="settings_update_custom_msg">Özəl URL daxil edin</string>
<string name="settings_core_only_title">Magisk Yalnız Nüvə Modu</string>
<string name="settings_core_only_summary">Yalnız nüvə xüsusiyyətlərini aç. MagiskSU və MagiskHide hələ də açıq qalacaq, amma əlavələr yüklənməyəcək.</string>
<string name="settings_magiskhide_summary">Magisk\'i fərqli növdə aşkarlamalardan gizləyin.</string>
<string name="settings_hosts_title">Sistemsiz host\'lar</string>
<string name="settings_hosts_summary">Adblock tətbiqləri üçün Sistemsiz host dəstəyi.</string>
<string name="settings_hosts_toast">Sistemsiz host əlavəsi quraşdırıldı</string>
<string name="settings_su_app_adb">Tətbiqlər və ADB</string>
<string name="settings_su_app">Yalnız Tətbiqlər</string>
<string name="settings_su_adb">Yalnız ADB</string>
<string name="settings_su_disable">Qapalı</string>
<string name="settings_su_request_10">10 saniyə</string>
<string name="settings_su_request_15">15 saniyə</string>
<string name="settings_su_request_20">20 saniyə</string>
<string name="settings_su_request_30">30 saniyə</string>
<string name="settings_su_request_45">45 saniyə</string>
<string name="settings_su_request_60">60 saniyə</string>
<string name="superuser_access">Superuser İcazəsi</string>
<string name="auto_response">Avtomatik Cavab</string>
<string name="request_timeout">İcazə Vaxtaşımı</string>
<string name="superuser_notification">Superuser Bildirişləri</string>
<string name="request_timeout_summary">%1$d saniyə</string>
<string name="settings_su_reauth_title">Yüksəltmədən sonra Yenidən İdentifikasiya et</string>
<string name="settings_su_reauth_summary">Tətbiq yeniləmələridən sonra superuser icazələrini yenidən identifikasiya et</string>
<string name="settings_su_fingerprint_title">Barmaq İzi İdentifikasiyasını</string>
<string name="settings_su_fingerprint_summary">Barmaq izi oxuyucunu superuser icazələri üçün işlət</string>
<string name="auth_fingerprint">Barmaq izini İdentifikasiya et</string>
<string name="multiuser_mode">Çox-istifadəçi modu</string>
<string name="settings_owner_only">Yalnız cihaz sahibi</string>
<string name="settings_owner_manage">Cihaz sahibinin idarəçiliyində</string>
<string name="settings_user_independent">İstifadəçidən asılı olmayaraq</string>
<string name="owner_only_summary">Yalnız cihaz sahibinin root icazəsi var.</string>
<string name="owner_manage_summary">Yalnız cihaz sahibi root icazələrini redaktə edə və icazə istəkləri qəbul edə bilər.</string>
<string name="user_indepenent_summary">Hər istifadəçinin ayrı root qaydaları var.</string>
<string name="mount_namespace_mode">Namespace Modunu Qoş</string>
<string name="settings_ns_global">Qlobal Namespace</string>
<string name="settings_ns_requester">Keçmə Namespace</string>
<string name="settings_ns_isolate">Ayrılmış Namespace</string>
<string name="global_summary">Bütün root sessyaları qlobal qoşma namespace\'dən istifadə edir.</string>
<string name="requester_summary">Root sessyaları soruşulan namespace\'ləri birindən digərinə keçirəcək.</string>
<string name="isolate_summary">Hər bir root sessyasının ayrılmış namespace\'i olacaq.</string>
<string name="android_o_not_support">Android 8.0+\'da dəstəklənmir.</string>
<string name="disable_fingerprint">Barmaq izi təyin edilməyib ya da dəstəklənmir.</string>
<!--Superuser-->
<string name="su_request_title">Superuser Tələbi</string>
<string name="deny">Ləğv et</string>
<string name="prompt">Yönləndir</string>
<string name="grant">Təmin et</string>
<string name="su_warning">Cihazın tam icazəsi ilə təmin edin.\nƏmin deyilsinizsə ləğv edin!</string>
<string name="forever">Sonsuz</string>
<string name="once">Bir dəfəlik</string>
<string name="tenmin">10 dəq</string>
<string name="twentymin">20 dəq</string>
<string name="thirtymin">30 dəq</string>
<string name="sixtymin">60 dəq</string>
<string name="su_allow_toast">%1$s SuperUser icazəsi ilə təmin edildi</string>
<string name="su_deny_toast">%1$s SuperUser icazəsi ilə təmin edilmədi</string>
<string name="no_apps_found">Tətbiq yoxdur</string>
<string name="su_snack_grant">%1$s üçün Superuser icazəsi verilib</string>
<string name="su_snack_deny">%1$s üçün Superuser icazəsi verilməyib</string>
<string name="su_snack_notif_on">%1$s üçün bildirişlər açıqdır</string>
<string name="su_snack_notif_off">%1$s üçün bildirişlər bağlıdır</string>
<string name="su_snack_log_on">%1$s üçün giriş açıqdır</string>
<string name="su_snack_log_off">%1$s üçün giriş bağlıdır</string>
<string name="su_revoke_title">Ləğv olunsun?</string>
<string name="su_revoke_msg">%1$s üçün haqları ləğv etməyi təsdiq edirsiniz?</string>
<string name="toast">Tost</string>
<string name="none">Heçnə</string>
<string name="auth_fail">İdentifikasiya xətası</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">Hədəf UID: %1$d</string>
<string name="command">Komanda: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Sistem tətbiqlərini göstər</string>
</resources>

View File

@ -61,7 +61,6 @@
<string name="app_changelog">Списък с промени</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>
@ -162,7 +161,6 @@
<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-->

View File

@ -24,6 +24,7 @@
<string name="advanced_settings_title">Configuració avançada</string>
<string name="keep_force_encryption">Mantenir el xifrat forçat</string>
<string name="keep_dm_verity">Mantenir AVB 2.0/dm-verity</string>
<string name="recovery_mode">Mode de Recuperació</string>
<string name="current_installed">Instal·lada: %1$s</string>
<string name="latest_version">Última: %1$s</string>
<string name="uninstall">Desinstal·lar</string>
@ -75,19 +76,18 @@
<string name="manager_update_title">Actualització de Magisk Manager disponible!</string>
<!-- Installation -->
<string name="manager_download_install">Prem per descarregar i instalar.</string>
<string name="download_zip_only">Descarrega només el ZIP</string>
<string name="manager_download_install">Premi per baixar i instalar.</string>
<string name="download_zip_only">Únicament baixa el ZIP</string>
<string name="direct_install">Instal·lació directa (Recomanat)</string>
<string name="install_inactive_slot">Instal·la a la ranura inactiva (Després d\'una OTA)</string>
<string name="install_inactive_slot_msg">El teu dispositiu serà FORÇAT a arrancar en l\'actual ranura inactiva després del reinici!\nUtilitza aquesta opció NOMÉS quan l\'OTA s\'hagi fet.\nContinuar?</string>
<string name="select_method">Sel·lecciona mètode</string>
<string name="select_method">Sel·lecciona un mètode</string>
<string name="setup_title">Instal·lació addicional</string>
<string name="select_patch_file">Sel·lecciona i arranja un arxiu</string>
<string name="patch_file_msg">Sel·lecciona una imatge crua (*.img) o un ODIN tarfile (*.tar)</string>
<string name="reboot_delay_toast">Reinici en 5 segons…</string>
<!--Toasts, Dialogs-->
<string name="close">Tancar</string>
<string name="repo_install_title">Instal·lar %1$s</string>
<string name="repo_install_msg">Vols instal·lar %1$s ara?</string>
<string name="download">Baixar</string>
@ -110,23 +110,23 @@
<string name="restore_img_msg">Restaurant…</string>
<string name="restore_done">Restauració feta!</string>
<string name="restore_fail">La còpia de seguretat de Stock no existeix!</string>
<string name="proprietary_title">Descarrega codi propietari</string>
<string name="proprietary_notice">Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager descarregui una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet?</string>
<string name="proprietary_title">Baixar codi propietari</string>
<string name="proprietary_notice">Magisk Manager és codi lliure i no conté codi de l\'API de SafetyNet, ja que és codi propietari de Google.\n\nPot permetre que Magisk Manager baixi una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet?</string>
<string name="setup_fail">Instal·lació fallida.</string>
<string name="env_fix_title">Es requereix instal·lació addicional</string>
<string name="env_fix_msg">El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es descarregarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara?</string>
<string name="env_fix_msg">El teu dispositiu necessita instal·lació addicional per Magisk per funcionar correctament. Es baixarà el ZIP d\'instal·lació de Magisk , vol procedir a l\'instalació ara?</string>
<string name="setup_msg">S\'està executant la configuració de l\'entorn…</string>
<!--Settings Activity -->
<string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Tema obscur</string>
<string name="settings_dark_theme_summary">Habilitar el tema obscur</string>
<string name="settings_download_path_title">Directori de descàrrega</string>
<string name="settings_dark_theme_title">Tema fosc</string>
<string name="settings_dark_theme_summary">Habilitar el tema fosc</string>
<string name="settings_download_path_title">Directori de baixades</string>
<string name="settings_download_path_message">Els arxius es desaràn a %1$s</string>
<string name="settings_clear_cache_title">Netejar memòria cau del repositori</string>
<string name="settings_clear_cache_summary">Neteja l\'informació en memòria cau per als repositoris en línia, força a l\'aplicació a actualitzar-se en línia.</string>
<string name="settings_hide_manager_title">Amagar Magisk Manager</string>
<string name="settings_hide_manager_summary">Re-empaquetar Magisk Manager amb un nom de paquet a l\'atzar</string>
<string name="settings_hide_manager_summary">Reempaquetar Magisk Manager amb un nom de paquet a l\'atzar</string>
<string name="settings_restore_manager_title">Restaurar Magisk Manager</string>
<string name="settings_restore_manager_summary">Restaura Magisk Manager amb el nom de paquet original</string>
<string name="language">Idioma</string>
@ -146,6 +146,10 @@
<string name="settings_hosts_summary">Suport per aplicacions tipus Adblock fora de la partició del sistema</string>
<string name="settings_hosts_toast">Agregat el mòdul Systemless Hosts</string>
<string name="settings_app_name">Escriu el nom desitjat per l\'App</string>
<string name="settings_app_name_hint">Nou nom</string>
<string name="settings_app_name_helper">Es refarà l\'App amb aquest nom</string>
<string name="settings_app_name_error">Format invàl·lid</string>
<string name="settings_su_app_adb">Aplicacions y ADB</string>
<string name="settings_su_app">Només aplicacions</string>
<string name="settings_su_adb">Només ADB</string>
@ -161,8 +165,8 @@
<string name="request_timeout">Temps de petició</string>
<string name="superuser_notification">Notificació de superusuari</string>
<string name="request_timeout_summary">%1$d segons</string>
<string name="settings_su_reauth_title">Re-autenticació</string>
<string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació es actualitzada o reinstal·lada</string>
<string name="settings_su_reauth_title">Demanar després d\'una actualització</string>
<string name="settings_su_reauth_summary">Demanar permisos de superusuari novament si una aplicació és actualitzada o reinstal·lada</string>
<string name="settings_su_fingerprint_title">Autenticació per Empremta Dactilar</string>
<string name="settings_su_fingerprint_summary">Utilitza el sensor d\'Empremta Dactilar per permetre les sol·licituds de superusuari</string>
<string name="auth_fingerprint">Autenticar Emprempta Digital</string>
@ -174,7 +178,7 @@
<string name="owner_only_summary">Només l\'administrador té accés d\'arrel</string>
<string name="owner_manage_summary"> Només l\'administrador pot supervisar l\'acces d\'arrel y rebre sol·licituds d\'altres usuaris</string>
<string name="user_indepenent_summary">Tots els usuaris tenen separades les seves pròpies regles d\'arrel </string>
<string name="mount_namespace_mode">Muntar Namespace </string>
<string name="settings_ns_global">Namespace Global</string>
<string name="settings_ns_requester">Heretar Namespace</string>
@ -182,7 +186,6 @@
<string name="global_summary">Totes les sessions d\'arrel utilitzen el suport Namespace Global</string>
<string name="requester_summary">Les sessions d\'arrel heretaran les peticiones Namespace</string>
<string name="isolate_summary">Totes les sessions d\'arrel tindran la seva pròpia Namespace</string>
<string name="android_o_not_support">No es compatible amb Android 8.0+</string>
<string name="disable_fingerprint">No s\'han establert empremtes dactilars o no existeix el suport del dispositiu</string>
<string name="settings_download_path_error">Error al crear la carpeta. El directori ha de ser accesible desde el directori arrel i no pot ser un arxiu.</string>
@ -217,7 +220,7 @@
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID de l\'objectiu: %1$d</string>
<string name="command">Ordre: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Mostra apps del sistema</string>

View File

@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Restartování za 5 sekund…</string>
<!--Toasts, Dialogs-->
<string name="close">Zavřít</string>
<string name="repo_install_title">Instalovat %1$s</string>
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
<string name="download">Stáhnout</string>
@ -175,7 +174,6 @@
<string name="global_summary">Všechny relace root používají globální připojení jmenného prostoru.</string>
<string name="requester_summary">Kořenové relace dědí jmenný prostor žadatele.</string>
<string name="isolate_summary">Každá relace root bude mít svůj vlastní izolovaný jmenný prostor.</string>
<string name="android_o_not_support">Nepodporuje Android 8.0+.</string>
<string name="disable_fingerprint">Nebyly nastaveny žádné otisky prstů ani žádná podpora zařízení.</string>
<!--Superuser-->

View File

@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Neustart in 5 Sekunden…</string>
<!--Toasts, Dialogs-->
<string name="close">Schließen</string>
<string name="repo_install_title">Installiere %1$s</string>
<string name="repo_install_msg">Möchtest du %1$s installieren?</string>
<string name="download">Herunterladen</string>
@ -177,7 +176,6 @@
<string name="global_summary">Alle Root-Sitzungen benutzen den global angelegten Namespace</string>
<string name="requester_summary">Root-Sitzungen erben den Namespace des Abfragenden</string>
<string name="isolate_summary">Jede Root-Sitzung hat ihren isolierten Namespace</string>
<string name="android_o_not_support">Android 8.0+ wird nicht unterstützt</string>
<string name="disable_fingerprint">Keine Fingerabdrücke gespeichert oder keine Geräteunterstützung</string>
<!--Superuser-->

View File

@ -62,7 +62,6 @@
<string name="app_changelog">Καταγραφή αλλαγών εφαρμογής</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>
@ -144,7 +143,6 @@
<string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string>
<string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string>
<string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string>
<string name="android_o_not_support">Δεν υποστηρίζεται Android 8.0+</string>
<!--Superuser-->
<string name="su_request_title">Αίτημα υπερχρήστη</string>

View File

@ -24,7 +24,7 @@
<string name="advanced_settings_title">Ajustes avanzados</string>
<string name="keep_force_encryption">Mantener cifrado forzado</string>
<string name="keep_dm_verity">Mantener AVB 2.0/dm-verity</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="recovery_mode">Modo Recovery</string>
<string name="current_installed">Instalada: %1$s</string>
<string name="latest_version">Última: %1$s</string>
<string name="uninstall">Desinstalar</string>
@ -45,7 +45,7 @@
<string name="reboot_recovery">Reiniciar en Modo Recovery</string>
<string name="reboot_bootloader">Reiniciar en Modo Bootloader</string>
<string name="reboot_download">Reiniciar en Modo Download</string>
<string name="reboot_edl">Reiniciar en Modo EDL</string>
<string name="reboot_edl">Reiniciar en Modo EDL</string>
<!--Repo Fragment-->
<string name="update_available">Actualización Disponible</string>
@ -72,21 +72,20 @@
<string name="download_file_error">Error descargando archivo</string>
<string name="magisk_update_title">Actualización de Magisk disponible!</string>
<string name="manager_update_title">Actualización de Magisk Manager disponible!</string>
<!-- Installation -->
<string name="manager_download_install">Pulse para descargar e instalar</string>
<string name="download_zip_only">Descargar sólo el archivo ZIP</string>
<string name="direct_install">Instalación Directa (Recomendado)</string>
<string name="install_inactive_slot">Instalar en ranura inactiva (después de OTA)</string>
<string name="install_inactive_slot_msg">¡Se forzará su dispositivo para que arranque en la ranura inactiva actual después de un reinicio!\nUtilice esta opción solo después de que se haya completado la OTA.\nContinuar?</string>
<string name="select_method">Seleccionar Método</string>
<string name="setup_title">Configuración Adicional</string>
<string name="select_patch_file">Seleccionar y parchear un archivo</string>
<string name="patch_file_msg">Seleccione una imagen raw (* .img) o un archivo tar de ODIN (* .tar)</string>
<string name="reboot_delay_toast">Reiniciando en 5 segundos…</string>
<!-- Installation -->
<string name="manager_download_install">Pulse para descargar e instalar</string>
<string name="download_zip_only">Descargar sólo el archivo ZIP</string>
<string name="direct_install">Instalación Directa (Recomendado)</string>
<string name="install_inactive_slot">Instalar en ranura inactiva (después de OTA)</string>
<string name="install_inactive_slot_msg">¡Se forzará su dispositivo para que arranque en la ranura inactiva actual después de un reinicio!\nUtilice esta opción solo después de que se haya completado la OTA.\nContinuar?</string>
<string name="select_method">Seleccionar Método</string>
<string name="setup_title">Configuración Adicional</string>
<string name="select_patch_file">Seleccionar y parchear un archivo</string>
<string name="patch_file_msg">Seleccione una imagen raw (* .img) o un archivo tar de ODIN (* .tar)</string>
<string name="reboot_delay_toast">Reiniciando en 5 segundos…</string>
<!--Toasts, Dialogs-->
<string name="close">Cerrar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">¿Quieres instalar %1$s ahora?</string>
<string name="download">Descargar</string>
@ -121,7 +120,7 @@
<string name="settings_dark_theme_title">Tema oscuro</string>
<string name="settings_dark_theme_summary">Habilitar el tema oscuro</string>
<string name="settings_download_path_title">Ruta de Descarga</string>
<string name="settings_download_path_message">Los archivos se guardarán en %1$s</string>
<string name="settings_download_path_message">Los archivos se guardarán en %1$s</string>
<string name="settings_clear_cache_title">Limpiar caché del repositorio</string>
<string name="settings_clear_cache_summary">Limpiar la información en caché para los repositorios en línea, fuerza a la aplicación a actualizar en línea</string>
<string name="settings_hide_manager_title">Ocultar Magisk Manager</string>
@ -180,7 +179,6 @@
<string name="global_summary">Todas las sesiones de root utilizan el soporte Global Namespace</string>
<string name="requester_summary">Las sesiones de root heredarán las peticiones Namespace</string>
<string name="isolate_summary">Cada sesión root tendrá su propia Namespace</string>
<string name="android_o_not_support">No es compatible con Android 8.0+</string>
<string name="disable_fingerprint">No se establecieron huellas dactilares o no existe soporte del dispositivo</string>
<string name="settings_download_path_error">Error al crear la carpeta. Debe ser accesible desde el directorio raíz de almacenamiento y no debe ser un archivo.</string>
@ -218,5 +216,5 @@
<!-- MagiskHide -->
<string name="show_system_app">Mostrar sistema</string>
</resources>

View File

@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Taaskäivitamine 5 sekundi pärast…</string>
<!--Toasts, Dialogs-->
<string name="close">Sulge</string>
<string name="repo_install_title">Installi %1$s</string>
<string name="repo_install_msg">Kas soovid kohe installida %1$s?</string>
<string name="download">Allalaadimine</string>
@ -183,7 +182,6 @@
<string name="global_summary">Kõik juurkasutaja sessioonid kasutavad globaalset monteerimise nimeruumi.</string>
<string name="requester_summary">Juurkasutaja sessioonid võtavad üle selle taotleja nimeruumi.</string>
<string name="isolate_summary">Iga juurkasutaja sessioon saab oma isoleeritud nimeruumi.</string>
<string name="android_o_not_support">Ei toeta Androidi versiooni 8.0+.</string>
<string name="disable_fingerprint">Sõrmejälgi pole määratud või seade pole toetatud.</string>
<string name="settings_download_path_error">Faili loomisel esines viga. See peab olema ligipääsetav mäluruumi juurkaustast ning ei tohi olla fail.</string>

View File

@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Redémarrage dans 5 secondes…</string>
<!--Toasts, Dialogs-->
<string name="close">Fermer</string>
<string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Voulezvous installer %1$s maintenant?</string>
<string name="download">Télécharger</string>
@ -183,7 +182,6 @@
<string name="global_summary">Toutes les sessions superutilisateur utilisent lespace de noms global du montage.</string>
<string name="requester_summary">Les sessions superutilisateur hériteront de lespace de noms de leur demandeur.</string>
<string name="isolate_summary">Chaque session superutilisateur aura son propre espace de noms isolé.</string>
<string name="android_o_not_support">Android 8.0 et supérieurs ne sont pas pris en charge.</string>
<string name="disable_fingerprint">Aucune empreinte digitale na été définie ou le lecteur dempreinte nest pas pris en charge.</string>
<string name="settings_download_path_error">Erreur lors de la création du dossier. Il doit être accessible depuis le répertoire racine du stockage et ne doit pas être un fichier.</string>

View File

@ -0,0 +1,223 @@
<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="recovery_mode">रिकवरी मोड</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">सभी मॉड्यूल अक्षम/हटा दिए जाएंगे. रुट और आपका संभावित रूप से एन्क्रिप्ट डाटा हटा दिया जाएगा.</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">रिकवरी मोड में रिबूट करें</string>
<string name="reboot_bootloader">बूटलोडर में रिबूट करें</string>
<string name="reboot_download">डाउनलोड में रिबूट करें</string>
<string name="reboot_edl">EDL मोड में रिबूट करें</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>
<!--About Activity-->
<string name="app_changelog">परिवर्तन अभिलेख</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="download_open_parent">मूल फ़ोल्डर में दिखाएँ</string>
<string name="download_open_self">फाइल दिखाएँ</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">निष्क्रिय स्लॉट में स्थापित करें (OTA के बाद)</string>
<string name="install_inactive_slot_msg">आपके डिवाइस को रीबूट के बाद वर्तमान निष्क्रिय स्लॉट में बूट करने के लिए मजबूर किया जाएगा!\nOTA होने के बाद ही इस विकल्प का उपयोग करें.\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 tarfile (*.tar)</string>
<string name="reboot_delay_toast">5 सेकंड में रिबूट हो रहा है …</string>
<!--Toasts, Dialogs-->
<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">Repo cache साफ़ हो गया</string>
<string name="dtbo_patched_title">DTBO पैच कर दिया गया!</string>
<string name="dtbo_patched_reboot">Magisk Manager ने dtbo.img को पैच कर दिया. कृपया रिबूट करें.</string>
<string name="flashing">फ़्लैश हो रहा है…</string>
<string name="done">हो गया!</string>
<string name="failure">विफल हुआ</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">इमेजेज को पुनर्स्थापित करें</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 है और उस्में Google का मालिकाना SafetyNet API कोड शामिल नहीं है.\n\nक्या आप Magisk Manager को SafetyNet चेक के लिए एक्सटेंशन (GoogleApiClient शामिल) डाउनलोड करने की अनुमति देंगे ?</string>
<string name="setup_fail">सेटअप असफल हुआ.</string>
<string name="env_fix_title">अतिरिक्त सेटअप की आवश्यकता है</string>
<string name="env_fix_msg">ठीक से काम करने के लिए आपके डिवाइस को Magisk के लिए अतिरिक्त सेटअप की आवश्यकता है. यह Magisk सेटअप zip डाउनलोड करेगा, क्या आप आगे बढ़ना चाहते हैं?</string>
<string name="setup_msg">पर्यावरण सेटअप चल रहा है…</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_download_path_title">डाउनलोड करने की जगह</string>
<string name="settings_download_path_message">%1$s में फाइल्स रखी जाएँगी</string>
<string name="settings_clear_cache_title">Repo Cache साफ़ करें</string>
<string name="settings_clear_cache_summary">ऑनलाइन Repo के लिए Cached जानकारी साफ़ करें. यह एप्लिकेशन को ऑनलाइन रिफ्रेश होने के लिए मजबूर करता है.</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 का केवल मूल मोड</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">एडब्लॉक ऍप्लिकेशन्स के लिए सिस्टमलेस होस्ट्स का समर्थन</string>
<string name="settings_hosts_toast">सिस्टमलेस होस्ट्स का मॉड्यूल जोड़ दिया गया</string>
<string name="settings_su_app_adb">ऍप्लिकेशन्स और ADB</string>
<string name="settings_su_app">केवल ऍप्लिकेशन्स</string>
<string name="settings_su_adb">केवल 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="disable_fingerprint">कोई फ़िंगरप्रिंट नहीं सेट किया गया या डिवाइस का समर्थन नहीं है.</string>
<string name="settings_download_path_error">फोल्डर बनाने में त्रुटि. यह स्टोरेज रूट डायरेक्टरी से एक्सेस होना चाहिए और फाइल नहीं होना चाहिए.</string>
<!--Superuser-->
<string name="su_request_title">उत्तम उपयोगकर्ता का अनुरोध</string>
<string name="deny">इंकार करें</string>
<string name="prompt">आदेश</string>
<string name="grant">अनुमति दें</string>
<string name="su_warning">यह आपके डिवाइस की पूरी पहुँच की अनुमति देगा. यदि आप सुनिश्चित नहीं हैं तो इंकार करें!</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_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">Command: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">सिस्टम ऍप्लिकेशन्स दिखाएं</string>
</resources>

View File

@ -55,7 +55,6 @@
<string name="app_changelog">Popis izmjena aplikacije</string>
<!--Toasts, Dialogs-->
<string name="close">Zatvori</string>
<string name="repo_install_title">Instaliraj %1$s</string>
<string name="repo_install_msg">Da li želite instalirati %1$s sada?</string>
<string name="download">Preuzmi</string>

View File

@ -86,7 +86,6 @@
<string name="reboot_delay_toast">Me-reboot dalam 5 detik…</string>
<!--Toasts, Dialogs-->
<string name="close">Tutup</string>
<string name="repo_install_title">Pasang %1$s</string>
<string name="repo_install_msg">Apakah Anda ingin memasang %1$s sekarang?</string>
<string name="download">Unduh</string>
@ -181,7 +180,6 @@
<string name="global_summary">Semua sesi root menggunakan mount ruang nama global.</string>
<string name="requester_summary">Sesi root akan mewarisi ruang nama peminta mereka.</string>
<string name="isolate_summary">Setiap sesi root akan memiliki ruang nama tersendiri.</string>
<string name="android_o_not_support">Tidak mendukung Android 8.0+.</string>
<string name="disable_fingerprint">Tidak ada sidik jari diatur atau tidak ada dukungan perangkat.</string>
<string name="settings_download_path_error">Kesalahan membuat folder. Folder harus dapat diakses dari direktori penyimpanan root dan bukan merupakan file.</string>

View File

@ -1,223 +1,221 @@
<resources>
<!--Welcome Activity-->
<string name="modules">Moduli</string>
<string name="downloads">Download</string>
<string name="superuser">Superuser</string>
<string name="log">Registro eventi</string>
<string name="settings">Impostazioni</string>
<string name="install">Installa</string>
<string name="unsupport_magisk_title">Versione di Magisk non supportata</string>
<string name="unsupport_magisk_message">Questa versione di Magisk Manager non supporta versioni di Magisk inferiori alla v18.0.\n\nPuoi aggiornare manualmente Magisk o tornare a una versione meno recente dell\'app.</string>
<!--Welcome Activity-->
<string name="modules">Moduli</string>
<string name="downloads">Download</string>
<string name="superuser">Superuser</string>
<string name="log">Registro eventi</string>
<string name="settings">Impostazioni</string>
<string name="install">Installa</string>
<string name="unsupport_magisk_title">Versione di Magisk non supportata</string>
<string name="unsupport_magisk_message">Questa versione di Magisk Manager non supporta versioni di Magisk inferiori alla v18.0.\n\nPuoi aggiornare manualmente Magisk o tornare a una versione meno recente dell\'app.</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk non è installato.</string>
<string name="checking_for_updates">Controllo aggiornamenti…</string>
<string name="invalid_update_channel">Canale di aggiornamento non valido</string>
<string name="safetyNet_check_text">Tocca per controllare SafetyNet</string>
<string name="checking_safetyNet_status">Controllo stato SafetyNet…</string>
<string name="safetyNet_check_success">Controllo SafetyNet Superato</string>
<string name="safetyNet_api_error">Errore API SafetyNet</string>
<string name="safetyNet_res_invalid">La risposta non è valida.</string>
<string name="magisk_up_to_date">Magisk è aggiornato</string>
<string name="manager_up_to_date">Magisk Manager è aggiornato</string>
<string name="advanced_settings_title">Impostazioni avanzate</string>
<string name="keep_force_encryption">Mantieni crittografia forzata</string>
<string name="keep_dm_verity">Mantieni AVB 2.0/dm-verity</string>
<string name="current_installed">Installata: %1$s</string>
<string name="latest_version">Ultima: %1$s</string>
<string name="uninstall">Disinstalla</string>
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
<string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi. Il root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già.</string>
<string name="update">Aggiorna</string>
<string name="core_only_enabled">(Modalità solo Core abilitata)</string>
<!--Status Fragment-->
<string name="magisk_version_error">Magisk non è installato.</string>
<string name="checking_for_updates">Controllo aggiornamenti…</string>
<string name="invalid_update_channel">Canale di aggiornamento non valido</string>
<string name="safetyNet_check_text">Tocca per controllare SafetyNet</string>
<string name="checking_safetyNet_status">Controllo stato SafetyNet…</string>
<string name="safetyNet_check_success">Controllo SafetyNet Superato</string>
<string name="safetyNet_api_error">Errore API SafetyNet</string>
<string name="safetyNet_res_invalid">La risposta non è valida.</string>
<string name="magisk_up_to_date">Magisk è aggiornato</string>
<string name="manager_up_to_date">Magisk Manager è aggiornato</string>
<string name="advanced_settings_title">Impostazioni avanzate</string>
<string name="keep_force_encryption">Mantieni crittografia forzata</string>
<string name="keep_dm_verity">Mantieni AVB 2.0/dm-verity</string>
<string name="current_installed">Installata: %1$s</string>
<string name="latest_version">Ultima: %1$s</string>
<string name="uninstall">Disinstalla</string>
<string name="uninstall_magisk_title">Disinstalla Magisk</string>
<string name="uninstall_magisk_msg">Tutti i moduli verranno disabilitati/rimossi. Il root verrà rimosso e i tuoi dati potrebbero essere criptati, nel caso non lo siano già.</string>
<string name="update">Aggiorna</string>
<string name="core_only_enabled">(Modalità solo Core abilitata)</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nessuna informazione)</string>
<string name="no_modules_found">Nessun modulo trovato.</string>
<string name="update_file_created">Il modulo sarà aggiornato al prossimo riavvio.</string>
<string name="remove_file_created">Il modulo sarà rimosso al prossimo riavvio.</string>
<string name="remove_file_deleted">Il modulo non sarà rimosso al prossimo riavvio.</string>
<string name="disable_file_created">Il modulo sarà disabilitato al prossimo riavvio.</string>
<string name="disable_file_removed">Il modulo sarà abilitato al prossimo riavvio.</string>
<string name="author">Creato da: %1$s</string>
<string name="reboot_recovery">Riavvia in Recovery</string>
<string name="reboot_bootloader">Riavvia in Bootloader</string>
<string name="reboot_download">Riavvia in Download Mode</string>
<!--Module Fragment-->
<string name="no_info_provided">(Nessuna informazione)</string>
<string name="no_modules_found">Nessun modulo trovato.</string>
<string name="update_file_created">Il modulo sarà aggiornato al prossimo riavvio.</string>
<string name="remove_file_created">Il modulo sarà rimosso al prossimo riavvio.</string>
<string name="remove_file_deleted">Il modulo non sarà rimosso al prossimo riavvio.</string>
<string name="disable_file_created">Il modulo sarà disabilitato al prossimo riavvio.</string>
<string name="disable_file_removed">Il modulo sarà abilitato al prossimo riavvio.</string>
<string name="author">Creato da: %1$s</string>
<string name="reboot_recovery">Riavvia in Recovery</string>
<string name="reboot_bootloader">Riavvia in Bootloader</string>
<string name="reboot_download">Riavvia in Download Mode</string>
<!--Repo Fragment-->
<string name="update_available">Aggiornamento disponibile</string>
<string name="installed">Installato</string>
<string name="not_installed">Non installato</string>
<string name="updated_on">Aggiornato il: %1$s</string>
<string name="sorting_order">Ordinamento</string>
<string name="sort_by_name">Ordina per nome</string>
<string name="sort_by_update">Ordina per ultimo aggiornamento</string>
<!--Repo Fragment-->
<string name="update_available">Aggiornamento disponibile</string>
<string name="installed">Installato</string>
<string name="not_installed">Non installato</string>
<string name="updated_on">Aggiornato il: %1$s</string>
<string name="sorting_order">Ordinamento</string>
<string name="sort_by_name">Ordina per nome</string>
<string name="sort_by_update">Ordina per ultimo aggiornamento</string>
<!--Log Fragment-->
<string name="menuSaveLog">Salva registro eventi</string>
<string name="menuReload">Ricarica</string>
<string name="menuClearLog">Svuota il registro eventi</string>
<string name="logs_cleared">Registro eventi svuotato correttamente.</string>
<!--Log Fragment-->
<string name="menuSaveLog">Salva registro eventi</string>
<string name="menuReload">Ricarica</string>
<string name="menuClearLog">Svuota il registro eventi</string>
<string name="logs_cleared">Registro eventi svuotato correttamente.</string>
<!--About Activity-->
<string name="app_changelog">Novità</string>
<string name="app_changelog">Novità</string>
<!-- System Components, Notifications -->
<string name="update_channel">Aggiornamenti Magisk</string>
<string name="progress_channel">Notifiche di avanzamento</string>
<string name="download_complete">Download completato</string>
<string name="update_channel">Aggiornamenti Magisk</string>
<string name="progress_channel">Notifiche di avanzamento</string>
<string name="download_complete">Download completato</string>
<string name="download_file_error">Errore durante il download del file</string>
<string name="download_open_parent">Mostra nella cartella padre</string>
<string name="download_open_self">Mostra file</string>
<string name="magisk_update_title">È disponibile un aggiornamento di Magisk!</string>
<string name="manager_update_title">È disponibile un aggiornamento di Magisk Manager!</string>
<string name="download_open_self">Mostra file</string>
<string name="magisk_update_title">È disponibile un aggiornamento di Magisk!</string>
<string name="manager_update_title">È disponibile un aggiornamento di Magisk Manager!</string>
<!-- Installation -->
<string name="manager_download_install">Apri questa notifica per scaricare e installare.</string>
<string name="download_zip_only">Scarica solo il file zip</string>
<string name="direct_install">Installazione diretta (raccomandata)</string>
<string name="install_inactive_slot">Installa nello slot inattivo (dopo un OTA)</string>
<string name="install_inactive_slot_msg">Questo dispositivo verrà FORZATO ad avviarsi usando lo slot inattivo!\nUsa questo metodo solo dopo che un OTA è stato installato.\nVuoi continuare?</string>
<string name="select_method">Seleziona un metodo</string>
<string name="setup_title">Configurazione aggiuntiva</string>
<string name="select_patch_file">Seleziona e aggiorna un file</string>
<string name="patch_file_msg">Seleziona un\'immagine in formato .img o un file ODIN .tar</string>
<string name="reboot_delay_toast">Riavvio fra 5 secondi…</string>
<!--Toasts, Dialogs-->
<string name="close">Chiudi</string>
<string name="repo_install_title">Installazione di %1$s</string>
<string name="repo_install_msg">Vuoi installare %1$s?</string>
<string name="download">Download</string>
<string name="reboot">Riavvia</string>
<string name="settings_reboot_toast">Riavvia per applicare i cambiamenti.</string>
<string name="release_notes">Note di rilascio</string>
<string name="repo_cache_cleared">La cache delle repository è stata svuotata</string>
<!-- Installation -->
<string name="manager_download_install">Apri questa notifica per scaricare e installare.</string>
<string name="download_zip_only">Scarica solo il file zip</string>
<string name="direct_install">Installazione diretta (raccomandata)</string>
<string name="install_inactive_slot">Installa nello slot inattivo (dopo un OTA)</string>
<string name="install_inactive_slot_msg">Questo dispositivo verrà FORZATO ad avviarsi usando lo slot inattivo!\nUsa questo metodo solo dopo che un OTA è stato installato.\nVuoi continuare?</string>
<string name="select_method">Seleziona un metodo</string>
<string name="setup_title">Configurazione aggiuntiva</string>
<string name="select_patch_file">Seleziona e aggiorna un file</string>
<string name="patch_file_msg">Seleziona un\'immagine in formato .img o un file ODIN .tar</string>
<string name="reboot_delay_toast">Riavvio fra 5 secondi…</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">Installazione di %1$s</string>
<string name="repo_install_msg">Vuoi installare %1$s?</string>
<string name="download">Download</string>
<string name="reboot">Riavvia</string>
<string name="settings_reboot_toast">Riavvia per applicare i cambiamenti.</string>
<string name="release_notes">Note di rilascio</string>
<string name="repo_cache_cleared">La cache delle repository è stata svuotata</string>
<string name="dtbo_patched_title">DTBO è stato aggiornato!</string>
<string name="dtbo_patched_reboot">Magisk Manager ha aggiornato dtbo.img. Riavvia per completare.</string>
<string name="flashing">Flash in corso…</string>
<string name="done">Completato!</string>
<string name="failure">Fallito</string>
<string name="hide_manager_title">Nascondendo Magisk Manager…</string>
<string name="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager.</string>
<string name="open_link_failed_toast">Nessuna app disponibile per aprire il link.</string>
<string name="warning">Attenzione</string>
<string name="complete_uninstall">Disinstallazione completa</string>
<string name="restore_img">Ripristina Immagini</string>
<string name="restore_img_msg">Ripristino…</string>
<string name="restore_done">Ripristino completato!</string>
<string name="restore_fail">Non esiste un\'immagine originale di boot!</string>
<string name="proprietary_title">Scarica codice proprietario</string>
<string name="proprietary_notice">Magisk Manager è FOSS e non contiene codice proprietario delle API Google SafetyNet.\n\nVuoi scaricare un\'estensione (contenente GoogleApiClient) per controllare lo stato di SafetyNet?</string>
<string name="setup_fail">Configurazione fallita.</string>
<string name="env_fix_title">Configurazione aggiuntiva richiesta</string>
<string name="env_fix_msg">Il tuo dispositivo necessita di una configurazione aggiuntiva per far funzionare Magisk correttamente. Verrà scaricato il file zip di Magisk, vuoi procedere ora?</string>
<string name="setup_msg">Configurazione dell\'ambiente in corso…</string>
<string name="dtbo_patched_reboot">Magisk Manager ha aggiornato dtbo.img. Riavvia per completare.</string>
<string name="flashing">Flash in corso…</string>
<string name="done">Completato!</string>
<string name="failure">Fallito</string>
<string name="hide_manager_title">Nascondendo Magisk Manager…</string>
<string name="hide_manager_fail_toast">Non è stato possibile nascondere Magisk Manager.</string>
<string name="open_link_failed_toast">Nessuna app disponibile per aprire il link.</string>
<string name="warning">Attenzione</string>
<string name="complete_uninstall">Disinstallazione completa</string>
<string name="restore_img">Ripristina Immagini</string>
<string name="restore_img_msg">Ripristino…</string>
<string name="restore_done">Ripristino completato!</string>
<string name="restore_fail">Non esiste un\'immagine originale di boot!</string>
<string name="proprietary_title">Scarica codice proprietario</string>
<string name="proprietary_notice">Magisk Manager è FOSS e non contiene codice proprietario delle API Google SafetyNet.\n\nVuoi scaricare un\'estensione (contenente GoogleApiClient) per controllare lo stato di SafetyNet?</string>
<string name="setup_fail">Configurazione fallita.</string>
<string name="env_fix_title">Configurazione aggiuntiva richiesta</string>
<string name="env_fix_msg">Il tuo dispositivo necessita di una configurazione aggiuntiva per far funzionare Magisk correttamente. Verrà scaricato il file zip di Magisk, vuoi procedere ora?</string>
<string name="setup_msg">Configurazione dell\'ambiente in corso…</string>
<!--Settings Activity -->
<string name="settings_general_category">Generale</string>
<string name="settings_dark_theme_title">Tema scuro</string>
<string name="settings_dark_theme_summary">Abilita il tema scuro.</string>
<string name="settings_dark_theme_title">Tema scuro</string>
<string name="settings_dark_theme_summary">Abilita il tema scuro.</string>
<string name="settings_download_path_title">Percorso di download</string>
<string name="settings_download_path_message">I file verranno salvati in %1$s</string>
<string name="settings_clear_cache_title">Svuota cache repository</string>
<string name="settings_clear_cache_summary">Svuota la cache delle repository. Questa opzione forza l\'aggiornamento online dell\'app.</string>
<string name="settings_hide_manager_title">Nascondi Magisk Manager</string>
<string name="settings_hide_manager_summary">Reinstalla Magisk Manager con un nome pacchetto casuale.</string>
<string name="settings_restore_manager_title">Ripristina Magisk Manager</string>
<string name="settings_restore_manager_summary">Ripristina Magisk Manager con il nome pacchetto originale</string>
<string name="language">Lingua</string>
<string name="system_default">(Sistema)</string>
<string name="settings_update">Impostazioni aggiornamento</string>
<string name="settings_check_update_title">Controlla aggiornamenti</string>
<string name="settings_check_update_summary">Controlla automaticamente gli aggiornamenti in background.</string>
<string name="settings_update_channel_title">Canale di aggiornamento</string>
<string name="settings_update_stable">Stabile</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Personalizzato</string>
<string name="settings_update_custom_msg">Inserisci un URL personalizzato</string>
<string name="settings_core_only_title">Modalità Magisk Core</string>
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU e MagiskHide rimarranno abilitati</string>
<string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni.</string>
<string name="settings_hosts_title">Host systemless</string>
<string name="settings_hosts_summary">Supporto a host systemless per le app che bloccano le pubblicità.</string>
<string name="settings_hosts_toast">Aggiunto modulo per host systemless</string>
<string name="settings_clear_cache_title">Svuota cache repository</string>
<string name="settings_clear_cache_summary">Svuota la cache delle repository. Questa opzione forza l\'aggiornamento online dell\'app.</string>
<string name="settings_hide_manager_title">Nascondi Magisk Manager</string>
<string name="settings_hide_manager_summary">Reinstalla Magisk Manager con un nome pacchetto casuale.</string>
<string name="settings_restore_manager_title">Ripristina Magisk Manager</string>
<string name="settings_restore_manager_summary">Ripristina Magisk Manager con il nome pacchetto originale</string>
<string name="language">Lingua</string>
<string name="system_default">(Sistema)</string>
<string name="settings_update">Impostazioni aggiornamento</string>
<string name="settings_check_update_title">Controlla aggiornamenti</string>
<string name="settings_check_update_summary">Controlla automaticamente gli aggiornamenti in background.</string>
<string name="settings_update_channel_title">Canale di aggiornamento</string>
<string name="settings_update_stable">Stabile</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Personalizzato</string>
<string name="settings_update_custom_msg">Inserisci un URL personalizzato</string>
<string name="settings_core_only_title">Modalità Magisk Core</string>
<string name="settings_core_only_summary">Abilita solo le funzioni principali. Nessun modulo verrà caricato. MagiskSU e MagiskHide rimarranno abilitati</string>
<string name="settings_magiskhide_summary">Nasconde Magisk da numerose rilevazioni.</string>
<string name="settings_hosts_title">Host systemless</string>
<string name="settings_hosts_summary">Supporto a host systemless per le app che bloccano le pubblicità.</string>
<string name="settings_hosts_toast">Aggiunto modulo per host systemless</string>
<string name="settings_su_app_adb">App e ADB</string>
<string name="settings_su_app">Solo app</string>
<string name="settings_su_adb">Solo ADB</string>
<string name="settings_su_disable">Disabilitato</string>
<string name="settings_su_request_10">10 secondi</string>
<string name="settings_su_request_15">15 secondi</string>
<string name="settings_su_request_20">20 secondi</string>
<string name="settings_su_request_30">30 secondi</string>
<string name="settings_su_request_45">45 secondi</string>
<string name="settings_su_request_60">60 secondi</string>
<string name="superuser_access">Accesso Superuser</string>
<string name="auto_response">Accesso predefinito</string>
<string name="request_timeout">Timeout richiesta</string>
<string name="superuser_notification">Notifica Superuser</string>
<string name="request_timeout_summary">%1$d secondi</string>
<string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string>
<string name="settings_su_reauth_summary">Riautentica i permessi Superuser dopo un aggiornamento dell\'app</string>
<string name="settings_su_fingerprint_title">Abilita autenticazione impronta</string>
<string name="settings_su_fingerprint_summary">Utilizza il sensore di impronte per accettare le richieste Superuser</string>
<string name="auth_fingerprint">Conferma impronta</string>
<string name="settings_su_app_adb">App e ADB</string>
<string name="settings_su_app">Solo app</string>
<string name="settings_su_adb">Solo ADB</string>
<string name="settings_su_disable">Disabilitato</string>
<string name="settings_su_request_10">10 secondi</string>
<string name="settings_su_request_15">15 secondi</string>
<string name="settings_su_request_20">20 secondi</string>
<string name="settings_su_request_30">30 secondi</string>
<string name="settings_su_request_45">45 secondi</string>
<string name="settings_su_request_60">60 secondi</string>
<string name="superuser_access">Accesso Superuser</string>
<string name="auto_response">Accesso predefinito</string>
<string name="request_timeout">Timeout richiesta</string>
<string name="superuser_notification">Notifica Superuser</string>
<string name="request_timeout_summary">%1$d secondi</string>
<string name="settings_su_reauth_title">Riautentica dopo aggiornamento</string>
<string name="settings_su_reauth_summary">Riautentica i permessi Superuser dopo un aggiornamento dell\'app</string>
<string name="settings_su_fingerprint_title">Abilita autenticazione impronta</string>
<string name="settings_su_fingerprint_summary">Utilizza il sensore di impronte per accettare le richieste Superuser</string>
<string name="auth_fingerprint">Conferma impronta</string>
<string name="multiuser_mode">Modalità multiutente</string>
<string name="settings_owner_only">Solo proprietario del dispositivo</string>
<string name="settings_owner_manage">Gestito dal proprietario utente</string>
<string name="settings_user_independent">Idipendente dall\'utente</string>
<string name="owner_only_summary">Solo il proprietario ha i permessi di root.</string>
<string name="owner_manage_summary">Solo il proprietario può gestire accesso root e ricevere richieste.</string>
<string name="user_indepenent_summary">Ogni utente ha le sue regole di root indpendenti.</string>
<string name="multiuser_mode">Modalità multiutente</string>
<string name="settings_owner_only">Solo proprietario del dispositivo</string>
<string name="settings_owner_manage">Gestito dal proprietario utente</string>
<string name="settings_user_independent">Idipendente dall\'utente</string>
<string name="owner_only_summary">Solo il proprietario ha i permessi di root.</string>
<string name="owner_manage_summary">Solo il proprietario può gestire accesso root e ricevere richieste.</string>
<string name="user_indepenent_summary">Ogni utente ha le sue regole di root indpendenti.</string>
<string name="mount_namespace_mode">Modalità mount namespace</string>
<string name="settings_ns_global">Namespace globale</string>
<string name="settings_ns_requester">Namespace ereditato</string>
<string name="settings_ns_isolate">Namespace isolato</string>
<string name="global_summary">Tutte le sessioni di root erediteranno il namespace globale.</string>
<string name="requester_summary">Le sessioni di root erediteranno il namespace del loro richiedente.</string>
<string name="isolate_summary">Ogni sessione di root avrà il suo namespace isolato.</string>
<string name="android_o_not_support">Non è supportato da Android 8.0+.</string>
<string name="disable_fingerprint">Non è presente alcuna impronta o il dispositivo non è supportato.</string>
<string name="settings_download_path_error">Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file.</string>
<string name="mount_namespace_mode">Modalità mount namespace</string>
<string name="settings_ns_global">Namespace globale</string>
<string name="settings_ns_requester">Namespace ereditato</string>
<string name="settings_ns_isolate">Namespace isolato</string>
<string name="global_summary">Tutte le sessioni di root erediteranno il namespace globale.</string>
<string name="requester_summary">Le sessioni di root erediteranno il namespace del loro richiedente.</string>
<string name="isolate_summary">Ogni sessione di root avrà il suo namespace isolato.</string>
<string name="disable_fingerprint">Non è presente alcuna impronta o il dispositivo non è supportato.</string>
<string name="settings_download_path_error">Errore durante la creazione della cartella. Deve essere accessibile dalla radice della memoria di archiviazione e non essere un file.</string>
<!--Superuser-->
<string name="su_request_title">Richiesta Superuser</string>
<!--Superuser-->
<string name="su_request_title">Richiesta Superuser</string>
<string name="deny">Nega</string>
<string name="prompt">Chiedi</string>
<string name="grant">Concedi</string>
<string name="su_warning">Concede il pieno accesso al dispositivo.\nNega se non sei sicuro!</string>
<string name="forever">Sempre</string>
<string name="once">Una volta</string>
<string name="tenmin">10 minuti</string>
<string name="twentymin">20 minuti</string>
<string name="thirtymin">30 minuti</string>
<string name="sixtymin">60 minuti</string>
<string name="su_allow_toast">%1$s ha ottenuto i permessi Superuser</string>
<string name="su_deny_toast">%1$s non ha ottenuto i permessi Superuser</string>
<string name="no_apps_found">Nessuna app trovata</string>
<string name="su_snack_grant"> %1$s ha ottenuto i permessi Superuser</string>
<string name="su_snack_deny"> %1$s non ha ottenuto i permessi Superuser</string>
<string name="su_snack_notif_on">Notifiche per %1$s abilitate</string>
<string name="su_snack_notif_off">Notifiche per %1$s disabilitate</string>
<string name="su_snack_log_on">Registro eventi abilitato per %1$s</string>
<string name="su_snack_log_off">Registro eventi non abilitato per %1$s</string>
<string name="prompt">Chiedi</string>
<string name="grant">Concedi</string>
<string name="su_warning">Concede il pieno accesso al dispositivo.\nNega se non sei sicuro!</string>
<string name="forever">Sempre</string>
<string name="once">Una volta</string>
<string name="tenmin">10 minuti</string>
<string name="twentymin">20 minuti</string>
<string name="thirtymin">30 minuti</string>
<string name="sixtymin">60 minuti</string>
<string name="su_allow_toast">%1$s ha ottenuto i permessi Superuser</string>
<string name="su_deny_toast">%1$s non ha ottenuto i permessi Superuser</string>
<string name="no_apps_found">Nessuna app trovata</string>
<string name="su_snack_grant"> %1$s ha ottenuto i permessi Superuser</string>
<string name="su_snack_deny"> %1$s non ha ottenuto i permessi Superuser</string>
<string name="su_snack_notif_on">Notifiche per %1$s abilitate</string>
<string name="su_snack_notif_off">Notifiche per %1$s disabilitate</string>
<string name="su_snack_log_on">Registro eventi abilitato per %1$s</string>
<string name="su_snack_log_off">Registro eventi non abilitato per %1$s</string>
<string name="su_revoke_title">Vuoi revocare?</string>
<string name="su_revoke_msg">Confermi la revoca dei diritti di %1$s?</string>
<string name="toast">Toast</string>
<string name="none">Nessuno</string>
<string name="auth_fail">Autenticatione fallita</string>
<string name="su_revoke_msg">Confermi la revoca dei diritti di %1$s?</string>
<string name="toast">Toast</string>
<string name="none">Nessuno</string>
<string name="auth_fail">Autenticatione fallita</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID destinazione: %1$d</string>
<string name="command">Comando: %1$s</string>
<!--Superuser logs-->
<string name="pid">PID: %1$d</string>
<string name="target_uid">UID destinazione: %1$d</string>
<string name="command">Comando: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Mostra app di sistema</string>
<!-- MagiskHide -->
<string name="show_system_app">Mostra app di sistema</string>
</resources>

View File

@ -72,7 +72,6 @@
<string name="manager_update_title">Magisk Managerの更新があります</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>
@ -169,7 +168,6 @@
<string name="global_summary">すべてのrootセッションがグローバル名前空間を使用します</string>
<string name="requester_summary">rootセッションはリクエスト者の名前空間を継承します</string>
<string name="isolate_summary">rootセッション毎に分離された名前空間を使用します</string>
<string name="android_o_not_support">Android 8.0以降では対応していません</string>
<string name="disable_fingerprint">指紋が登録されていないか、お使いの端末でサポートされていません。</string>
<!--Superuser-->

View File

@ -83,7 +83,6 @@
<string name="patch_file_msg">원시 이미지 (*.img) 또는 오딘 tar 파일 (*.tar) 선택</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>
@ -176,7 +175,6 @@
<string name="global_summary">모든 루트 세션이 전역 마운트 이름공간을 사용합니다.</string>
<string name="requester_summary">루트 세션은 요청자의 이름공간을 상속합니다.</string>
<string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 이름공간을 사용합니다.</string>
<string name="android_o_not_support">안드로이드 8.0 이상 버전에서 사용할 수 없습니다.</string>
<string name="disable_fingerprint">지문이 등록되지 않았거나 기기가 지문 인식을 지원하지 않습니다.</string>
<!--Superuser-->

View File

@ -61,7 +61,6 @@
<string name="app_changelog">Pakeitimų sąrašas</string>
<!--Toasts, Dialogs-->
<string name="close">Uždaryti</string>
<string name="repo_install_title">Instaliuoti %1$s</string>
<string name="repo_install_msg">Ar jūs norite instaliuoti %1$s?</string>
<string name="download">Atsisiųsti</string>
@ -156,7 +155,6 @@
<string name="global_summary">Visos root sesijos naudoja globalią vardų sritį</string>
<string name="requester_summary">Root sesijos paveldi jos išprašytojo/s vardų sritį</string>
<string name="isolate_summary">Kiekviena root sesija turi savo izoliuotą vardų sritį</string>
<string name="android_o_not_support">Įrenginiai su Android 8.0+ nepalaiko šio nustatymo</string>
<string name="disable_fingerprint">Jūsų įrenginyje nebuvo surasta pirštų antspaudų arba jūsų įrenginys neturi pirštų antspaudų skaitytuvo</string>
<!--Superuser-->

View File

@ -84,7 +84,6 @@
<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>
@ -175,7 +174,6 @@
<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-->

View File

@ -69,7 +69,6 @@
<string name="manager_update_title">En Magisk Manager-oppdatering er tilgjengelig!</string>
<!--Toasts, Dialogs-->
<string name="close">Lukk</string>
<string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Vil du installere %1$s nå?</string>
<string name="download">Last ned</string>
@ -166,7 +165,6 @@
<string name="global_summary">Alle root-økter benytter det altdekkende monteringsnavnefeltet.</string>
<string name="requester_summary">Root-økter vil arve forespørrerens navnefelt.</string>
<string name="isolate_summary">Hver root-økt vil ha sitt eget isolerte navnefelt.</string>
<string name="android_o_not_support">Støtter ikke Android ≥8.0.</string>
<string name="disable_fingerprint">Ingen fingeravtrykk ble gitt, eller så støttes det ikke av enheten.</string>
<!--Superuser-->

View File

@ -62,7 +62,6 @@
<string name="app_changelog">App\'s changelog</string>
<!--Toasts, Dialogs-->
<string name="close">Sluiten</string>
<string name="repo_install_title">%1$s installeren</string>
<string name="repo_install_msg">Zeker weten %1$s installeren?</string>
<string name="download">Downloaden</string>
@ -151,7 +150,6 @@
<string name="global_summary">Alle rootsessies gebruiken de globale naamruimte</string>
<string name="requester_summary">Rootsessies verkrijgen de verzoeker\'s naamruimte</string>
<string name="isolate_summary">Iedere rootsessie heeft een eigen geïsoleerde naamruimte</string>
<string name="android_o_not_support">Ondersteunt geen Android 8.0+</string>
<string name="disable_fingerprint">Geen vingerafdrukken ingesteld, of geen apparaatondersteuning</string>
<!--Superuser-->

View File

@ -9,12 +9,12 @@
<string name="install">Instaluj</string>
<string name="unsupport_magisk_title">Nieobsługiwana Wersja Magisk</string>
<string name="unsupport_magisk_message">Ta wersja Magisk Managera nie obsługuje wersji Magisk niższej niż v18.0.\n\nMożesz albo ręcznie zaktualizować Magisk lub obniżyć w aplikacji do starszej wersji.</string>
<!--Status Fragment-->
<!--Status Fragment-->
<string name="magisk_version_error">Magisk nie jest zainstalowany.</string>
<string name="checking_for_updates">Sprawdzanie aktualizacji…</string>
<string name="invalid_update_channel">Nieprawidłowy Kanał Aktualizacji</string>
<string name="safetyNet_check_text">Dotknij aby sprawdzić SafetyNet</string>
<string name="safetyNet_check_text">Dotknij aby sprawdzić SafetyNet</string>
<string name="checking_safetyNet_status">Sprawdzanie statusu SafetyNet…</string>
<string name="safetyNet_check_success">SafetyNet Poprawny</string>
<string name="safetyNet_api_error">SafetyNet API Błędny</string>
@ -28,11 +28,11 @@
<string name="latest_version">Ostatnia: %1$s</string>
<string name="uninstall">Odinstaluj</string>
<string name="uninstall_magisk_title">Odinstaluj Magisk</string>
<string name="uninstall_magisk_msg">Wszystkie moduły będą wyłączone/usunięte. Root zostanie usunięty i przywrócone szyfrowanie danych, jeśli nie są te dane obecnie szyfrowane</string>
<string name="uninstall_magisk_msg">Wszystkie moduły będą wyłączone/usunięte. Root zostanie usunięty i przywrócone szyfrowanie danych, jeśli nie są te dane obecnie szyfrowane</string>
<string name="update">Pobierz</string>
<string name="core_only_enabled">(Włączony tylko tryb jądra)</string>
<!--Module Fragment-->
<!--Module Fragment-->
<string name="no_info_provided">(Nie umieszczono informacji)</string>
<string name="no_modules_found">Nie znaleziono modułów.</string>
<string name="update_file_created">Moduł zostanie zaktualizowany przy następnym restarcie.</string>
@ -45,12 +45,12 @@
<string name="reboot_bootloader">Restart do Bootloadera</string>
<string name="reboot_download">Restart do Download</string>
<string name="reboot_edl">Restart do EDL</string>
<!--Repo Fragment-->
<!--Repo Fragment-->
<string name="update_available">Aktualizacja dostępna</string>
<string name="installed">Zainstalowany</string>
<string name="not_installed">Nie zainstalowany</string>
<string name="updated_on">Zaktualizowano: %1$s</string>
<string name="updated_on">Zaktualizowano: %1$s</string>
<string name="sorting_order">Kolejność Sortowania</string>
<string name="sort_by_name">Sortuj po nazwie</string>
<string name="sort_by_update">Sortuj po ostatniej aktualizacji</string>
@ -71,23 +71,22 @@
<string name="download_file_error">Błąd pobierania pliku</string>
<string name="download_open_parent">Pokaż w folderze nadrzędnym</string>
<string name="download_open_self">Pokaż pliki</string>
<string name="magisk_update_title">Nowa Wersja Magisk Dostępna!</string>
<string name="magisk_update_title">Nowa Wersja Magisk Dostępna!</string>
<string name="manager_update_title">Nowa Wersja Magisk Manager Dostępna!</string>
<!-- Installation -->
<string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string>
<string name="download_zip_only">Pobierz Tylko Zip</string>
<!-- Installation -->
<string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string>
<string name="download_zip_only">Pobierz Tylko Zip</string>
<string name="direct_install">Bezpośrednia instalacja (Zalecane)</string>
<string name="install_inactive_slot">Zainstaluj do Nieaktywnego Slotu (po OTA)</string>
<string name="install_inactive_slot">Zainstaluj do Nieaktywnego Slotu (po OTA)</string>
<string name="install_inactive_slot_msg">Urządzenie będzie MUSIAŁO uruchomić się z bieżącego nieaktywnego slotu po restarcie! /\nUżyj tylko tej opcji po zakończeniu OTA.\nKontynuować?</string>
<string name="select_method">Wybierz Metodę</string>
<string name="setup_title">Dodatkowa konfiguracja</string>
<string name="select_method">Wybierz Metodę</string>
<string name="setup_title">Dodatkowa konfiguracja</string>
<string name="select_patch_file">Wybierz i Wgraj Plik</string>
<string name="patch_file_msg">Wybierz obraz raw (*.img) lub plik ODIN tar (*.tar)</string>
<string name="reboot_delay_toast">Ponowne uruchomienie za 5 sekund…</string>
<!--Toasts, Dialogs-->
<string name="close">Zamknij</string>
<!--Toasts, Dialogs-->
<string name="repo_install_title">Instaluj %1$s</string>
<string name="repo_install_msg">Czy chcesz zainstalować %1$s ?</string>
<string name="download">Pobierz</string>
@ -100,14 +99,14 @@
<string name="dtbo_patched_reboot">Magisk Manager wgrał dtbo.img. Uruchom ponownie</string>
<string name="flashing">Flashowanie</string>
<string name="done">Gotowe!</string>
<string name="failure">Błąd</string>
<string name="hide_manager_title">Ukryj Magisk Manager…</string>
<string name="failure">Błąd</string>
<string name="hide_manager_title">Ukryj Magisk Manager…</string>
<string name="hide_manager_fail_toast">Błąd Ukrycia Magisk Managera.</string>
<string name="open_link_failed_toast">Nie znaleziono aplikacji pod linkiem.</string>
<string name="open_link_failed_toast">Nie znaleziono aplikacji pod linkiem.</string>
<string name="warning">Uwaga</string>
<string name="complete_uninstall">Odinstalowywanie Zakończone</string>
<string name="restore_img">Przywróć Obraz</string>
<string name="restore_img_msg">Przywracanie…</string>
<string name="restore_img_msg">Przywracanie…</string>
<string name="restore_done">Przywracanie zakończone!</string>
<string name="restore_fail">Stock backup nie istnieje!</string>
<string name="proprietary_title">Pobierz Kod</string>
@ -123,7 +122,7 @@
<string name="settings_dark_theme_summary">Włącz ciemny motyw</string>
<string name="settings_download_path_title">Pobierz dodatek</string>
<string name="settings_download_path_message">Pliki zostaną zapisane w %1$s</string>
<string name="settings_clear_cache_title">Wyczyść Pamięć Repozytorium</string>
<string name="settings_clear_cache_title">Wyczyść Pamięć Repozytorium</string>
<string name="settings_clear_cache_summary">Wymusza na aplikacji odświeżenie repozytorium online.</string>
<string name="settings_hide_manager_title">Ukryj Magisk Manager</string>
<string name="settings_hide_manager_summary">Przepakowanie Magisk Manager z losową nazwą pakietu</string>
@ -145,7 +144,7 @@
<string name="settings_hosts_title">Włącz systemless hosts</string>
<string name="settings_hosts_summary">Wsparcie systemless dla aplikacji Adblock</string>
<string name="settings_hosts_toast">Dodano moduł systemless hosts</string>
<string name="settings_su_app_adb">Aplikacje i ADB</string>
<string name="settings_su_app">Tylko Aplikacje</string>
<string name="settings_su_adb">Tylko ADB</string>
@ -166,8 +165,8 @@
<string name="settings_su_fingerprint_title">Włącz Uwierzytelnienie Odciskiem Palca</string>
<string name="settings_su_fingerprint_summary">Użyj skanera linii papilarnych, aby zezwolić na żądania supersu</string>
<string name="auth_fingerprint">Uwierzytelnianie Odciskiem Palca</string>
<string name="multiuser_mode">Tryb Multiusera</string>
<string name="multiuser_mode">Tryb Multiusera</string>
<string name="settings_owner_only">Tylko Właściciel Urządzenia</string>
<string name="settings_owner_manage">Zarządzanie Właścicielami Urządzenia</string>
<string name="settings_user_independent">Niezależny Użytkownik</string>
@ -182,11 +181,10 @@
<string name="global_summary">Wszystkie sesje root za pomocą globalnej przestrzeni montowań nazw</string>
<string name="requester_summary">Sesje Root będzie dziedziczyć prośby i nazwy</string>
<string name="isolate_summary">W każdej sesji root będzie miał własną odosobnioną nazwę</string>
<string name="android_o_not_support">Brak wsparcia dla Androida 8.0+</string>
<string name="disable_fingerprint">Nie ustawiono żadnych odcisków palców lub brak obsługi urządzenia</string>
<string name="settings_download_path_error">Błąd podczas tworzenia folderu. Musi być dostępny z głównego katalogu pamięci i nie może być plikiem.</string>
<!--Superuser-->
<!--Superuser-->
<string name="su_request_title">Prośba o dostęp Superusera</string>
<string name="deny">Odmów</string>
<string name="prompt">Zapytaj</string>
@ -220,5 +218,5 @@
<!-- MagiskHide -->
<string name="show_system_app">Pokaż aplikacje systemowe</string>
</resources>

View File

@ -63,7 +63,6 @@
<string name="app_changelog">Registro de mudanças</string>
<!--Toasts, Dialogs-->
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Instalar %1$s agora?</string>
<string name="download">Baixar</string>
@ -153,7 +152,6 @@
<string name="global_summary">Todas as sessões root usam montagem de espaço de nome global</string>
<string name="requester_summary">As sessões root herdarão espaço de nome de seu solicitante</string>
<string name="isolate_summary">Cada sessão root terá seu próprio espaço de nome isolado</string>
<string name="android_o_not_support">Não suporta Android 8.0+</string>
<string name="disable_fingerprint">Nenhuma impressão digital foi definida ou o dispostivo não tem suporte</string>
<!--Superuser-->

View File

@ -53,7 +53,6 @@
<string name="app_changelog">Lista de alterações da aplicação</string>
<!--Toasts, Dialogs-->
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Deseja instalar%1$s agora?</string>
<string name="download">Transferir</string>

View File

@ -87,7 +87,6 @@
<string name="reboot_delay_toast">Repornire în 5 secunde…</string>
<!--Toasts, Dialogs-->
<string name="close">Închide</string>
<string name="repo_install_title">Instalează %1$s</string>
<string name="repo_install_msg">Vrei să instalezi acum %1$s?</string>
<string name="download">Descarcă</string>
@ -182,7 +181,6 @@
<string name="global_summary">Toate sesiunile de root folosesc spațiul de nume global.</string>
<string name="requester_summary">Sesiunile de root vor moșteni spațiul de nume al solicitantului.</string>
<string name="isolate_summary">Fiecare sesiune de root va avea propriul spațiu de nume izolat.</string>
<string name="android_o_not_support">Nu suportă Android 8.0+.</string>
<string name="disable_fingerprint">Nu au fost setate amprente sau scannerul de amprentă lipsește.</string>
<string name="settings_download_path_error">Eroare la crearea dosarului. Acesta trebuie să fie accesibil din directorul rădăcină al stocării și nu trebuie să fie un fișier.</string>

View File

@ -18,18 +18,18 @@
<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="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="recovery_mode">Режим Recovery</string>
<string name="current_installed">Установлена: %1$s</string>
<string name="latest_version">Последняя: %1$s</string>
<string name="keep_force_encryption">Не отключать шифрование /data</string>
<string name="keep_dm_verity">Не отключать AVB 2.0/dm-verity</string>
<string name="recovery_mode">Режим установки в recovery</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">Все модули будут отключены/удалены. Root-права будут удалены. Шифрование будет активировано.</string>
<string name="uninstall_magisk_msg">Все модули будут отключены/удалены!\nRoot-права будут удалены!\nШифрование будет активировано!</string>
<string name="update">Обновить</string>
<string name="core_only_enabled">(Активирован режим Magisk Core)</string>
@ -76,24 +76,23 @@
<string name="manager_update_title">Доступно обновление Magisk Manager!</string>
<!-- Installation -->
<string name="manager_download_install">Нажмите, чтобы загрузить и установить.</string>
<string name="download_zip_only">Загрузка установочного ZIP</string>
<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="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="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>
<string name="repo_install_msg">Установить %1$s ?</string>
<string name="download">Скачать</string>
<string name="reboot">Перезагрузка</string>
<string name="settings_reboot_toast">Для применения настроек перезагрузите устройство.</string>
<string name="settings_reboot_toast">Для применения настроек перезагрузите устройство</string>
<string name="release_notes">О версии</string>
<string name="repo_cache_cleared">Кэш репозитория очищен</string>
@ -102,9 +101,9 @@
<string name="flashing">Прошивка…</string>
<string name="done">Завершено!</string>
<string name="failure">Ошибка</string>
<string name="hide_manager_title">Маскировка Magisk Manager…</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="open_link_failed_toast">Не найдено приложений для открытия ссылки</string>
<string name="warning">Предупреждение</string>
<string name="complete_uninstall">Полное удаление</string>
<string name="restore_img">Восстановить разделы</string>
@ -112,8 +111,8 @@
<string name="restore_done">Восстановление завершено!</string>
<string name="restore_fail">Резервная копия отсутствует!</string>
<string name="proprietary_title">Загрузка SafetyNet</string>
<string name="proprietary_notice">Magisk Manager — свободно распространяемый продукт, он не содержит собственный код SafetyNet API от Google.\n\nРазрешить Magisk Manager загрузить расширение для проверки SafetyNet? (содержит GoogleApiClient)</string>
<string name="setup_fail">Ошибка установки.</string>
<string name="proprietary_notice">Magisk Manager — проект с открытым исходным кодом и не содержит проприетарный код SafetyNet API от Google.\n\nРазрешить Magisk Manager загрузить расширение для проверки SafetyNet? (содержит GoogleApiClient)</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>
@ -121,32 +120,36 @@
<!--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_dark_theme_summary">Включить тёмное оформление</string>
<string name="settings_download_path_title">Папка загрузки</string>
<string name="settings_download_path_message">Файлы будут загружаться в %1$s</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_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="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_check_update_summary">Периодически проверять наличие обновлений в фоновом режиме</string>
<string name="settings_update_channel_title">Источник обновлений</string>
<string name="settings_update_stable">Стабильный канал</string>
<string name="settings_update_beta">Beta канал</string>
<string name="settings_update_custom">Сторонний канал</string>
<string name="settings_update_custom_msg">Укажите ссылку</string>
<string name="settings_core_only_title">Magisk Core</string>
<string name="settings_core_only_summary">Активировать только основные возможности. Модули не будут загружены. MagiskSU и Magisk Hide останутся активными.</string>
<string name="settings_magiskhide_summary">Скрыть Magisk от различных обнаружений.</string>
<string name="settings_core_only_summary">Активировать только основные возможности. Модули не будут загружены. MagiskSU и Magisk Hide останутся активными</string>
<string name="settings_magiskhide_summary">Скрывать Magisk от различных обнаружений</string>
<string name="settings_hosts_title">Внесистемные хосты</string>
<string name="settings_hosts_summary">Поддержка внесистемных хостов для приложений, блокирующих рекламу.</string>
<string name="settings_hosts_summary">Поддержка внесистемных хостов для приложений, блокирующих рекламу</string>
<string name="settings_hosts_toast">Добавлен модуль внесистемных хостов</string>
<string name="settings_app_name">Укажите имя приложения</string>
<string name="settings_app_name_hint">Новое имя</string>
<string name="settings_app_name_helper">Приложение будет пересобрано с этим именем</string>
<string name="settings_app_name_error">Некорректный формат</string>
<string name="settings_su_app_adb">Приложения и ADB</string>
<string name="settings_su_app">Только приложения</string>
<string name="settings_su_adb">Только ADB</string>
@ -163,18 +166,18 @@
<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_reauth_summary">Повторный запрос прав суперпользователя после обновления приложений</string>
<string name="settings_su_fingerprint_title">Биометрическая аутентификация</string>
<string name="settings_su_fingerprint_summary">Использовать сканер отпечатков пальцев для запросов прав суперпользователя.</string>
<string name="auth_fingerprint">Аутентифицировать отпечаток пальца</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">Только владелец имеет Root-доступ.</string>
<string name="owner_manage_summary">Только владелец управляет Root-доступом и обрабатывает запросы.</string>
<string name="user_indepenent_summary">Каждый пользователь имеет свои собственные правила Root-доступа.</string>
<string name="owner_only_summary">Только владелец имеет Root-доступ</string>
<string name="owner_manage_summary">Только владелец управляет Root-доступом и обрабатывает запросы</string>
<string name="user_indepenent_summary">Каждый пользователь имеет свои собственные правила Root-доступа</string>
<string name="mount_namespace_mode">Настройка пространств имён</string>
<string name="settings_ns_global">Общее пространство имён</string>
@ -183,18 +186,17 @@
<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>
<string name="settings_download_path_error">Ошибка создания папки. Она должна быть доступна из корневой директории хранилища и не должна быть файлом.</string>
<!--Superuser-->
<string name="su_request_title">Запрос прав суперпользователя</string>
<string name="deny">Отказать</string>
<string name="deny">Запретить</string>
<string name="prompt">Запрос</string>
<string name="grant">Предоставить</string>
<string name="su_warning">Предоставить полный доступ к устройству.\nЕсли не уверены - отклоните данное действие!</string>
<string name="grant">Разрешить</string>
<string name="su_warning">Разрешить полный доступ к устройству?\nЕсли не уверены - отклоните данное действие!</string>
<string name="forever">Навсегда</string>
<string name="once">Сейчас</string>
<string name="once">Единожды</string>
<string name="tenmin">10 мин.</string>
<string name="twentymin">20 мин.</string>
<string name="thirtymin">30 мин.</string>
@ -220,6 +222,6 @@
<string name="command">Команда: %1$s</string>
<!-- MagiskHide -->
<string name="show_system_app">Показать системные приложения</string>
<string name="show_system_app">Системные приложения</string>
</resources>

View File

@ -72,7 +72,6 @@
<string name="manager_update_title">Je dostupná aktualizácia Magisk Manager!</string>
<!--Toasts, Dialogs-->
<string name="close">Zavrieť</string>
<string name="repo_install_title">Nainštalovať %1$s</string>
<string name="repo_install_msg">Chcete teraz nainštalovať %1$s?</string>
<string name="download">Stiahnuť</string>
@ -167,7 +166,6 @@
<string name="global_summary">Všetky relácie root použijú globálne mount namespace</string>
<string name="requester_summary">Relácie root zdedia namespace od požadovateľa</string>
<string name="isolate_summary">Každá relácia root bude mať vlastný izolovaný namespace</string>
<string name="android_o_not_support">Nepodporuje Android 8.0+</string>
<string name="disable_fingerprint">Neboli odoslané žiadne odtlačky prsta alebo ich zariadenie nepodporuje</string>
<!--Superuser-->

View File

@ -55,7 +55,6 @@
<string name="app_changelog">Дневник промена апликације</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>

View File

@ -53,7 +53,6 @@
<string name="app_changelog">Ändringslogg</string>
<!--Toasts, Dialogs-->
<string name="close">Stäng</string>
<string name="repo_install_title">Installera %1$s</string>
<string name="repo_install_msg">Vill du installera %1$s ?</string>
<string name="download">Ladda ner</string>
@ -62,7 +61,7 @@
<string name="settings_reboot_toast">Starta om för att tillämpa inställningar</string>
<string name="release_notes">Release notes</string>
<string name="repo_cache_cleared">Repo-cache rensad</string>
<string name="manager_update_title">En uppdatering av Magisk maneger finns tillgänglig!</string>
<string name="manager_update_title">En uppdatering av Magisk Manager finns tillgänglig!</string>
<string name="manager_download_install">Tryck för att ladda ner och installera</string>
<string name="update_channel">Magiska uppdateringar</string>
<string name="download_file_error">Fel vid nerladdning av fil</string>

View File

@ -69,7 +69,6 @@
<string name="manager_update_title">มีการอัพเดต Magisk Manager!</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>
@ -166,7 +165,6 @@
<string name="global_summary">All root sessions use the global mount namespace.</string>
<string name="requester_summary">Root sessions will inherit their requester\'s namespace.</string>
<string name="isolate_summary">Each root session will have its own isolated namespace.</string>
<string name="android_o_not_support">ไม่รองรับ Android 8.0 ขึ้นไป</string>
<string name="disable_fingerprint">ไม่มีลายนิ้วมือหรืออุปกรณ์แสกน</string>
<!--Superuser-->

View File

@ -88,7 +88,6 @@
<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>
<string name="repo_install_msg">%1$s yüklensin mi?</string>
<string name="download">İndir</string>
@ -147,6 +146,10 @@
<string name="settings_hosts_summary">Reklam engelleme uygulamaları için sistemsiz host desteği</string>
<string name="settings_hosts_toast">Sistemsiz host modülü eklendi</string>
<string name="settings_app_name">İstediğiniz uygulama adını yazın</string>
<string name="settings_app_name_hint">Yeni ad</string>
<string name="settings_app_name_helper">Uygulama bu ad ile yeniden paketlenecek</string>
<string name="settings_app_name_error">Geçersiz format</string>
<string name="settings_su_app_adb">Uygulamalar ve ADB</string>
<string name="settings_su_app">Sadece uygulamalar</string>
<string name="settings_su_adb">Sadece ADB</string>
@ -183,9 +186,8 @@
<string name="global_summary">Tüm kök oturumları genel bağlama ad alanını kullanır</string>
<string name="requester_summary">Kök oturumları, istekte bulunanın ad alanını devralır</string>
<string name="isolate_summary">Her bir kök oturumunun kendi izole ad alanı olacaktır</string>
<string name="android_o_not_support">Android 8.0 ve üzerinde desteklenmiyor</string>
<string name="disable_fingerprint">Parmak izi ayarlanmadı veya cihaz desteği yok</string>
<string name="settings_download_path_error">Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır.</string>
<string name="settings_download_path_error">Klasör oluşturma hatası. Depolama kök dizininden erişilebilir olmalı ve bir dosya olmamalıdır.</string>
<!--Superuser-->
<string name="su_request_title">Yetkili Kullanıcı İsteği</string>

View File

@ -88,7 +88,6 @@
<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>
@ -106,8 +105,8 @@
<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">Відновити образи</string>
<string name="complete_uninstall">Повне видалення</string>
<string name="restore_img">Відновити розділи</string>
<string name="restore_img_msg">Відновлення…</string>
<string name="restore_done">Відновлення завершено!</string>
<string name="restore_fail">Немає резервної копії оригінального boot образу</string>
@ -140,13 +139,17 @@
<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</string>
<string name="settings_core_only_title">Режим Magisk Core</string>
<string name="settings_core_only_summary">Увімкнути тільки можливості ядра. MagiskSU i Magisk Hide залишуться увімкненими, проте ніякі модулі не будуть завантажені.</string>
<string name="settings_magiskhide_summary">Приховати Magisk від різних форм виявлень.</string>
<string name="settings_hosts_title">Позасистемні хости</string>
<string name="settings_hosts_summary">Підтримка позасистемних хостів для програм блокування реклами.</string>
<string name="settings_hosts_toast">Додано модуль позасистемних хостів</string>
<string name="settings_app_name">Введіть бажане ім\'я застосунку</string>
<string name="settings_app_name_hint">Нове ім\'я</string>
<string name="settings_app_name_helper">Застосунок буде перезібрано з цим ім\'ям</string>
<string name="settings_app_name_error">Неправильний формат</string>
<string name="settings_su_app_adb">Програми і ADB</string>
<string name="settings_su_app">Програми</string>
<string name="settings_su_adb">ADB</string>
@ -183,7 +186,6 @@
<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>
<string name="settings_download_path_error">Помилка створення папки. Вона повинна бути доступна з кореневої директорії сховища і не повинна бути файлом.</string>

View File

@ -61,7 +61,6 @@
<string name="app_changelog">Nhật ký thay đổi của ứng dụng</string>
<!--Toasts, Dialogs-->
<string name="close">Đóng</string>
<string name="repo_install_title">Cài đặt %1$s</string>
<string name="repo_install_msg">Bạn muốn cài đặt %1$s ?</string>
<string name="download">Tải xuống</string>
@ -159,7 +158,6 @@
<string name="global_summary">Tất cả các phiên root sử dụng không gian tên gắn kết chung.</string>
<string name="requester_summary">Các phiên root sẽ kế thừa không gian tên của người yêu cầu.</string>
<string name="isolate_summary">Mỗi phiên root sẽ có không gian tên riêng biệt.</string>
<string name="android_o_not_support">Không hỗ trợ Android 8.0+.</string>
<string name="disable_fingerprint">Không có dấu vân tay nào được thiết lập hoặc thiết bị không hỗ trợ.</string>
<!--Superuser-->

View File

@ -88,12 +88,11 @@
<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="settings_reboot_toast">重启设备以应用设置</string>
<string name="release_notes">发布说明</string>
<string name="repo_cache_cleared">仓库缓存已清除</string>
@ -147,6 +146,10 @@
<string name="settings_hosts_summary">为广告屏蔽应用提供 Systemless hosts 支持</string>
<string name="settings_hosts_toast">已添加 systemless hosts 模块</string>
<string name="settings_app_name">输入想要的应用名称</string>
<string name="settings_app_name_hint">新名称</string>
<string name="settings_app_name_helper">新应用将使用此名称</string>
<string name="settings_app_name_error">输入无效</string>
<string name="settings_su_app_adb">应用和 ADB</string>
<string name="settings_su_app">仅应用</string>
<string name="settings_su_adb">仅 ADB</string>
@ -183,7 +186,6 @@
<string name="global_summary">所有的 ROOT 会话使用全局挂载命名空间</string>
<string name="requester_summary">ROOT 会话继承原程序的命名空间</string>
<string name="isolate_summary">每一个 ROOT 会话使用自己独立的命名空间</string>
<string name="android_o_not_support">不支持 Android 8.0+</string>
<string name="disable_fingerprint">没有设置指纹或设备不支持</string>
<string name="settings_download_path_error">创建文件夹出错。路径需要位于内部存储空间,并且不能有同名文件。</string>

View File

@ -84,7 +84,6 @@
<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>
@ -177,7 +176,6 @@
<string name="global_summary">所有 Root 工作階段皆使用全域 Namespace</string>
<string name="requester_summary">所有 Root 工作階段皆繼承原程式 Namespace</string>
<string name="isolate_summary">所有 Root 工作階段個別擁有獨立 Namespace</string>
<string name="android_o_not_support">不支援 Android 8.0 及更新版本</string>
<string name="disable_fingerprint">未設定指紋或無指紋辨識器</string>
<!--Superuser-->

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Static strings -->
<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"/>
</resources>

View File

@ -18,7 +18,7 @@
<string name="checking_safetyNet_status">Checking SafetyNet status…</string>
<string name="safetyNet_check_success">SafetyNet Check Success</string>
<string name="safetyNet_api_error">SafetyNet API Error</string>
<string name="safetyNet_res_invalid">The response is invalid.</string>
<string name="safetyNet_res_invalid">The response is invalid</string>
<string name="magisk_up_to_date">Magisk is up to date</string>
<string name="manager_up_to_date">Magisk Manager is up to date</string>
<string name="advanced_settings_title">Advanced Settings</string>
@ -29,7 +29,7 @@
<string name="latest_version">Latest: %1$s</string>
<string name="uninstall">Uninstall</string>
<string name="uninstall_magisk_title">Uninstall Magisk</string>
<string name="uninstall_magisk_msg">All modules will be disabled/removed. Root will be removed, and your data potentially encrypted if not already.</string>
<string name="uninstall_magisk_msg">All modules will be disabled/removed!\nRoot will be removed!\nYour data potentially encrypted if not already!</string>
<string name="update">Update</string>
<string name="core_only_enabled">(Core only mode enabled)</string>
@ -76,7 +76,7 @@
<string name="manager_update_title">Magisk Manager Update Available!</string>
<!-- Installation -->
<string name="manager_download_install">Press to download and install.</string>
<string name="manager_download_install">Press to download and install</string>
<string name="download_zip_only">Download Zip Only</string>
<string name="direct_install">Direct Install (Recommended)</string>
<string name="install_inactive_slot">Install to Inactive Slot (After OTA)</string>
@ -88,12 +88,11 @@
<string name="reboot_delay_toast">Rebooting in 5 seconds…</string>
<!--Toasts, Dialogs-->
<string name="close">Close</string>
<string name="repo_install_title">Install %1$s</string>
<string name="repo_install_msg">Do you want to install %1$s now?</string>
<string name="download">Download</string>
<string name="reboot">Reboot</string>
<string name="settings_reboot_toast">Reboot to apply settings.</string>
<string name="settings_reboot_toast">Reboot to apply settings</string>
<string name="release_notes">Release notes</string>
<string name="repo_cache_cleared">Repo cache cleared</string>
@ -104,7 +103,7 @@
<string name="failure">Failed</string>
<string name="hide_manager_title">Hiding Magisk Manager…</string>
<string name="hide_manager_fail_toast">Hide Magisk Manager failed.</string>
<string name="open_link_failed_toast">No application found to open the link.</string>
<string name="open_link_failed_toast">No application found to open the link</string>
<string name="warning">Warning</string>
<string name="complete_uninstall">Complete Uninstall</string>
<string name="restore_img">Restore Images</string>
@ -113,7 +112,7 @@
<string name="restore_fail">Stock backup does not exist!</string>
<string name="proprietary_title">Download Proprietary Code</string>
<string name="proprietary_notice">Magisk Manager is FOSS and doesn\'t contain Google\'s proprietary SafetyNet API code.\n\nWill you allow Magisk Manager to download an extension (contains GoogleApiClient) for SafetyNet checks?</string>
<string name="setup_fail">Setup failed.</string>
<string name="setup_fail">Setup failed</string>
<string name="env_fix_title">Requires Additional Setup</string>
<string name="env_fix_msg">Your device needs additional setup for Magisk to work properly. It will download the Magisk setup zip, do you want to proceed now?</string>
<string name="setup_msg">Running environment setup…</string>
@ -121,32 +120,36 @@
<!--Settings Activity -->
<string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Dark Theme</string>
<string name="settings_dark_theme_summary">Enable dark theme.</string>
<string name="settings_dark_theme_summary">Enable dark theme</string>
<string name="settings_download_path_title">Download path</string>
<string name="settings_download_path_message">Files will be saved to %1$s</string>
<string name="settings_clear_cache_title">Clear Repo Cache</string>
<string name="settings_clear_cache_summary">Clear the cached information for online repos. This forces the app to refresh online.</string>
<string name="settings_clear_cache_summary">Clear the cached information for online repos. This forces the app to refresh online</string>
<string name="settings_hide_manager_title">Hide Magisk Manager</string>
<string name="settings_hide_manager_summary">Repackage Magisk Manager with random package name.</string>
<string name="settings_hide_manager_summary">Repackage Magisk Manager with random package and app names</string>
<string name="settings_restore_manager_title">Restore Magisk Manager</string>
<string name="settings_restore_manager_summary">Restore Magisk Manager with original package</string>
<string name="settings_restore_manager_summary">Restore Magisk Manager with original package and app names</string>
<string name="language">Language</string>
<string name="system_default">(System Default)</string>
<string name="settings_update">Update Settings</string>
<string name="settings_check_update_title">Check Updates</string>
<string name="settings_check_update_summary">Periodically check for updates in the background.</string>
<string name="settings_check_update_summary">Periodically check for updates in the background</string>
<string name="settings_update_channel_title">Update Channel</string>
<string name="settings_update_stable">Stable</string>
<string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Custom</string>
<string name="settings_update_custom_msg">Insert a custom URL</string>
<string name="settings_core_only_title">Magisk Core Only Mode</string>
<string name="settings_core_only_summary">Enable only core features. MagiskSU and MagiskHide will still be enabled, but no modules will be loaded.</string>
<string name="settings_magiskhide_summary">Hide Magisk from various forms of detection.</string>
<string name="settings_core_only_summary">Enable only core features. MagiskSU and MagiskHide will still be enabled, but no modules will be loaded</string>
<string name="settings_magiskhide_summary">Hide Magisk from various forms of detection</string>
<string name="settings_hosts_title">Systemless hosts</string>
<string name="settings_hosts_summary">Systemless hosts support for Adblock apps.</string>
<string name="settings_hosts_summary">Systemless hosts support for Adblock apps</string>
<string name="settings_hosts_toast">Added systemless hosts module</string>
<string name="settings_app_name">Type desired app name</string>
<string name="settings_app_name_hint">New name</string>
<string name="settings_app_name_helper">App will be repackaged to this name</string>
<string name="settings_app_name_error">Invalid format</string>
<string name="settings_su_app_adb">Apps and ADB</string>
<string name="settings_su_app">Apps only</string>
<string name="settings_su_adb">ADB only</string>
@ -172,19 +175,18 @@
<string name="settings_owner_only">Device Owner Only</string>
<string name="settings_owner_manage">Device Owner Managed</string>
<string name="settings_user_independent">User-Independent</string>
<string name="owner_only_summary">Only owner has root access.</string>
<string name="owner_manage_summary">Only owner can manage root access and receive request prompts.</string>
<string name="user_indepenent_summary">Each user has his/her own separate root rules.</string>
<string name="owner_only_summary">Only owner has root access</string>
<string name="owner_manage_summary">Only owner can manage root access and receive request prompts</string>
<string name="user_indepenent_summary">Each user has his/her own separate root rules</string>
<string name="mount_namespace_mode">Mount Namespace Mode</string>
<string name="settings_ns_global">Global Namespace</string>
<string name="settings_ns_requester">Inherit Namespace</string>
<string name="settings_ns_isolate">Isolated Namespace</string>
<string name="global_summary">All root sessions use the global mount namespace.</string>
<string name="requester_summary">Root sessions will inherit their requester\'s namespace.</string>
<string name="isolate_summary">Each root session will have its own isolated namespace.</string>
<string name="android_o_not_support">Does not support Android 8.0+.</string>
<string name="disable_fingerprint">No fingerprints were set or no device support.</string>
<string name="global_summary">All root sessions use the global mount namespace</string>
<string name="requester_summary">Root sessions will inherit their requester\'s namespace</string>
<string name="isolate_summary">Each root session will have its own isolated namespace</string>
<string name="disable_fingerprint">No fingerprints were set or no device support</string>
<string name="settings_download_path_error">Error creating folder. It must be accessible from storage root directory and must not be a file.</string>
<!--Superuser-->

View File

@ -62,7 +62,7 @@ subprojects {
android {
signingConfigs {
config {
storeFile rootProject.file('release-key.jks')
storeFile new File(props['keyStore'])
storePassword props['keyStorePass']
keyAlias props['keyAlias']
keyPassword props['keyPass']
@ -85,13 +85,12 @@ subprojects {
}
aaptOptions {
// Preserve stub resource IDs
File publicTxt = rootProject.file('stub-public.txt')
if (publicTxt.exists()) {
additionalParameters "--stable-ids", "${publicTxt.absolutePath}"
} else if (module.name == 'stub') {
additionalParameters "--emit-ids", "${publicTxt.absolutePath}"
}
// Handle resource IDs
File resId = project.file('res-ids.txt')
if (resId.exists())
additionalParameters "--stable-ids", "${resId.absolutePath}"
else
additionalParameters "--emit-ids", "${resId.absolutePath}"
}
}
}

158
build.py
View File

@ -3,7 +3,8 @@ import sys
import os
import subprocess
if os.name == 'nt':
is_windows = os.name == 'nt'
if is_windows:
import colorama
colorama.init()
@ -44,6 +45,7 @@ import shutil
import lzma
import tempfile
# Constants
if 'ANDROID_NDK_HOME' in os.environ:
ndk_build = os.path.join(os.environ['ANDROID_NDK_HOME'], 'ndk-build')
else:
@ -51,14 +53,16 @@ else:
os.environ['ANDROID_HOME'], 'ndk-bundle', 'ndk-build')
cpu_count = multiprocessing.cpu_count()
gradlew = os.path.join('.', 'gradlew' + ('.bat' if os.name == 'nt' else ''))
gradlew = os.path.join('.', 'gradlew' + ('.bat' if is_windows else ''))
archs = ['armeabi-v7a', 'x86']
arch64 = ['arm64-v8a', 'x86_64']
keystore = 'release-key.jks'
config = {}
support_targets = ['magisk', 'magiskinit', 'magiskboot', 'magiskpolicy', 'busybox', 'test']
default_targets = ['magisk', 'magiskinit', 'magiskboot', 'busybox']
build_tools = os.path.join(os.environ['ANDROID_HOME'], 'build-tools', '29.0.2')
# Global vars
config = {}
STDOUT = None
def mv(source, target):
try:
@ -96,18 +100,56 @@ def mkdir_p(path, mode=0o777):
os.makedirs(path, mode, exist_ok=True)
def execv(cmd, redirect=None):
return subprocess.run(cmd, stdout=redirect if redirect != None else STDOUT)
def execv(cmd):
return subprocess.run(cmd, stdout=STDOUT)
def system(cmd, redirect=None):
return subprocess.run(cmd, shell=True, stdout=redirect if redirect != None else STDOUT)
def system(cmd):
return subprocess.run(cmd, shell=True, stdout=STDOUT)
def xz(data):
return lzma.compress(data, preset=9, check=lzma.CHECK_NONE)
def load_config(args):
# Some default values
config['outdir'] = 'out'
config['prettyName'] = 'false'
config['keyStore'] = 'release-key.jks'
# Load prop file
if not os.path.exists(args.config):
error(f'Please make sure {args.config} existed')
with open(args.config, 'r') as f:
for line in [l.strip(' \t\r\n') for l in f]:
if line.startswith('#') or len(line) == 0:
continue
prop = line.split('=')
if len(prop) != 2:
continue
config[prop[0].strip(' \t\r\n')] = prop[1].strip(' \t\r\n')
config['prettyName'] = config['prettyName'].lower() == 'true'
# Sanitize configs
if 'version' not in config or 'versionCode' not in config:
error('Config error: "version" and "versionCode" is required')
try:
config['versionCode'] = int(config['versionCode'])
except ValueError:
error('Config error: "versionCode" is required to be an integer')
if args.release and not os.path.exists(config['keyStore']):
error(f'Config error: assign "keyStore" to a java keystore')
mkdir_p(config['outdir'])
global STDOUT
STDOUT = None if args.verbose else subprocess.DEVNULL
def zip_with_msg(zip_file, source, target):
if not os.path.exists(source):
error(f'{source} does not exist! Try build \'binary\' and \'apk\' before zipping!')
@ -125,12 +167,13 @@ def collect_binary():
def clean_elf():
if os.name == 'nt':
if is_windows:
elf_cleaner = os.path.join('tools', 'elf-cleaner.exe')
else:
elf_cleaner = os.path.join('native', 'out', 'elf-cleaner')
if not os.path.exists(elf_cleaner):
execv(['g++', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp', '-o', elf_cleaner])
if not os.path.exists(elf_cleaner):
execv(['g++', 'tools/termux-elf-cleaner/termux-elf-cleaner.cpp',
'-o', elf_cleaner])
args = [elf_cleaner]
args.extend(os.path.join('native', 'out', arch, 'magisk') for arch in archs + arch64)
execv(args)
@ -152,7 +195,7 @@ def sign_zip(unsigned, output, release):
header('* Signing Zip')
proc = execv(['java', '-jar', zipsigner, keystore, config['keyStorePass'],
proc = execv(['java', '-jar', zipsigner, config['keyStore'], config['keyStorePass'],
config['keyAlias'], config['keyPass'], unsigned, output])
if proc.returncode != 0:
@ -259,14 +302,47 @@ def build_apk(args, module):
proc = execv([gradlew, f'{module}:assemble{build_type}',
'-PconfigPath=' + os.path.abspath(args.config)])
if proc.returncode != 0:
error('Build Magisk Manager failed!')
error(f'Build {module} failed!')
build_type = build_type.lower()
apk = f'{module}-{build_type}.apk'
source = os.path.join(module, 'build', 'outputs', 'apk', build_type, apk)
target = os.path.join(config['outdir'], apk)
mv(source, target)
if args.release:
zipalign = os.path.join(build_tools, 'zipalign' + ('.exe' if is_windows else ''))
aapt2 = os.path.join(build_tools, 'aapt2' + ('.exe' if is_windows else ''))
apksigner = os.path.join(build_tools, 'apksigner' + ('.bat' if is_windows else ''))
try:
with tempfile.NamedTemporaryFile(delete=False) as f:
tmp = f.name
# AAPT2 optimization
execv([aapt2, 'optimize', '-o', tmp, '--enable-resource-obfuscation',
'--enable-resource-path-shortening', source])
# Recompress everything just to piss people off
with zipfile.ZipFile(source, 'w', compression=zipfile.ZIP_DEFLATED) as zout:
with zipfile.ZipFile(tmp) as zin:
for e in zin.namelist():
zout.writestr(e, zin.read(e))
# Zipalign
execv([zipalign, '-fz', '4', source, target])
# Sign APK
execv([apksigner, 'sign', '--v1-signer-name', 'CERT',
'--ks', config['keyStore'],
'--ks-pass', f'pass:{config["keyStorePass"]}',
'--ks-key-alias', config['keyAlias'],
'--key-pass', f'pass:{config["keyPass"]}', target])
finally:
rm(tmp)
rm(source)
else:
mv(source, target)
header('Output: ' + target)
return target
@ -309,7 +385,8 @@ def build_snet(args):
def zip_main(args):
header('* Packing Flashable Zip')
unsigned = tempfile.mkstemp()[1]
with tempfile.NamedTemporaryFile(delete=False) as f:
unsigned = f.name
with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# update-binary
@ -367,13 +444,15 @@ def zip_main(args):
output = os.path.join(config['outdir'], f'Magisk-v{config["version"]}.zip' if config['prettyName'] else
'magisk-release.zip' if args.release else 'magisk-debug.zip')
sign_zip(unsigned, output, args.release)
rm(unsigned)
header('Output: ' + output)
def zip_uninstaller(args):
header('* Packing Uninstaller Zip')
unsigned = tempfile.mkstemp()[1]
with tempfile.NamedTemporaryFile(delete=False) as f:
unsigned = f.name
with zipfile.ZipFile(unsigned, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=False) as zipf:
# update-binary
@ -412,6 +491,7 @@ def zip_uninstaller(args):
output = os.path.join(config['outdir'], f'Magisk-uninstaller-{datestr}.zip'
if config['prettyName'] else 'magisk-uninstaller.zip')
sign_zip(unsigned, output, args.release)
rm(unsigned)
header('Output: ' + output)
@ -444,28 +524,28 @@ def build_all(args):
parser = argparse.ArgumentParser(description='Magisk build script')
parser.add_argument('-r', '--release', action='store_true',
help='compile Magisk for release')
help='compile in release mode')
parser.add_argument('-v', '--verbose', action='store_true',
help='verbose output')
parser.add_argument('-c', '--config', default='config.prop',
help='config file location')
help='override config file (default: config.prop)')
subparsers = parser.add_subparsers(title='actions')
all_parser = subparsers.add_parser(
'all', help='build everything (binaries/apks/zips)')
'all', help='build binaries, apks, zips')
all_parser.set_defaults(func=build_all)
binary_parser = subparsers.add_parser('binary', help='build binaries')
binary_parser.add_argument(
'target', nargs='*', help=f"Either {', '.join(support_targets)}, \
'target', nargs='*', help=f"{', '.join(support_targets)}, \
or empty for defaults ({', '.join(default_targets)})")
binary_parser.set_defaults(func=build_binary)
apk_parser = subparsers.add_parser('apk', help='build Magisk Manager APK')
apk_parser.set_defaults(func=build_app)
app_parser = subparsers.add_parser('app', help='build Magisk Manager')
app_parser.set_defaults(func=build_app)
stub_parser = subparsers.add_parser(
'stub', help='build stub Magisk Manager APK')
'stub', help='build stub Magisk Manager')
stub_parser.set_defaults(func=build_stub)
snet_parser = subparsers.add_parser(
@ -480,9 +560,9 @@ un_parser = subparsers.add_parser(
'uninstaller', help='create flashable uninstaller')
un_parser.set_defaults(func=zip_uninstaller)
clean_parser = subparsers.add_parser('clean', help='cleanup.')
clean_parser = subparsers.add_parser('clean', help='cleanup')
clean_parser.add_argument(
'target', nargs='*', help='Either native, java, or empty to clean both.')
'target', nargs='*', help='native, java, or empty to clean both')
clean_parser.set_defaults(func=cleanup)
if len(sys.argv) == 1:
@ -490,33 +570,7 @@ if len(sys.argv) == 1:
sys.exit(1)
args = parser.parse_args()
# Some default values
config['outdir'] = 'out'
config['prettyName'] = 'false'
with open(args.config, 'r') as f:
for line in [l.strip(' \t\r\n') for l in f]:
if line.startswith('#') or len(line) == 0:
continue
prop = line.split('=')
config[prop[0].strip(' \t\r\n')] = prop[1].strip(' \t\r\n')
if 'version' not in config or 'versionCode' not in config:
error('"version" and "versionCode" is required in "config.prop"')
try:
config['versionCode'] = int(config['versionCode'])
except ValueError:
error('"versionCode" is required to be an integer')
config['prettyName'] = config['prettyName'].lower() == 'true'
mkdir_p(config['outdir'])
if args.release and not os.path.exists(keystore):
error(f'Please generate a java keystore and place it in "{keystore}"')
STDOUT = None if args.verbose else subprocess.DEVNULL
load_config(args)
# Call corresponding functions
args.func(args)

View File

@ -13,8 +13,9 @@ outdir=out
prettyName=false
# Only used when building with release flag
# These passwords are used along with release-key.jks to sign APKs and zips
# These passwords are used along with keyStore to sign APKs and zips
# keyPass is the pwd for the specified keyAlias
keyStore=release-key.jks
keyStorePass=
keyAlias=
keyPass=

View File

@ -1,4 +1,4 @@
# Magisk Documentations
# Magisk Documentation
(Updated on 2019.9.19)
- [Installation](install.md)
@ -6,7 +6,7 @@
- [OTA Installation](tutorials.md#ota-installation)
- [Best Practices for MagiskHide](tutorials.md#best-practices-for-magiskhide)
The followings are for developers
The following sections are for developers
- [Magisk Details](details.md)
- [Magisk Tools](tools.md)

View File

@ -54,6 +54,7 @@ static void *request_handler(void *args) {
case BOOT_COMPLETE:
case SQLITE_CMD:
case BROADCAST_ACK:
case BROADCAST_TEST:
if (credential.uid != 0) {
write_int(client, ROOT_REQUIRED);
close(client);
@ -91,9 +92,10 @@ static void *request_handler(void *args) {
exec_sql(client);
break;
case BROADCAST_ACK:
LOGD("* Use broadcasts for su logging and notify\n");
CONNECT_BROADCAST = true;
close(client);
broadcast_ack(client);
break;
case BROADCAST_TEST:
broadcast_test(client);
break;
case REMOVE_MODULES:
if (credential.uid == UID_SHELL || credential.uid == UID_ROOT) {

View File

@ -219,7 +219,6 @@ int get_db_strings(db_strings &str, int key) {
char *err;
auto string_cb = [&](db_row &row) -> bool {
str[row["key"]] = row["value"];
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
return true;
};
if (key >= 0) {
@ -273,6 +272,7 @@ int validate_manager(string &alt_pkg, int userid, struct stat *st) {
}
void exec_sql(int client) {
run_finally f([=]{ close(client); });
char *sql = read_string(client);
char *err = db_exec(sql, [&](db_row &row) -> bool {
string out;
@ -289,9 +289,6 @@ void exec_sql(int client) {
return true;
});
free(sql);
db_err_cmd(err,
write_int(client, 0);
return;
);
close(client);
write_int(client, 0);
db_err_cmd(err, return; );
}

View File

@ -9,7 +9,6 @@
#include <magisk.h>
#include <daemon.h>
#include <selinux.h>
#include <db.h>
#include <flags.h>
using namespace std::literals;
@ -36,7 +35,8 @@ Advanced Options (Internal APIs):
--clone-attr SRC DEST clone permission, owner, and selinux context
--clone SRC DEST clone SRC to DEST
--sqlite SQL exec SQL commands to Magisk database
--use-broadcast use broadcast for su logging and notify
--connect-mode [MODE] get/set connect mode for su request and notify
--broadcast-test manually trigger broadcast tests
Supported init triggers:
post-fs-data, service, boot-complete
@ -79,12 +79,10 @@ int magisk_main(int argc, char *argv[]) {
restore_rootcon();
restorecon();
return 0;
} else if (argv[1] == "--clone-attr"sv) {
if (argc < 4) usage();
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
clone_attr(argv[2], argv[3]);
return 0;
} else if (argv[1] == "--clone"sv) {
if (argc < 4) usage();
} else if (argc >= 4 && argv[1] == "--clone"sv) {
cp_afc(argv[2], argv[3]);
return 0;
} else if (argv[1] == "--daemon"sv) {
@ -103,7 +101,7 @@ int magisk_main(int argc, char *argv[]) {
int fd = connect_daemon(true);
write_int(fd, BOOT_COMPLETE);
return read_int(fd);
} else if (argv[1] == "--sqlite"sv) {
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
int fd = connect_daemon();
write_int(fd, SQLITE_CMD);
write_string(fd, argv[2]);
@ -115,14 +113,23 @@ int magisk_main(int argc, char *argv[]) {
printf("%s\n", res);
free(res);
}
} else if (argv[1] == "--use-broadcast"sv) {
} else if (argv[1] == "--connect-mode"sv) {
int fd = connect_daemon();
write_int(fd, BROADCAST_ACK);
return 0;
if (argc >= 3) {
write_int(fd, parse_int(argv[2]));
} else {
write_int(fd, -1);
}
return read_int(fd);
} else if (argv[1] == "--remove-modules"sv) {
int fd = connect_daemon();
write_int(fd, REMOVE_MODULES);
return read_int(fd);
} else if (argv[1] == "--broadcast-test"sv) {
int fd = connect_daemon();
write_int(fd, BROADCAST_TEST);
return read_int(fd);
}
#if 0
/* Entry point for testing stuffs */

View File

@ -19,6 +19,7 @@ enum {
SQLITE_CMD,
BROADCAST_ACK,
REMOVE_MODULES,
BROADCAST_TEST,
};
// Return codes for daemon
@ -84,10 +85,13 @@ void magiskhide_handler(int client);
*************/
void su_daemon_handler(int client, struct ucred *credential);
void broadcast_test();
void broadcast_test(int client = -1);
void broadcast_ack(int client);
/*********************
* Daemon Global Vars
*********************/
extern int SDK_INT;
extern bool RECOVERY_MODE;
extern bool CONNECT_BROADCAST;
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")

Some files were not shown because too many files have changed in this diff Show More