Commit f11bb609 authored by Viktor De Pasquale's avatar Viktor De Pasquale

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
parents b910a927 5e87483f
...@@ -2,8 +2,8 @@ out ...@@ -2,8 +2,8 @@ out
*.zip *.zip
*.jks *.jks
*.apk *.apk
config.prop /config.prop
update.sh /update.sh
# Built binaries # Built binaries
native/out native/out
......
...@@ -30,12 +30,12 @@ Furthermore, Magisk provides a **Systemless Interface** to alter the system (or ...@@ -30,12 +30,12 @@ Furthermore, Magisk provides a **Systemless Interface** to alter the system (or
## Translations ## 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` - `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 ## Signature Verification
......
...@@ -75,7 +75,7 @@ dependencies { ...@@ -75,7 +75,7 @@ dependencies {
implementation "${bindingAdapter}:${vBAdapt}" implementation "${bindingAdapter}:${vBAdapt}"
implementation "${bindingAdapter}-recyclerview:${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:core:${vMarkwon}"
implementation "io.noties.markwon:html:${vMarkwon}" implementation "io.noties.markwon:html:${vMarkwon}"
implementation "io.noties.markwon:image:${vMarkwon}" implementation "io.noties.markwon:image:${vMarkwon}"
...@@ -112,7 +112,7 @@ dependencies { ...@@ -112,7 +112,7 @@ dependencies {
replacedBy('com.github.topjohnwu:room-runtime') replacedBy('com.github.topjohnwu:room-runtime')
} }
} }
def vRoom = "2.2.0" def vRoom = "2.2.1"
implementation "com.github.topjohnwu:room-runtime:${vRoom}" implementation "com.github.topjohnwu:room-runtime:${vRoom}"
kapt "androidx.room:room-compiler:${vRoom}" kapt "androidx.room:room-compiler:${vRoom}"
...@@ -124,9 +124,10 @@ dependencies { ...@@ -124,9 +124,10 @@ dependencies {
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03'
implementation 'androidx.browser:browser:1.0.0' implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.preference:preference:1.1.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.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.multidex:multidex:2.0.1'
implementation 'androidx.core:core-ktx:1.1.0' implementation 'androidx.core:core-ktx:1.1.0'
implementation 'com.google.android.material:material:1.1.0-beta01' implementation 'com.google.android.material:material:1.1.0-beta01'
......
...@@ -32,7 +32,11 @@ ...@@ -32,7 +32,11 @@
-keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker -keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker
# BootSigner # 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 # Strip logging
-assumenosideeffects class timber.log.Timber.Tree { *; } -assumenosideeffects class timber.log.Timber.Tree { *; }
......
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
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
<activity <activity
android:name="a.m" android:name="a.m"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:directBootAware="true" android:directBootAware="true"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:exported="false" /> android:exported="false" />
...@@ -88,6 +89,7 @@ ...@@ -88,6 +89,7 @@
android:name="a.h" android:name="a.h"
android:directBootAware="true"> android:directBootAware="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.REBOOT" />
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCALE_CHANGED" /> <action android:name="android.intent.action.LOCALE_CHANGED" />
</intent-filter> </intent-filter>
...@@ -110,6 +112,12 @@ ...@@ -110,6 +112,12 @@
android:name="com.google.android.gms.version" android:name="com.google.android.gms.version"
android:value="12451000" /> android:value="12451000" />
<!-- Initialize WorkManager on-demand -->
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
tools:node="remove" />
</application> </application>
</manifest> </manifest>
package a; package a;
import androidx.annotation.Keep;
import androidx.core.app.AppComponentFactory; import androidx.core.app.AppComponentFactory;
import com.topjohnwu.magisk.utils.PatchAPK; import com.topjohnwu.magisk.utils.PatchAPK;
import com.topjohnwu.signing.BootSigner; import com.topjohnwu.signing.BootSigner;
@Keep
public class a extends AppComponentFactory { public class a extends AppComponentFactory {
@Deprecated
public static boolean patchAPK(String in, String out, String pkg) { public static boolean patchAPK(String in, String out, String pkg) {
return PatchAPK.patch(in, out, 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 { public static void main(String[] args) throws Exception {
BootSigner.main(args); BootSigner.main(args);
} }
......
...@@ -3,5 +3,11 @@ package a; ...@@ -3,5 +3,11 @@ package a;
import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.App;
public class e extends App { public class e extends App {
/* stub */ public e() {
super();
}
public e(Object o) {
super(o);
}
} }
...@@ -7,7 +7,6 @@ import androidx.work.Worker; ...@@ -7,7 +7,6 @@ import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import com.topjohnwu.magisk.base.DelegateWorker; import com.topjohnwu.magisk.base.DelegateWorker;
import com.topjohnwu.magisk.utils.ResourceMgrKt;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
...@@ -19,7 +18,7 @@ public abstract class w<T extends DelegateWorker> extends Worker { ...@@ -19,7 +18,7 @@ public abstract class w<T extends DelegateWorker> extends Worker {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
w(@NonNull Context context, @NonNull WorkerParameters workerParams) { w(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(ResourceMgrKt.wrap(context, false), workerParams); super(context, workerParams);
try { try {
base = ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()) base = ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0]).newInstance(); .getActualTypeArguments()[0]).newInstance();
......
...@@ -6,6 +6,7 @@ import android.content.res.Configuration ...@@ -6,6 +6,7 @@ import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex import androidx.multidex.MultiDex
import androidx.room.Room import androidx.room.Room
import androidx.work.WorkManager
import androidx.work.impl.WorkDatabase import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkDatabase_Impl import androidx.work.impl.WorkDatabase_Impl
import com.topjohnwu.magisk.data.database.RepoDatabase import com.topjohnwu.magisk.data.database.RepoDatabase
...@@ -14,16 +15,17 @@ import com.topjohnwu.magisk.di.ActivityTracker ...@@ -14,16 +15,17 @@ import com.topjohnwu.magisk.di.ActivityTracker
import com.topjohnwu.magisk.di.koinModules import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.unwrap import com.topjohnwu.magisk.extensions.unwrap
import com.topjohnwu.magisk.utils.ResourceMgr
import com.topjohnwu.magisk.utils.RootInit import com.topjohnwu.magisk.utils.RootInit
import com.topjohnwu.magisk.utils.isRunningAsStub
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin import org.koin.core.context.startKoin
import timber.log.Timber import timber.log.Timber
open class App : Application() { open class App() : Application() {
constructor(o: Any) : this() {
Info.stub = DynAPK.load(o)
}
init { init {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
...@@ -50,7 +52,6 @@ open class App : Application() { ...@@ -50,7 +52,6 @@ open class App : Application() {
val app: Application val app: Application
val impl: Context val impl: Context
if (base is Application) { if (base is Application) {
isRunningAsStub = true
app = base app = base
impl = base.baseContext impl = base.baseContext
} else { } else {
...@@ -67,6 +68,7 @@ open class App : Application() { ...@@ -67,6 +68,7 @@ open class App : Application() {
} }
ResourceMgr.reload() ResourceMgr.reload()
app.registerActivityLifecycleCallbacks(get<ActivityTracker>()) app.registerActivityLifecycleCallbacks(get<ActivityTracker>())
WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build())
} }
// This is required as some platforms expect ContextImpl // This is required as some platforms expect ContextImpl
......
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
}
}
...@@ -33,8 +33,9 @@ object Config : PreferenceModel, DBConfig { ...@@ -33,8 +33,9 @@ object Config : PreferenceModel, DBConfig {
const val ROOT_ACCESS = "root_access" const val ROOT_ACCESS = "root_access"
const val SU_MULTIUSER_MODE = "multiuser_mode" const val SU_MULTIUSER_MODE = "multiuser_mode"
const val SU_MNT_NS = "mnt_ns" const val SU_MNT_NS = "mnt_ns"
const val SU_MANAGER = "requester"
const val SU_FINGERPRINT = "su_fingerprint" const val SU_FINGERPRINT = "su_fingerprint"
const val SU_MANAGER = "requester"
const val KEYSTORE = "keystore"
// prefs // prefs
const val SU_REQUEST_TIMEOUT = "su_request_timeout" const val SU_REQUEST_TIMEOUT = "su_request_timeout"
...@@ -100,7 +101,12 @@ object Config : PreferenceModel, DBConfig { ...@@ -100,7 +101,12 @@ object Config : PreferenceModel, DBConfig {
} }
private val defaultChannel = 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 else Value.DEFAULT_CHANNEL
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS) var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
...@@ -133,6 +139,7 @@ object Config : PreferenceModel, DBConfig { ...@@ -133,6 +139,7 @@ object Config : PreferenceModel, DBConfig {
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY) var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
var suFingerprint by dbSettings(Key.SU_FINGERPRINT, false) var suFingerprint by dbSettings(Key.SU_FINGERPRINT, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true) 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 // Always return a path in external storage where we can write
val downloadDirectory get() = val downloadDirectory get() =
...@@ -141,9 +148,6 @@ object Config : PreferenceModel, DBConfig { ...@@ -141,9 +148,6 @@ object Config : PreferenceModel, DBConfig {
fun initialize() = prefs.edit { fun initialize() = prefs.edit {
parsePrefs(this) parsePrefs(this)
if (!prefs.contains(Key.UPDATE_CHANNEL))
putString(Key.UPDATE_CHANNEL, defaultChannel.toString())
// Get actual state // Get actual state
putBoolean(Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists()) putBoolean(Key.COREONLY, Const.MAGISK_DISABLE_FILE.exists())
...@@ -152,6 +156,9 @@ object Config : PreferenceModel, DBConfig { ...@@ -152,6 +156,9 @@ object Config : PreferenceModel, DBConfig {
putString(Key.SU_MNT_NS, suMntNamespaceMode.toString()) putString(Key.SU_MNT_NS, suMntNamespaceMode.toString())
putString(Key.SU_MULTIUSER_MODE, suMultiuserMode.toString()) putString(Key.SU_MULTIUSER_MODE, suMultiuserMode.toString())
putBoolean(Key.SU_FINGERPRINT, FingerprintHelper.useFingerprint()) 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 { private fun parsePrefs(editor: SharedPreferences.Editor) = editor.apply {
...@@ -215,4 +222,4 @@ object Config : PreferenceModel, DBConfig { ...@@ -215,4 +222,4 @@ object Config : PreferenceModel, DBConfig {
Shell.su("cat $xml > /data/adb/${Const.MANAGER_CONFIGS}").exec() Shell.su("cat $xml > /data/adb/${Const.MANAGER_CONFIGS}").exec()
} }
} }
\ No newline at end of file
...@@ -22,8 +22,9 @@ object Const { ...@@ -22,8 +22,9 @@ object Const {
const val MANAGER_CONFIGS = ".tmp.magisk.config" const val MANAGER_CONFIGS = ".tmp.magisk.config"
val USER_ID = Process.myUid() / 100000 val USER_ID = Process.myUid() / 100000
object MagiskVersion { object Version {
const val MIN_SUPPORT = 18000 const val MIN_SUPPORT = 18000
const val CONNECT_MODE = 20002
} }
object ID { object ID {
......
@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() }
}
package com.topjohnwu.magisk 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.model.entity.UpdateInfo
import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
val isRunningAsStub get() = Info.stub != null
object Info { object Info {
@JvmStatic val envRef = CachedValue { loadState() }
var magiskVersionCode = -1
@JvmStatic @JvmStatic
var magiskVersionString = "" val env by envRef // Local
var remote = UpdateInfo() // Remote
var remote = UpdateInfo() var stub: DynAPK.Data? = null // Stub
@JvmStatic @JvmStatic
var keepVerity = false var keepVerity = false
...@@ -21,11 +27,40 @@ object Info { ...@@ -21,11 +27,40 @@ object Info {
@JvmStatic @JvmStatic
var recovery = false var recovery = false
fun loadMagiskInfo() { val isConnected by lazy {
runCatching { KObservableField(false).also { field ->
magiskVersionString = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] ReactiveNetwork.observeNetworkConnectivity(get())
magiskVersionCode = ShellUtils.fastCmd("magisk -V").toInt() .subscribeK {
Config.magiskHide = Shell.su("magiskhide --status").exec().isSuccess 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
} }
} }
} }
...@@ -21,7 +21,7 @@ import com.topjohnwu.magisk.extensions.set ...@@ -21,7 +21,7 @@ import com.topjohnwu.magisk.extensions.set
import com.topjohnwu.magisk.model.events.EventHandler import com.topjohnwu.magisk.model.events.EventHandler
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.utils.wrap import com.topjohnwu.magisk.wrap
import kotlin.random.Random import kotlin.random.Random
typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit
......
...@@ -4,7 +4,7 @@ import android.content.BroadcastReceiver ...@@ -4,7 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.utils.wrap import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
abstract class BaseReceiver : BroadcastReceiver(), KoinComponent { abstract class BaseReceiver : BroadcastReceiver(), KoinComponent {
......
...@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.base ...@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.base
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import com.topjohnwu.magisk.utils.wrap import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
abstract class BaseService : Service(), KoinComponent { abstract class BaseService : Service(), KoinComponent {
......
package com.topjohnwu.magisk.base.viewmodel package com.topjohnwu.magisk.base.viewmodel
import android.app.Activity import android.app.Activity
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.topjohnwu.magisk.extensions.doOnSubscribeUi 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.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.ViewActionEvent import com.topjohnwu.magisk.model.events.ViewActionEvent
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.PublishSubject
import com.topjohnwu.magisk.Info.isConnected as gIsConnected
abstract class BaseViewModel( abstract class BaseViewModel(
initialState: State = State.LOADING initialState: State = State.LOADING
) : LoadingViewModel(initialState) { ) : LoadingViewModel(initialState) {
val isConnected = KObservableField(false) val isConnected = object : KObservableField<Boolean>(gIsConnected.value, gIsConnected) {
override fun get(): Boolean {
init { return gIsConnected.value
ReactiveNetwork.observeNetworkConnectivity(get()) }
.subscribeK { isConnected.value = it.available() }
.add()
} }
fun withView(action: Activity.() -> Unit) { fun withView(action: Activity.() -> Unit) {
......
...@@ -29,7 +29,7 @@ class MagiskRepository( ...@@ -29,7 +29,7 @@ class MagiskRepository(
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
}.flatMap { }.flatMap {
// If remote version is lower than current installed, try switching to beta // 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.DEFAULT_CHANNEL) {
Config.updateChannel = Config.Value.BETA_CHANNEL Config.updateChannel = Config.Value.BETA_CHANNEL
apiRaw.fetchBetaUpdate() apiRaw.fetchBetaUpdate()
...@@ -74,4 +74,4 @@ class MagiskRepository( ...@@ -74,4 +74,4 @@ class MagiskRepository(
) } ) }
} }
} }
\ No newline at end of file
...@@ -20,15 +20,18 @@ import androidx.annotation.ColorRes ...@@ -20,15 +20,18 @@ import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.net.toUri 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.DynamicClassLoader
import com.topjohnwu.magisk.utils.FileProvider
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.currentLocale import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.Shell
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import java.lang.reflect.Array as JArray
val packageName: String get() = get<Context>().packageName val packageName: String get() = get<Context>().packageName
...@@ -99,33 +102,38 @@ fun Context.readUri(uri: Uri) = ...@@ -99,33 +102,38 @@ fun Context.readUri(uri: Uri) =
fun Intent.startActivity(context: Context) = context.startActivity(this) fun Intent.startActivity(context: Context) = context.startActivity(this)
fun Intent.toCommand(args: MutableList<String>) { fun Intent.startActivityWithRoot() {
if (action != null) { 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("-a")
args.add(action!!) args.add(it)
} }
if (component != null) { component?.also {
args.add("-n") args.add("-n")
args.add(component!!.flattenToString()) args.add(it.flattenToString())
} }
if (data != null) { data?.also {
args.add("-d") args.add("-d")
args.add(dataString!!) args.add(it.toString())
} }
if (categories != null) { categories?.also {
for (cat in categories) { for (cat in it) {
args.add("-c") args.add("-c")
args.add(cat) args.add(cat)
} }
} }
if (type != null) { type?.also {
args.add("-t") args.add("-t")
args.add(type!!) args.add(it)
} }
val extras = extras extras?.also {
if (extras != null) { loop@ for (key in it.keySet()) {
loop@ for (key in extras.keySet()) { val v = it[key] ?: continue
val v = extras.get(key) ?: continue
var value: Any = v var value: Any = v
val arg: String val arg: String
when { when {
...@@ -139,9 +147,8 @@ fun Intent.toCommand(args: MutableList<String>) { ...@@ -139,9 +147,8 @@ fun Intent.toCommand(args: MutableList<String>) {
arg = "--ecn" arg = "--ecn"
value = v.flattenToString() value = v.flattenToString()
} }
v is ArrayList<*> -> { v is List<*> -> {
if (v.size <= 0) if (v.isEmpty())
/* Impossible to know the type due to type erasure */
continue@loop continue@loop
arg = if (v[0] is Int) arg = if (v[0] is Int)
...@@ -177,11 +184,9 @@ fun Intent.toCommand(args: MutableList<String>) { ...@@ -177,11 +184,9 @@ fun Intent.toCommand(args: MutableList<String>) {
continue@loop /* Unsupported */ continue@loop /* Unsupported */
val sb = StringBuilder() val sb = StringBuilder()
val len = java.lang.reflect.Array.getLength(v) val len = JArray.getLength(v)
for (i in 0 until len) { for (i in 0 until len) {
sb.append( sb.append(JArray.get(v, i)!!.toString().replace(",", "\\,"))
java.lang.reflect.Array.get(v, i)!!.toString().replace(",", "\\,")
)
sb.append(',') sb.append(',')
} }
// Remove trailing comma // Remove trailing comma
...@@ -198,6 +203,7 @@ fun Intent.toCommand(args: MutableList<String>) { ...@@ -198,6 +203,7 @@ fun Intent.toCommand(args: MutableList<String>) {
} }
args.add("-f") args.add("-f")
args.add(flags.toString()) args.add(flags.toString())
return args
} }
fun File.provide(context: Context = get()): Uri { fun File.provide(context: Context = get()): Uri {
......
...@@ -33,3 +33,5 @@ fun String.trimEmptyToNull(): String? = if (isBlank()) null else this ...@@ -33,3 +33,5 @@ fun String.trimEmptyToNull(): String? = if (isBlank()) null else this
fun String.legalFilename() = replace(" ", "_").replace("'", "").replace("\"", "") fun String.legalFilename() = replace(" ", "_").replace("'", "").replace("\"", "")
.replace("$", "").replace("`", "").replace("*", "").replace("/", "_") .replace("$", "").replace("`", "").replace("*", "").replace("/", "_")
.replace("#", "").replace("@", "").replace("\\", "_") .replace("#", "").replace("@", "").replace("\\", "_")
fun String.isEmptyInternal() = isNullOrBlank()
\ No newline at end of file
...@@ -7,11 +7,11 @@ import android.content.Intent ...@@ -7,11 +7,11 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.chooser import com.topjohnwu.magisk.extensions.chooser
import com.topjohnwu.magisk.extensions.exists import com.topjohnwu.magisk.extensions.exists
import com.topjohnwu.magisk.extensions.provide 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.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
...@@ -63,7 +63,7 @@ open class DownloadService : RemoteFileService() { ...@@ -63,7 +63,7 @@ open class DownloadService : RemoteFileService() {
remove(id) remove(id)
when (subject.configuration) { when (subject.configuration) {
is APK.Upgrade -> APKInstall.install(this, subject.file) is APK.Upgrade -> APKInstall.install(this, subject.file)
else -> Unit is APK.Restore -> Unit
} }
} }
...@@ -140,8 +140,7 @@ open class DownloadService : RemoteFileService() { ...@@ -140,8 +140,7 @@ open class DownloadService : RemoteFileService() {
inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) { inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) {
val app = context.applicationContext val app = context.applicationContext
val builder = Builder().apply(argBuilder) val builder = Builder().apply(argBuilder)
val intent = Intent(app, ClassMap[DownloadService::class.java]) val intent = app.intent(DownloadService::class.java).putExtra(ARG_URL, builder.subject)
.putExtra(ARG_URL, builder.subject)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
app.startForegroundService(intent) app.startForegroundService(intent)
...@@ -152,4 +151,4 @@ open class DownloadService : RemoteFileService() { ...@@ -152,4 +151,4 @@ open class DownloadService : RemoteFileService() {
} }
} }
\ No newline at end of file
package com.topjohnwu.magisk.model.download package com.topjohnwu.magisk.model.download
import android.content.ComponentName import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.extensions.writeTo
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.model.entity.internal.Configuration.APK.Restore 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.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject 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.PatchAPK
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import timber.log.Timber
import java.io.File import java.io.File
private fun RemoteFileService.patchPackage(apk: File, id: Int) { private fun RemoteFileService.patch(apk: File, id: Int) {
if (packageName != BuildConfig.APPLICATION_ID) { if (packageName == BuildConfig.APPLICATION_ID)
update(id) { notification -> return
notification.setProgress(0, 0, true)
.setProgress(0, 0, true) update(id) { notification ->
.setContentTitle(getString(R.string.hide_manager_title)) notification.setProgress(0, 0, true)
.setContentText("") .setProgress(0, 0, true)
} .setContentTitle(getString(R.string.hide_manager_title))
val patched = File(apk.parent, "patched.apk") .setContentText("")
try { }
// Try using the new APK to patch itself val patched = File(apk.parent, "patched.apk")
val loader = DynamicClassLoader(apk) PatchAPK.patch(apk, patched, packageName, applicationInfo.nonLocalizedLabel.toString())
loader.loadClass("a.a") apk.delete()
.getMethod("patchAPK", String::class.java, String::class.java, String::class.java) patched.renameTo(apk)
.invoke(null, apk.path, patched.path, packageName) }
} catch (e: Exception) {
Timber.e(e) private fun RemoteFileService.upgrade(apk: File, id: Int) {
// Fallback to use the current implementation if (isRunningAsStub) {
PatchAPK.patch(apk.path, patched.path, packageName) // Move to upgrade location
} apk.copyTo(DynAPK.update(this), overwrite = true)
apk.delete() 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) { ...@@ -51,15 +55,11 @@ private fun RemoteFileService.restore(apk: File, id: Int) {
Config.export() Config.export()
// Make it world readable // Make it world readable
apk.setReadable(true, false) apk.setReadable(true, false)
if (Shell.su("pm install $apk").exec().isSuccess) { Shell.su("pm install $apk && pm uninstall $packageName").exec()
val component = ComponentName(BuildConfig.APPLICATION_ID,
ClassMap.get<Class<*>>(SplashActivity::class.java).name)
Utils.rmAndLaunch(packageName, component)
}
} }
fun RemoteFileService.handleAPK(subject: DownloadSubject.Manager) fun RemoteFileService.handleAPK(subject: DownloadSubject.Manager)
= when (subject.configuration) { = when (subject.configuration) {
is Upgrade -> patchPackage(subject.file, subject.hashCode()) is Upgrade -> upgrade(subject.file, subject.hashCode())
is Restore -> restore(subject.file, subject.hashCode()) is Restore -> restore(subject.file, subject.hashCode())
} }
...@@ -25,7 +25,7 @@ import java.io.InputStream ...@@ -25,7 +25,7 @@ import java.io.InputStream
abstract class RemoteFileService : NotificationService() { abstract class RemoteFileService : NotificationService() {
private val service: GithubRawServices by inject() val service: GithubRawServices by inject()
override val defaultNotification: NotificationCompat.Builder override val defaultNotification: NotificationCompat.Builder
get() = Notifications.progress(this, "") get() = Notifications.progress(this, "")
...@@ -134,4 +134,4 @@ abstract class RemoteFileService : NotificationService() { ...@@ -134,4 +134,4 @@ abstract class RemoteFileService : NotificationService() {
} }
} }
} }
\ No newline at end of file
...@@ -8,7 +8,8 @@ import se.ansman.kotshi.JsonSerializable ...@@ -8,7 +8,8 @@ import se.ansman.kotshi.JsonSerializable
data class UpdateInfo( data class UpdateInfo(
val app: ManagerJson = ManagerJson(), val app: ManagerJson = ManagerJson(),
val uninstaller: UninstallerJson = UninstallerJson(), val uninstaller: UninstallerJson = UninstallerJson(),
val magisk: MagiskJson = MagiskJson() val magisk: MagiskJson = MagiskJson(),
val stub: StubJson = StubJson()
) )
@JsonSerializable @JsonSerializable
...@@ -33,3 +34,9 @@ data class ManagerJson( ...@@ -33,3 +34,9 @@ data class ManagerJson(
val link: String = "", val link: String = "",
val note: String = "" val note: String = ""
) : Parcelable ) : Parcelable
@JsonSerializable
data class StubJson(
val versionCode: Int = -1,
val link: String = ""
)
...@@ -2,14 +2,14 @@ package com.topjohnwu.magisk.model.receiver ...@@ -2,14 +2,14 @@ package com.topjohnwu.magisk.model.receiver
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.ClassMap import android.os.Build.VERSION.SDK_INT
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.base.BaseReceiver import com.topjohnwu.magisk.base.BaseReceiver
import com.topjohnwu.magisk.data.database.PolicyDao import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.data.database.base.su import com.topjohnwu.magisk.data.database.base.su
import com.topjohnwu.magisk.extensions.reboot 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.download.DownloadService
import com.topjohnwu.magisk.model.entity.ManagerJson import com.topjohnwu.magisk.model.entity.ManagerJson
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.entity.internal.Configuration
...@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.view.Notifications ...@@ -20,6 +20,7 @@ import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import org.koin.core.inject import org.koin.core.inject
import timber.log.Timber
open class GeneralReceiver : BaseReceiver() { open class GeneralReceiver : BaseReceiver() {
...@@ -38,6 +39,17 @@ open class GeneralReceiver : BaseReceiver() { ...@@ -38,6 +39,17 @@ open class GeneralReceiver : BaseReceiver() {
override fun onReceive(context: ContextWrapper, intent: Intent?) { override fun onReceive(context: ContextWrapper, intent: Intent?) {
intent ?: return 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) { when (intent.action ?: return) {
Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> { Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> {
val action = intent.getStringExtra("action") val action = intent.getStringExtra("action")
...@@ -51,16 +63,26 @@ open class GeneralReceiver : BaseReceiver() { ...@@ -51,16 +63,26 @@ open class GeneralReceiver : BaseReceiver() {
} }
when (action) { when (action) {
REQUEST -> { REQUEST -> {
val i = Intent(context, ClassMap[SuRequestActivity::class.java]) val i = context.intent(SuRequestActivity::class.java)
.setAction(action) .setAction(action)
.putExtra("socket", intent.getStringExtra("socket")) .putExtra("socket", intent.getStringExtra("socket"))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_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 -> Intent.ACTION_PACKAGE_REPLACED ->
......
...@@ -20,7 +20,7 @@ class UpdateCheckService : DelegateWorker() { ...@@ -20,7 +20,7 @@ class UpdateCheckService : DelegateWorker() {
magiskRepo.fetchUpdate().blockingGet() magiskRepo.fetchUpdate().blockingGet()
if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode) if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode)
Notifications.managerUpdate(applicationContext) Notifications.managerUpdate(applicationContext)
else if (Info.magiskVersionCode < Info.remote.magisk.versionCode) else if (Info.env.magiskVersionCode < Info.remote.magisk.versionCode)
Notifications.magiskUpdate(applicationContext) Notifications.magiskUpdate(applicationContext)
ListenableWorker.Result.success() ListenableWorker.Result.success()
}.getOrElse { }.getOrElse {
......
...@@ -7,8 +7,6 @@ import androidx.fragment.app.Fragment ...@@ -7,8 +7,6 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import com.ncapdevi.fragnav.FragNavController import com.ncapdevi.fragnav.FragNavController
import com.ncapdevi.fragnav.FragNavTransactionOptions 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.Const.Key.OPEN_SECTION
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
...@@ -17,6 +15,7 @@ import com.topjohnwu.magisk.base.BaseFragment ...@@ -17,6 +15,7 @@ import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.databinding.ActivityMainBinding import com.topjohnwu.magisk.databinding.ActivityMainBinding
import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback import com.topjohnwu.magisk.extensions.addOnPropertyChangedCallback
import com.topjohnwu.magisk.extensions.snackbar import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.* import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder import com.topjohnwu.magisk.model.navigation.MagiskAnimBuilder
import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent import com.topjohnwu.magisk.model.navigation.MagiskNavigationEvent
...@@ -61,7 +60,7 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na ...@@ -61,7 +60,7 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
if (!SplashActivity.DONE) { if (!SplashActivity.DONE) {
startActivity(Intent(this, ClassMap[SplashActivity::class.java])) startActivity(intent(SplashActivity::class.java))
finish() finish()
} }
...@@ -155,11 +154,11 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na ...@@ -155,11 +154,11 @@ open class MainActivity : BaseActivity<MainViewModel, ActivityMainBinding>(), Na
private fun checkHideSection() { private fun checkHideSection() {
val menu = binding.navView.menu val menu = binding.navView.menu
menu.findItem(R.id.magiskHideFragment).isVisible = menu.findItem(R.id.magiskHideFragment).isVisible =
Shell.rootAccess() && Config.magiskHide Shell.rootAccess() && Info.env.magiskHide
menu.findItem(R.id.modulesFragment).isVisible = menu.findItem(R.id.modulesFragment).isVisible =
Shell.rootAccess() && Info.magiskVersionCode >= 0 Shell.rootAccess() && Info.env.magiskVersionCode >= 0
menu.findItem(R.id.reposFragment).isVisible = 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 = menu.findItem(R.id.logFragment).isVisible =
Shell.rootAccess() Shell.rootAccess()
menu.findItem(R.id.superuserFragment).isVisible = menu.findItem(R.id.superuserFragment).isVisible =
......
...@@ -2,14 +2,12 @@ package com.topjohnwu.magisk.ui ...@@ -2,14 +2,12 @@ package com.topjohnwu.magisk.ui
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.topjohnwu.magisk.* import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.model.navigation.Navigation import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
...@@ -24,11 +22,11 @@ open class SplashActivity : Activity() { ...@@ -24,11 +22,11 @@ open class SplashActivity : Activity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Shell.getShell { 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) AlertDialog.Builder(this)
.setTitle(R.string.unsupport_magisk_title) .setTitle(R.string.unsupport_magisk_title)
.setMessage(R.string.unsupport_magisk_message) .setMessage(R.string.unsupport_magisk_message)
.setNegativeButton(R.string.ok, null) .setNegativeButton(android.R.string.ok, null)
.setOnDismissListener { finish() } .setOnDismissListener { finish() }
.show() .show()
} else { } else {
......
...@@ -6,12 +6,12 @@ import android.net.Uri ...@@ -6,12 +6,12 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri import androidx.core.net.toUri
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.databinding.ActivityFlashBinding import com.topjohnwu.magisk.databinding.ActivityFlashBinding
import com.topjohnwu.magisk.extensions.snackbar import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.SnackbarEvent import com.topjohnwu.magisk.model.events.SnackbarEvent
...@@ -60,7 +60,7 @@ open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>() ...@@ -60,7 +60,7 @@ open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>()
companion object { 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) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
private fun intent(context: Context, file: File) = intent(context).setData(file.toUri()) private fun intent(context: Context, file: File) = intent(context).setData(file.toUri())
......
...@@ -87,8 +87,8 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentMagiskBinding>(), ...@@ -87,8 +87,8 @@ class HomeFragment : BaseFragment<HomeViewModel, FragmentMagiskBinding>(),
.setTitle(R.string.proprietary_title) .setTitle(R.string.proprietary_title)
.setMessage(R.string.proprietary_notice) .setMessage(R.string.proprietary_notice)
.setCancelable(false) .setCancelable(false)
.setPositiveButton(R.string.yes) { _, _ -> download() } .setPositiveButton(android.R.string.yes) { _, _ -> download() }
.setNegativeButton(R.string.no_thanks) { _, _ -> viewModel.finishSafetyNetCheck(-2) } .setNegativeButton(android.R.string.no) { _, _ -> viewModel.finishSafetyNetCheck(-2) }
.show() .show()
} }
......
...@@ -107,10 +107,10 @@ class HomeViewModel( ...@@ -107,10 +107,10 @@ class HomeViewModel(
Info.recovery = it ?: return@addOnPropertyChangedCallback Info.recovery = it ?: return@addOnPropertyChangedCallback
} }
isConnected.addOnPropertyChangedCallback { isConnected.addOnPropertyChangedCallback {
if (it == true) refresh() if (it == true) refresh(false)
} }
refresh() refresh(false)
} }
fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish() fun paypalPressed() = OpenLinkEvent(Const.Url.PAYPAL_URL).publish()
...@@ -170,7 +170,11 @@ class HomeViewModel( ...@@ -170,7 +170,11 @@ class HomeViewModel(
} }
} }
fun refresh() { @JvmOverloads
fun refresh(invalidate: Boolean = true) {
if (invalidate)
Info.envRef.invalidate()
hasRoot.value = Shell.rootAccess() hasRoot.value = Shell.rootAccess()
val fetchUpdate = if (isConnected.value) val fetchUpdate = if (isConnected.value)
...@@ -179,7 +183,8 @@ class HomeViewModel( ...@@ -179,7 +183,8 @@ class HomeViewModel(
Completable.complete() Completable.complete()
Completable.fromAction { Completable.fromAction {
Info.loadMagiskInfo() // Ensure value is ready
Info.env
}.andThen(fetchUpdate) }.andThen(fetchUpdate)
.applyViewModel(this) .applyViewModel(this)
.doOnSubscribeUi { .doOnSubscribeUi {
...@@ -197,33 +202,40 @@ class HomeViewModel( ...@@ -197,33 +202,40 @@ class HomeViewModel(
private fun refreshVersions() { private fun refreshVersions() {
magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) { magiskCurrentVersion.value = if (magiskState.value != MagiskState.NOT_INSTALLED) {
version.format(Info.magiskVersionString, Info.magiskVersionCode) VERSION_FMT.format(Info.env.magiskVersionString, Info.env.magiskVersionCode)
} else { } else {
"" ""
} }
managerCurrentVersion.value = version managerCurrentVersion.value = if (isRunningAsStub) MGR_VER_FMT
.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE) .format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, Info.stub!!.version)
else
VERSION_FMT.format(BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)
} }
private fun updateSelf() { private fun updateSelf() {
magiskState.value = when (Info.magiskVersionCode) { magiskState.value = when (Info.env.magiskVersionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED 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 else -> MagiskState.UP_TO_DATE
} }
magiskLatestVersion.value = version magiskLatestVersion.value =
.format(Info.remote.magisk.version, Info.remote.magisk.versionCode) VERSION_FMT.format(Info.remote.magisk.version, Info.remote.magisk.versionCode)
_managerState.value = when (Info.remote.app.versionCode) { _managerState.value = when (Info.remote.app.versionCode) {
in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel in Int.MIN_VALUE until 0 -> MagiskState.NOT_INSTALLED //wrong update channel
in (BuildConfig.VERSION_CODE + 1)..Int.MAX_VALUE -> MagiskState.OBSOLETE in (BuildConfig.VERSION_CODE + 1) until Int.MAX_VALUE -> MagiskState.OBSOLETE
else -> MagiskState.UP_TO_DATE else -> {
if (isRunningAsStub && Info.stub!!.version < Info.remote.stub.versionCode)
MagiskState.OBSOLETE
else
MagiskState.UP_TO_DATE
}
} }
managerLatestVersion.value = version managerLatestVersion.value = MGR_VER_FMT
.format(Info.remote.app.version, Info.remote.app.versionCode) .format(Info.remote.app.version, Info.remote.app.versionCode, Info.remote.stub.versionCode)
} }
private fun ensureEnv() { private fun ensureEnv() {
...@@ -240,7 +252,8 @@ class HomeViewModel( ...@@ -240,7 +252,8 @@ class HomeViewModel(
} }
companion object { companion object {
private const val version = "%s (%d)" private const val VERSION_FMT = "%s (%d)"
private const val MGR_VER_FMT = "%s (%d) (%d)"
} }
} }
...@@ -8,12 +8,12 @@ import android.view.MenuInflater ...@@ -8,12 +8,12 @@ import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.topjohnwu.magisk.ClassMap
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseFragment import com.topjohnwu.magisk.base.BaseFragment
import com.topjohnwu.magisk.databinding.FragmentModulesBinding import com.topjohnwu.magisk.databinding.FragmentModulesBinding
import com.topjohnwu.magisk.extensions.reboot import com.topjohnwu.magisk.extensions.reboot
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.OpenFilePickerEvent import com.topjohnwu.magisk.model.events.OpenFilePickerEvent
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
import com.topjohnwu.magisk.ui.flash.FlashActivity import com.topjohnwu.magisk.ui.flash.FlashActivity
...@@ -28,7 +28,7 @@ class ModulesFragment : BaseFragment<ModuleViewModel, FragmentModulesBinding>() ...@@ -28,7 +28,7 @@ class ModulesFragment : BaseFragment<ModuleViewModel, FragmentModulesBinding>()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) { if (requestCode == Const.ID.FETCH_ZIP && resultCode == Activity.RESULT_OK && data != null) {
// Get the URI of the selected file // 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) intent.setData(data.data).putExtra(Const.Key.FLASH_ACTION, Const.Value.FLASH_ZIP)
startActivity(intent) startActivity(intent)
} }
......
...@@ -13,20 +13,17 @@ import androidx.preference.ListPreference ...@@ -13,20 +13,17 @@ import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BasePreferenceFragment import com.topjohnwu.magisk.base.BasePreferenceFragment
import com.topjohnwu.magisk.data.database.RepoDao import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
import com.topjohnwu.magisk.databinding.DialogCustomNameBinding
import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.toLangTag import com.topjohnwu.magisk.extensions.toLangTag
import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.observer.Observer import com.topjohnwu.magisk.model.observer.Observer
import com.topjohnwu.magisk.net.Networking
import com.topjohnwu.magisk.utils.* import com.topjohnwu.magisk.utils.*
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
...@@ -58,6 +55,7 @@ class SettingsFragment : BasePreferenceFragment() { ...@@ -58,6 +55,7 @@ class SettingsFragment : BasePreferenceFragment() {
findPreference<PreferenceCategory>("redesign_cat")?.isVisible = BuildConfig.DEBUG findPreference<PreferenceCategory>("redesign_cat")?.isVisible = BuildConfig.DEBUG
// Get preferences
updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!! updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!!
rootConfig = findPreference(Config.Key.ROOT_ACCESS)!! rootConfig = findPreference(Config.Key.ROOT_ACCESS)!!
autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!! autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!!
...@@ -71,17 +69,68 @@ class SettingsFragment : BasePreferenceFragment() { ...@@ -71,17 +69,68 @@ class SettingsFragment : BasePreferenceFragment() {
val magiskCategory = findPreference<PreferenceCategory>("magisk")!! val magiskCategory = findPreference<PreferenceCategory>("magisk")!!
val suCategory = findPreference<PreferenceCategory>("superuser")!! val suCategory = findPreference<PreferenceCategory>("superuser")!!
val hideManager = findPreference<Preference>("hide")!! val hideManager = findPreference<Preference>("hide")!!
hideManager.setOnPreferenceClickListener { val restoreManager = findPreference<Preference>("restore")!!
PatchAPK.hideManager(requireContext())
true // 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)
}
// 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)
} }
val restoreManager = findPreference<Preference>("restore")
restoreManager?.setOnPreferenceClickListener { if (Const.USER_ID == 0 && Info.isConnected.value && Shell.rootAccess()) {
DownloadService(requireContext()) { if (activity.packageName == BuildConfig.APPLICATION_ID) {
subject = DownloadSubject.Manager(Configuration.APK.Restore) 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 { findPreference<Preference>("clear")?.setOnPreferenceClickListener {
Completable.fromAction { repoDB.clear() }.subscribeK { Completable.fromAction { repoDB.clear() }.subscribeK {
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT) Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT)
...@@ -125,58 +174,7 @@ class SettingsFragment : BasePreferenceFragment() { ...@@ -125,58 +174,7 @@ class SettingsFragment : BasePreferenceFragment() {
setLocalePreference(findPreference(Config.Key.LOCALE)!!) 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() 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) { override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
...@@ -299,8 +297,8 @@ class SettingsFragment : BasePreferenceFragment() { ...@@ -299,8 +297,8 @@ class SettingsFragment : BasePreferenceFragment() {
AlertDialog.Builder(requireActivity()) AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_update_custom) .setTitle(R.string.settings_update_custom)
.setView(v) .setView(v)
.setPositiveButton(R.string.ok) { _, _ -> onSuccess(url.text.toString()) } .setPositiveButton(android.R.string.ok) { _, _ -> onSuccess(url.text.toString()) }
.setNegativeButton(R.string.close) { _, _ -> onCancel() } .setNegativeButton(android.R.string.cancel) { _, _ -> onCancel() }
.setOnCancelListener { onCancel() } .setOnCancelListener { onCancel() }
.show() .show()
} }
...@@ -324,11 +322,35 @@ class SettingsFragment : BasePreferenceFragment() { ...@@ -324,11 +322,35 @@ class SettingsFragment : BasePreferenceFragment() {
AlertDialog.Builder(requireActivity()) AlertDialog.Builder(requireActivity())
.setTitle(R.string.settings_download_path_title) .setTitle(R.string.settings_download_path_title)
.setView(binding.root) .setView(binding.root)
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) } Utils.ensureDownloadPath(data.text.value)?.let { onSuccess(data.text.value) }
?: Utils.toast(R.string.settings_download_path_error, Toast.LENGTH_SHORT) ?: 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() .show()
} }
}
\ No newline at end of file inner class ManagerNameData {
val name = KObservableField(resources.getString(R.string.re_app_name))
}
}
...@@ -84,8 +84,8 @@ class SuperuserViewModel( ...@@ -84,8 +84,8 @@ class SuperuserViewModel(
CustomAlertDialog(this) CustomAlertDialog(this)
.setTitle(R.string.su_revoke_title) .setTitle(R.string.su_revoke_title)
.setMessage(getString(R.string.su_revoke_msg, item.item.appName)) .setMessage(getString(R.string.su_revoke_msg, item.item.appName))
.setPositiveButton(R.string.yes) { _, _ -> updateState() } .setPositiveButton(android.R.string.yes) { _, _ -> updateState() }
.setNegativeButton(R.string.no_thanks, null) .setNegativeButton(android.R.string.no, null)
.setCancelable(true) .setCancelable(true)
.show() .show()
} }
...@@ -144,4 +144,4 @@ class SuperuserViewModel( ...@@ -144,4 +144,4 @@ class SuperuserViewModel(
private fun deletePolicy(policy: MagiskPolicy) = private fun deletePolicy(policy: MagiskPolicy) =
policyDB.delete(policy.uid).andThen(Single.just(policy)) policyDB.delete(policy.uid).andThen(Single.just(policy))
} }
\ No newline at end of file
...@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.surequest ...@@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.surequest
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils
import android.view.Window import android.view.Window
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.base.BaseActivity
...@@ -31,19 +30,17 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB ...@@ -31,19 +30,17 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val intent = intent val intent = intent
val action = intent.action
if (TextUtils.equals(action, GeneralReceiver.REQUEST)) { when (intent?.action) {
if (!viewModel.handleRequest(intent)) GeneralReceiver.REQUEST -> {
finish() if (!viewModel.handleRequest(intent))
return 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() finish()
} }
......
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
}
}
}
...@@ -31,6 +31,7 @@ import com.google.android.material.button.MaterialButton ...@@ -31,6 +31,7 @@ import com.google.android.material.button.MaterialButton
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.android.material.textfield.TextInputLayout
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.drawableCompat import com.topjohnwu.magisk.extensions.drawableCompat
import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial import com.topjohnwu.magisk.extensions.replaceRandomWithSpecial
...@@ -240,6 +241,13 @@ fun setEnabled(view: View, isEnabled: Boolean) { ...@@ -240,6 +241,13 @@ fun setEnabled(view: View, isEnabled: Boolean) {
view.isEnabled = isEnabled 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 // md2
@BindingAdapter("onSelectClick", "onSelectReset", requireAll = false) @BindingAdapter("onSelectClick", "onSelectReset", requireAll = false)
......
...@@ -9,15 +9,11 @@ import java.io.Serializable ...@@ -9,15 +9,11 @@ import java.io.Serializable
* You can define if wrapped type is Nullable or not. * You can define if wrapped type is Nullable or not.
* You can use kotlin get/set syntax for value * 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 var value: T
set(value) { get() = get()
if (field != value) { set(value) { set(value) }
field = value
notifyChange()
}
}
constructor(init: T) { constructor(init: T) {
value = init value = init
...@@ -27,23 +23,8 @@ class KObservableField<T> : ObservableField<T>, Serializable { ...@@ -27,23 +23,8 @@ class KObservableField<T> : ObservableField<T>, Serializable {
value = init value = init
} }
@Deprecated( @Suppress("UNCHECKED_CAST")
message = "Needed for data binding, use KObservableField.value syntax from code",
replaceWith = ReplaceWith("value")
)
override fun get(): T { 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)"
}
}
\ No newline at end of file
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
}
}
@file:Suppress("DEPRECATION")
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.utils
import android.annotation.SuppressLint 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.Configuration
import android.content.res.Resources import android.content.res.Resources
import androidx.annotation.StringRes
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.ResourceMgr
import com.topjohnwu.magisk.extensions.langTagToLocale import com.topjohnwu.magisk.extensions.langTagToLocale
import io.reactivex.Single import io.reactivex.Single
import java.util.* import java.util.*
import kotlin.Comparator
var isRunningAsStub = false
var currentLocale: Locale = Locale.getDefault() var currentLocale: Locale = Locale.getDefault()
private set
@SuppressLint("ConstantLocale") @SuppressLint("ConstantLocale")
val defaultLocale: Locale = Locale.getDefault() val defaultLocale: Locale = Locale.getDefault()
@Suppress("DEPRECATION")
val availableLocales = Single.fromCallable { val availableLocales = Single.fromCallable {
val compareId = R.string.app_changelog val compareId = R.string.app_changelog
mutableListOf<Locale>().apply { mutableListOf<Locale>().apply {
...@@ -54,73 +47,3 @@ val availableLocales = Single.fromCallable { ...@@ -54,73 +47,3 @@ val availableLocales = Single.fromCallable {
.compareTo(b.getDisplayName(b).toLowerCase(b)) .compareTo(b.getDisplayName(b).toLowerCase(b))
}) })
}.cache()!! }.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() }
}
}
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.utils
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.os.Build.VERSION.SDK_INT
import android.widget.Toast import android.widget.Toast
import com.topjohnwu.magisk.* 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.extensions.subscribeK
import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.signing.JarMap import com.topjohnwu.signing.JarMap
import com.topjohnwu.signing.SignAPK import com.topjohnwu.signing.SignAPK
...@@ -47,81 +50,86 @@ object PatchAPK { ...@@ -47,81 +50,86 @@ object PatchAPK {
} }
private fun findAndPatch(xml: ByteArray, from: String, to: String): Boolean { private fun findAndPatch(xml: ByteArray, from: String, to: String): Boolean {
if (from.length != to.length) if (to.length > from.length)
return false return false
val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer() val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asCharBuffer()
val offList = mutableListOf<Int>() val offList = mutableListOf<Int>()
var i = 0 var i = 0
while (i < buf.length - from.length) { loop@ while (i < buf.length - from.length) {
var match = true for (j in from.indices) {
for (j in 0 until from.length) {
if (buf.get(i + j) != from[j]) { if (buf.get(i + j) != from[j]) {
match = false ++i
break continue@loop
} }
} }
if (match) { offList.add(i)
offList.add(i) i += from.length
i += from.length
}
++i
} }
if (offList.isEmpty()) if (offList.isEmpty())
return false return false
val toBuf = to.toCharArray().copyOf(from.length)
for (off in offList) { for (off in offList) {
buf.position(off) buf.position(off)
buf.put(to) buf.put(toBuf)
} }
return true return true
} }
private fun findAndPatch(xml: ByteArray, a: Int, b: Int): Boolean { private fun patchAndHide(context: Context, label: String): Boolean {
val buf = ByteBuffer.wrap(xml).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer() // If not running as stub, and we are compatible with stub, use stub
val len = xml.size / 4 val src = if (!isRunningAsStub && SDK_INT >= 28 && Info.env.connectionMode == 3) {
for (i in 0 until len) { val stub = File(context.cacheDir, "stub.apk")
if (buf.get(i) == a) { val svc = get<GithubRawServices>()
buf.put(i, b) runCatching {
return true 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 random package name and signature
// Generate a new app with random package name val repack = File(context.cacheDir, "patched.apk")
val repack = File(context.filesDir, "patched.apk")
val pkg = genPackageName("com.", BuildConfig.APPLICATION_ID.length) 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 return false
// Install the application // Install the application
repack.setReadable(true, false) repack.setReadable(true, false)
if (!Shell.su("pm install $repack").exec().isSuccess) if (!Shell.su("force_pm_install $repack").exec().isSuccess)
return false return false
Config.suManager = pkg Config.suManager = pkg
Config.export() Config.export()
Utils.rmAndLaunch(BuildConfig.APPLICATION_ID, Shell.su("pm uninstall ${BuildConfig.APPLICATION_ID}").submit()
ComponentName(pkg, ClassMap.get<Class<*>>(SplashActivity::class.java).name))
return true return true
} }
@JvmStatic @JvmStatic
fun patch(apk: String, out: String, pkg: String): Boolean { @JvmOverloads
fun patch(apk: String, out: String, pkg: String, label: String = "Manager"): Boolean {
try { try {
val jar = JarMap(apk) val jar = JarMap(apk)
val je = jar.getJarEntry(Const.ANDROID_MANIFEST) val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
val xml = jar.getRawData(je) val xml = jar.getRawData(je)
if (!findAndPatch(xml, BuildConfig.APPLICATION_ID, pkg) || 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 return false
// Write apk changes // Write apk changes
jar.getOutputStream(je).write(xml) 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) { } catch (e: Exception) {
Timber.e(e) Timber.e(e)
return false return false
...@@ -130,11 +138,36 @@ object PatchAPK { ...@@ -130,11 +138,36 @@ object PatchAPK {
return true 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 { Completable.fromAction {
val progress = Notifications.progress(context, context.getString(R.string.hide_manager_title)) val progress = Notifications.progress(context, context.getString(R.string.hide_manager_title))
Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build()) 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) Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG)
Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID) Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID)
}.subscribeK() }.subscribeK()
......
...@@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Const ...@@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.rawResource import com.topjohnwu.magisk.extensions.rawResource
import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile
...@@ -16,12 +17,14 @@ class RootInit : Shell.Initializer() { ...@@ -16,12 +17,14 @@ class RootInit : Shell.Initializer() {
} }
fun init(context: Context, shell: Shell): Boolean { fun init(context: Context, shell: Shell): Boolean {
// Invalidate env state if shell is recreated
Info.envRef.invalidate()
val job = shell.newJob() val job = shell.newJob()
if (shell.isRoot) { if (shell.isRoot) {
job.add(context.rawResource(R.raw.util_functions)) 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") Const.MAGISK_DISABLE_FILE = SuFile("/cache/.disable_magisk")
Info.loadMagiskInfo()
} else { } else {
job.add(context.rawResource(R.raw.nonroot_utils)) job.add(context.rawResource(R.raw.nonroot_utils))
} }
...@@ -35,6 +38,7 @@ class RootInit : Shell.Initializer() { ...@@ -35,6 +38,7 @@ class RootInit : Shell.Initializer() {
Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean() Info.keepVerity = ShellUtils.fastCmd("echo \$KEEPVERITY").toBoolean()
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean() Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean() Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
return true return true
} }
} }
...@@ -2,14 +2,13 @@ package com.topjohnwu.magisk.utils ...@@ -2,14 +2,13 @@ package com.topjohnwu.magisk.utils
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.os.Process import android.os.Process
import android.widget.Toast import android.widget.Toast
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.PolicyDao import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.data.repository.LogRepository 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.MagiskPolicy
import com.topjohnwu.magisk.model.entity.toLog import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.model.entity.toPolicy import com.topjohnwu.magisk.model.entity.toPolicy
...@@ -17,15 +16,13 @@ import java.util.* ...@@ -17,15 +16,13 @@ import java.util.*
object SuLogger { object SuLogger {
private val context: Context by inject() fun handleLogs(context: Context, intent: Intent) {
fun handleLogs(intent: Intent) {
val fromUid = intent.getIntExtra("from.uid", -1) val fromUid = intent.getIntExtra("from.uid", -1)
if (fromUid < 0) return if (fromUid < 0) return
if (fromUid == Process.myUid()) return if (fromUid == Process.myUid()) return
val pm: PackageManager by inject() val pm = context.packageManager
val notify: Boolean val notify: Boolean
val data = intent.extras val data = intent.extras
...@@ -36,7 +33,7 @@ object SuLogger { ...@@ -36,7 +33,7 @@ object SuLogger {
}.getOrElse { return } }.getOrElse { return }
} else { } else {
// Doesn't report whether notify or not, check database ourselves // 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 val policy = policyDB.fetch(fromUid).blockingGet() ?: return
notify = policy.notification notify = policy.notification
policy policy
...@@ -46,7 +43,7 @@ object SuLogger { ...@@ -46,7 +43,7 @@ object SuLogger {
return return
if (notify) if (notify)
handleNotify(policy) handleNotify(context, policy)
val toUid = intent.getIntExtra("to.uid", -1) val toUid = intent.getIntExtra("to.uid", -1)
if (toUid < 0) return if (toUid < 0) return
...@@ -62,11 +59,11 @@ object SuLogger { ...@@ -62,11 +59,11 @@ object SuLogger {
date = Date() date = Date()
) )
val logRepo: LogRepository by inject() val logRepo = get<LogRepository>()
logRepo.put(log).blockingGet()?.printStackTrace() 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) { if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) {
Utils.toast( Utils.toast(
context.getString( context.getString(
...@@ -80,16 +77,16 @@ object SuLogger { ...@@ -80,16 +77,16 @@ object SuLogger {
} }
} }
fun handleNotify(intent: Intent) { fun handleNotify(context: Context, intent: Intent) {
val fromUid = intent.getIntExtra("from.uid", -1) val fromUid = intent.getIntExtra("from.uid", -1)
if (fromUid < 0) return if (fromUid < 0) return
if (fromUid == Process.myUid()) return if (fromUid == Process.myUid()) return
runCatching { runCatching {
val packageManager: PackageManager by inject() val pm = context.packageManager
val policy = fromUid.toPolicy(packageManager) val policy = fromUid.toPolicy(pm)
.copy(policy = intent.getIntExtra("policy", -1)) .copy(policy = intent.getIntExtra("policy", -1))
if (policy.policy >= 0) if (policy.policy >= 0)
handleNotify(policy) handleNotify(context, policy)
} }
} }
} }
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.utils
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Resources import android.content.res.Resources
...@@ -46,7 +45,7 @@ object Utils { ...@@ -46,7 +45,7 @@ object Utils {
.setRequiresDeviceIdle(true) .setRequiresDeviceIdle(true)
.build() .build()
val request = PeriodicWorkRequest val request = PeriodicWorkRequest
.Builder(ClassMap[UpdateCheckService::class.java], 12, TimeUnit.HOURS) .Builder(ClassMap[UpdateCheckService::class.java] as Class<Worker>, 12, TimeUnit.HOURS)
.setConstraints(constraints) .setConstraints(constraints)
.build() .build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork( WorkManager.getInstance(context).enqueueUniquePeriodicWork(
...@@ -73,8 +72,4 @@ object Utils { ...@@ -73,8 +72,4 @@ object Utils {
if ((exists() && isDirectory) || mkdirs()) this else null if ((exists() && isDirectory) || mkdirs()) this else null
} }
fun rmAndLaunch(rm: String, component: ComponentName) {
Shell.su("(rm_launch $rm ${component.flattenToString()})").exec()
}
} }
...@@ -48,7 +48,7 @@ object MarkDownWindow : KoinComponent { ...@@ -48,7 +48,7 @@ object MarkDownWindow : KoinComponent {
AlertDialog.Builder(activity) AlertDialog.Builder(activity)
.setTitle(title) .setTitle(title)
.setView(mv) .setView(mv)
.setNegativeButton(R.string.close) { dialog, _ -> dialog.dismiss() } .setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() }
.show() .show()
} }
} }
......
...@@ -4,15 +4,11 @@ import android.app.NotificationChannel ...@@ -4,15 +4,11 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent
import android.os.Build import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.TaskStackBuilder import androidx.core.app.TaskStackBuilder
import com.topjohnwu.magisk.ClassMap import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.model.receiver.GeneralReceiver import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.ui.SplashActivity import com.topjohnwu.magisk.ui.SplashActivity
...@@ -20,6 +16,7 @@ import com.topjohnwu.magisk.ui.SplashActivity ...@@ -20,6 +16,7 @@ import com.topjohnwu.magisk.ui.SplashActivity
object Notifications { object Notifications {
val mgr by lazy { NotificationManagerCompat.from(get()) } val mgr by lazy { NotificationManagerCompat.from(get()) }
private val icon by lazy { resolveRes(DynAPK.NOTIFICATION) }
fun setup(context: Context) { fun setup(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
...@@ -34,16 +31,16 @@ object Notifications { ...@@ -34,16 +31,16 @@ object Notifications {
} }
fun magiskUpdate(context: Context) { fun magiskUpdate(context: Context) {
val intent = Intent(context, ClassMap[SplashActivity::class.java]) val intent = context.intent(SplashActivity::class.java)
intent.putExtra(Const.Key.OPEN_SECTION, "magisk") .putExtra(Const.Key.OPEN_SECTION, "magisk")
val stackBuilder = TaskStackBuilder.create(context) val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(ClassMap.get<Class<*>>(SplashActivity::class.java)) stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName))
stackBuilder.addNextIntent(intent) stackBuilder.addNextIntent(intent)
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
PendingIntent.FLAG_UPDATE_CURRENT) PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL) 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)) .setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install)) .setContentText(context.getString(R.string.manager_download_install))
.setVibrate(longArrayOf(0, 100, 100, 100)) .setVibrate(longArrayOf(0, 100, 100, 100))
...@@ -54,15 +51,15 @@ object Notifications { ...@@ -54,15 +51,15 @@ object Notifications {
} }
fun managerUpdate(context: Context) { fun managerUpdate(context: Context) {
val intent = Intent(context, ClassMap[GeneralReceiver::class.java]) val intent = context.intent(GeneralReceiver::class.java)
intent.action = Const.Key.BROADCAST_MANAGER_UPDATE .setAction(Const.Key.BROADCAST_MANAGER_UPDATE)
intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app) .putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
val pendingIntent = PendingIntent.getBroadcast(context, val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL) 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)) .setContentTitle(context.getString(R.string.manager_update_title))
.setContentText(context.getString(R.string.manager_download_install)) .setContentText(context.getString(R.string.manager_download_install))
.setVibrate(longArrayOf(0, 100, 100, 100)) .setVibrate(longArrayOf(0, 100, 100, 100))
...@@ -73,13 +70,13 @@ object Notifications { ...@@ -73,13 +70,13 @@ object Notifications {
} }
fun dtboPatched(context: Context) { fun dtboPatched(context: Context) {
val intent = Intent(context, ClassMap[GeneralReceiver::class.java]) val intent = context.intent(GeneralReceiver::class.java)
.setAction(Const.Key.BROADCAST_REBOOT) .setAction(Const.Key.BROADCAST_REBOOT)
val pendingIntent = PendingIntent.getBroadcast(context, val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL) 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)) .setContentTitle(context.getString(R.string.dtbo_patched_title))
.setContentText(context.getString(R.string.dtbo_patched_reboot)) .setContentText(context.getString(R.string.dtbo_patched_reboot))
.setVibrate(longArrayOf(0, 100, 100, 100)) .setVibrate(longArrayOf(0, 100, 100, 100))
......
...@@ -15,55 +15,56 @@ import com.topjohnwu.superuser.Shell ...@@ -15,55 +15,56 @@ import com.topjohnwu.superuser.Shell
object Shortcuts { object Shortcuts {
fun setup(context: Context) { 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) val manager = context.getSystemService(ShortcutManager::class.java)
manager?.dynamicShortcuts = getShortCuts(context) manager?.dynamicShortcuts = getShortCuts(context)
} }
} }
@RequiresApi(api = Build.VERSION_CODES.N_MR1) @RequiresApi(api = 25)
private fun getShortCuts(context: Context): List<ShortcutInfo> { private fun getShortCuts(context: Context): List<ShortcutInfo> {
val shortCuts = mutableListOf<ShortcutInfo>() val shortCuts = mutableListOf<ShortcutInfo>()
val root = Shell.rootAccess() val root = Shell.rootAccess()
val intent = context.intent(SplashActivity::class.java)
if (Utils.showSuperUser()) { if (Utils.showSuperUser()) {
shortCuts.add(ShortcutInfo.Builder(context, "superuser") shortCuts.add(ShortcutInfo.Builder(context, "superuser")
.setShortLabel(context.getString(R.string.superuser)) .setShortLabel(context.getString(R.string.superuser))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java]) .setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "superuser") .putExtra(Const.Key.OPEN_SECTION, "superuser")
.setAction(Intent.ACTION_VIEW) .setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_superuser)) .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.SUPERUSER)))
.setRank(0) .setRank(0)
.build()) .build())
} }
if (root && Config.magiskHide) { if (root && Info.env.magiskHide) {
shortCuts.add(ShortcutInfo.Builder(context, "magiskhide") shortCuts.add(ShortcutInfo.Builder(context, "magiskhide")
.setShortLabel(context.getString(R.string.magiskhide)) .setShortLabel(context.getString(R.string.magiskhide))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java]) .setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "magiskhide") .putExtra(Const.Key.OPEN_SECTION, "magiskhide")
.setAction(Intent.ACTION_VIEW) .setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_magiskhide)) .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MAGISKHIDE)))
.setRank(1) .setRank(1)
.build()) .build())
} }
if (!Config.coreOnly && root && Info.magiskVersionCode >= 0) { if (!Config.coreOnly && root && Info.env.magiskVersionCode >= 0) {
shortCuts.add(ShortcutInfo.Builder(context, "modules") shortCuts.add(ShortcutInfo.Builder(context, "modules")
.setShortLabel(context.getString(R.string.modules)) .setShortLabel(context.getString(R.string.modules))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java]) .setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "modules") .putExtra(Const.Key.OPEN_SECTION, "modules")
.setAction(Intent.ACTION_VIEW) .setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_extension)) .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.MODULES)))
.setRank(3) .setRank(3)
.build()) .build())
shortCuts.add(ShortcutInfo.Builder(context, "downloads") shortCuts.add(ShortcutInfo.Builder(context, "downloads")
.setShortLabel(context.getString(R.string.downloads)) .setShortLabel(context.getString(R.string.downloads))
.setIntent(Intent(context, ClassMap[SplashActivity::class.java]) .setIntent(Intent(intent)
.putExtra(Const.Key.OPEN_SECTION, "downloads") .putExtra(Const.Key.OPEN_SECTION, "downloads")
.setAction(Intent.ACTION_VIEW) .setAction(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK))
.setIcon(Icon.createWithResource(context, R.drawable.sc_cloud_download)) .setIcon(Icon.createWithResource(context, resolveRes(DynAPK.DOWNLOAD)))
.setRank(2) .setRank(2)
.build()) .build())
} }
......
...@@ -23,7 +23,7 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) { ...@@ -23,7 +23,7 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) {
setTitle(R.string.env_fix_title) setTitle(R.string.env_fix_title)
setMessage(R.string.env_fix_msg) setMessage(R.string.env_fix_msg)
setCancelable(true) setCancelable(true)
setPositiveButton(R.string.yes) { _, _ -> setPositiveButton(android.R.string.yes) { _, _ ->
val pd = ProgressDialog.show(activity, val pd = ProgressDialog.show(activity,
activity.getString(R.string.setup_title), activity.getString(R.string.setup_title),
activity.getString(R.string.setup_msg)) activity.getString(R.string.setup_msg))
...@@ -46,6 +46,6 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) { ...@@ -46,6 +46,6 @@ class EnvFixDialog(activity: Activity) : CustomAlertDialog(activity) {
} }
}.exec() }.exec()
} }
setNegativeButton(R.string.no_thanks, null) setNegativeButton(android.R.string.no, null)
} }
} }
...@@ -31,7 +31,7 @@ class FingerprintAuthDialog(activity: Activity, private val callback: () -> Unit ...@@ -31,7 +31,7 @@ class FingerprintAuthDialog(activity: Activity, private val callback: () -> Unit
binding.message.compoundDrawablePadding = Utils.dpInPx(20) binding.message.compoundDrawablePadding = Utils.dpInPx(20)
binding.message.gravity = Gravity.CENTER binding.message.gravity = Gravity.CENTER
setMessage(R.string.auth_fingerprint) setMessage(R.string.auth_fingerprint)
setNegativeButton(R.string.close) { _, _ -> setNegativeButton(android.R.string.cancel) { _, _ ->
helper?.cancel() helper?.cancel()
failureCallback?.invoke() failureCallback?.invoke()
} }
......
...@@ -62,12 +62,12 @@ internal class InstallMethodDialog(activity: BaseActivity<*, *>, options: List<S ...@@ -62,12 +62,12 @@ internal class InstallMethodDialog(activity: BaseActivity<*, *>, options: List<S
.setTitle(R.string.warning) .setTitle(R.string.warning)
.setMessage(R.string.install_inactive_slot_msg) .setMessage(R.string.install_inactive_slot_msg)
.setCancelable(true) .setCancelable(true)
.setPositiveButton(R.string.yes) { _, _ -> .setPositiveButton(android.R.string.yes) { _, _ ->
DownloadService(activity) { DownloadService(activity) {
subject = DownloadSubject.Magisk(Configuration.Flash.Secondary) subject = DownloadSubject.Magisk(Configuration.Flash.Secondary)
} }
} }
.setNegativeButton(R.string.no_thanks, null) .setNegativeButton(android.R.string.no, null)
.show() .show()
} }
} }
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<FrameLayout <androidx.fragment.app.FragmentContainerView
android:id="@+id/main_nav_host" android:id="@+id/main_nav_host"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
......
<?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>
\ No newline at end of file
...@@ -110,8 +110,12 @@ EOF ...@@ -110,8 +110,12 @@ EOF
cd / cd /
} }
rm_launch() { force_pm_install() {
pm uninstall $1 local APK=$1
am start -n $2 local VERIFY=`settings get global package_verifier_enable`
exit [ "$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
} }
...@@ -89,7 +89,6 @@ ...@@ -89,7 +89,6 @@
<string name="reboot_delay_toast">إعادة التشغيل خلال خمس ثواني…</string> <string name="reboot_delay_toast">إعادة التشغيل خلال خمس ثواني…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">إغلاق</string>
<string name="repo_install_title">تثبيت %1$s</string> <string name="repo_install_title">تثبيت %1$s</string>
<string name="repo_install_msg">هل تريد تثبيت %1$s ?</string> <string name="repo_install_msg">هل تريد تثبيت %1$s ?</string>
<string name="download">التنزيل</string> <string name="download">التنزيل</string>
...@@ -184,7 +183,6 @@ ...@@ -184,7 +183,6 @@
<string name="global_summary">تستخدم كافة جلسات العمل للروت مساحة الاسم ذات التركيب العامة</string> <string name="global_summary">تستخدم كافة جلسات العمل للروت مساحة الاسم ذات التركيب العامة</string>
<string name="requester_summary">سترث جلسات العمل للروت مساحة الأسماء لطالبيها</string> <string name="requester_summary">سترث جلسات العمل للروت مساحة الأسماء لطالبيها</string>
<string name="isolate_summary">سيكون لكل جلسة عمل للروت مساحة اسم معزولة خاصة بها </string> <string name="isolate_summary">سيكون لكل جلسة عمل للروت مساحة اسم معزولة خاصة بها </string>
<string name="android_o_not_support">لا يدعم إصدار الأندرويد +8.0</string>
<string name="disable_fingerprint">لم تُعين بصمات الأصابع أو لا يوجد قارئ بصمات</string> <string name="disable_fingerprint">لم تُعين بصمات الأصابع أو لا يوجد قارئ بصمات</string>
<string name="settings_download_path_error">خطأ عند إنشاء مجلد. عليه أن يكون سهلا الوصول إليه من خلال مجلد التخزين للروت و ألا يكون ملفا.</string> <string name="settings_download_path_error">خطأ عند إنشاء مجلد. عليه أن يكون سهلا الوصول إليه من خلال مجلد التخزين للروت و ألا يكون ملفا.</string>
......
This diff is collapsed.
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
<string name="app_changelog">Списък с промени</string> <string name="app_changelog">Списък с промени</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Затваряне</string>
<string name="repo_install_title">Инсталиране на %1$s</string> <string name="repo_install_title">Инсталиране на %1$s</string>
<string name="repo_install_msg">Желаете ли да инсталирате %1$s сега?</string> <string name="repo_install_msg">Желаете ли да инсталирате %1$s сега?</string>
<string name="download">Изтегляне</string> <string name="download">Изтегляне</string>
...@@ -162,7 +161,6 @@ ...@@ -162,7 +161,6 @@
<string name="global_summary">Всички сесии с руут достъп използват глобалното именно пространство.</string> <string name="global_summary">Всички сесии с руут достъп използват глобалното именно пространство.</string>
<string name="requester_summary">Всички сесии с руут достъп наследяват именното пространство на запитващото приложение.</string> <string name="requester_summary">Всички сесии с руут достъп наследяват именното пространство на запитващото приложение.</string>
<string name="isolate_summary">Всички сесии с руут достъп имат собствени именни пространства.</string> <string name="isolate_summary">Всички сесии с руут достъп имат собствени именни пространства.</string>
<string name="android_o_not_support">Не поддържа Android 8.0+.</string>
<string name="disable_fingerprint">Не са добавени пръстови отпечатъци или устройството не поддържа тази функция.</string> <string name="disable_fingerprint">Не са добавени пръстови отпечатъци или устройството не поддържа тази функция.</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
<string name="advanced_settings_title">Configuració avançada</string> <string name="advanced_settings_title">Configuració avançada</string>
<string name="keep_force_encryption">Mantenir el xifrat forçat</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="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="current_installed">Instal·lada: %1$s</string>
<string name="latest_version">Última: %1$s</string> <string name="latest_version">Última: %1$s</string>
<string name="uninstall">Desinstal·lar</string> <string name="uninstall">Desinstal·lar</string>
...@@ -75,19 +76,18 @@ ...@@ -75,19 +76,18 @@
<string name="manager_update_title">Actualització de Magisk Manager disponible!</string> <string name="manager_update_title">Actualització de Magisk Manager disponible!</string>
<!-- Installation --> <!-- Installation -->
<string name="manager_download_install">Prem per descarregar i instalar.</string> <string name="manager_download_install">Premi per baixar i instalar.</string>
<string name="download_zip_only">Descarrega només el ZIP</string> <string name="download_zip_only">Únicament baixa el ZIP</string>
<string name="direct_install">Instal·lació directa (Recomanat)</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">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="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="setup_title">Instal·lació addicional</string>
<string name="select_patch_file">Sel·lecciona i arranja un arxiu</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="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> <string name="reboot_delay_toast">Reinici en 5 segons…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Tancar</string>
<string name="repo_install_title">Instal·lar %1$s</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="repo_install_msg">Vols instal·lar %1$s ara?</string>
<string name="download">Baixar</string> <string name="download">Baixar</string>
...@@ -110,23 +110,23 @@ ...@@ -110,23 +110,23 @@
<string name="restore_img_msg">Restaurant…</string> <string name="restore_img_msg">Restaurant…</string>
<string name="restore_done">Restauració feta!</string> <string name="restore_done">Restauració feta!</string>
<string name="restore_fail">La còpia de seguretat de Stock no existeix!</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_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 descarregui una extensió que conté el GoogleApiClient per poder fer la comprobació de SafetyNet?</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="setup_fail">Instal·lació fallida.</string>
<string name="env_fix_title">Es requereix instal·lació addicional</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> <string name="setup_msg">S\'està executant la configuració de l\'entorn…</string>
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">General</string> <string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Tema obscur</string> <string name="settings_dark_theme_title">Tema fosc</string>
<string name="settings_dark_theme_summary">Habilitar el tema obscur</string> <string name="settings_dark_theme_summary">Habilitar el tema fosc</string>
<string name="settings_download_path_title">Directori de descàrrega</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_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_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_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_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_title">Restaurar Magisk Manager</string>
<string name="settings_restore_manager_summary">Restaura Magisk Manager amb el nom de paquet original</string> <string name="settings_restore_manager_summary">Restaura Magisk Manager amb el nom de paquet original</string>
<string name="language">Idioma</string> <string name="language">Idioma</string>
...@@ -146,6 +146,10 @@ ...@@ -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_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_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_adb">Aplicacions y ADB</string>
<string name="settings_su_app">Només aplicacions</string> <string name="settings_su_app">Només aplicacions</string>
<string name="settings_su_adb">Només ADB</string> <string name="settings_su_adb">Només ADB</string>
...@@ -161,8 +165,8 @@ ...@@ -161,8 +165,8 @@
<string name="request_timeout">Temps de petició</string> <string name="request_timeout">Temps de petició</string>
<string name="superuser_notification">Notificació de superusuari</string> <string name="superuser_notification">Notificació de superusuari</string>
<string name="request_timeout_summary">%1$d segons</string> <string name="request_timeout_summary">%1$d segons</string>
<string name="settings_su_reauth_title">Re-autenticació</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ó es actualitzada o reinstal·lada</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_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="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> <string name="auth_fingerprint">Autenticar Emprempta Digital</string>
...@@ -174,7 +178,7 @@ ...@@ -174,7 +178,7 @@
<string name="owner_only_summary">Només l\'administrador té accés d\'arrel</string> <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="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="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="mount_namespace_mode">Muntar Namespace </string>
<string name="settings_ns_global">Namespace Global</string> <string name="settings_ns_global">Namespace Global</string>
<string name="settings_ns_requester">Heretar Namespace</string> <string name="settings_ns_requester">Heretar Namespace</string>
...@@ -182,7 +186,6 @@ ...@@ -182,7 +186,6 @@
<string name="global_summary">Totes les sessions d\'arrel utilitzen el suport Namespace Global</string> <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="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="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="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> <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 @@ ...@@ -217,7 +220,7 @@
<string name="pid">PID: %1$d</string> <string name="pid">PID: %1$d</string>
<string name="target_uid">UID de l\'objectiu: %1$d</string> <string name="target_uid">UID de l\'objectiu: %1$d</string>
<string name="command">Ordre: %1$s</string> <string name="command">Ordre: %1$s</string>
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">Mostra apps del sistema</string> <string name="show_system_app">Mostra apps del sistema</string>
......
...@@ -84,7 +84,6 @@ ...@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Restartování za 5 sekund…</string> <string name="reboot_delay_toast">Restartování za 5 sekund…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Zavřít</string>
<string name="repo_install_title">Instalovat %1$s</string> <string name="repo_install_title">Instalovat %1$s</string>
<string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string> <string name="repo_install_msg">Chcete nyní nainstalovat %1$s?</string>
<string name="download">Stáhnout</string> <string name="download">Stáhnout</string>
...@@ -175,7 +174,6 @@ ...@@ -175,7 +174,6 @@
<string name="global_summary">Všechny relace root používají globální připojení jmenného prostoru.</string> <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="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="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> <string name="disable_fingerprint">Nebyly nastaveny žádné otisky prstů ani žádná podpora zařízení.</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -84,7 +84,6 @@ ...@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Neustart in 5 Sekunden…</string> <string name="reboot_delay_toast">Neustart in 5 Sekunden…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Schließen</string>
<string name="repo_install_title">Installiere %1$s</string> <string name="repo_install_title">Installiere %1$s</string>
<string name="repo_install_msg">Möchtest du %1$s installieren?</string> <string name="repo_install_msg">Möchtest du %1$s installieren?</string>
<string name="download">Herunterladen</string> <string name="download">Herunterladen</string>
...@@ -177,7 +176,6 @@ ...@@ -177,7 +176,6 @@
<string name="global_summary">Alle Root-Sitzungen benutzen den global angelegten Namespace</string> <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="requester_summary">Root-Sitzungen erben den Namespace des Abfragenden</string>
<string name="isolate_summary">Jede Root-Sitzung hat ihren isolierten Namespace</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> <string name="disable_fingerprint">Keine Fingerabdrücke gespeichert oder keine Geräteunterstützung</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
<string name="app_changelog">Καταγραφή αλλαγών εφαρμογής</string> <string name="app_changelog">Καταγραφή αλλαγών εφαρμογής</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Κλείσιμο</string>
<string name="repo_install_title">Εγκατάσταση %1$s</string> <string name="repo_install_title">Εγκατάσταση %1$s</string>
<string name="repo_install_msg">Θέλετε να εγκαταστήσετε το %1$s τώρα;</string> <string name="repo_install_msg">Θέλετε να εγκαταστήσετε το %1$s τώρα;</string>
<string name="download">Λήψη</string> <string name="download">Λήψη</string>
...@@ -144,7 +143,6 @@ ...@@ -144,7 +143,6 @@
<string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string> <string name="global_summary">Όλες οι συνεδρίες root χρησιμοποιούν τον καθολικό χώρο oνομάτων προσάρτησης</string>
<string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string> <string name="requester_summary">Οι συνεδρίες root θα κληρονομούν το χώρο ονομάτων του αιτούντα τους</string>
<string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string> <string name="isolate_summary">Κάθε συνεδρία root θα έχει το δικό της απομονωμένο χώρο ονομάτων</string>
<string name="android_o_not_support">Δεν υποστηρίζεται Android 8.0+</string>
<!--Superuser--> <!--Superuser-->
<string name="su_request_title">Αίτημα υπερχρήστη</string> <string name="su_request_title">Αίτημα υπερχρήστη</string>
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
<string name="advanced_settings_title">Ajustes avanzados</string> <string name="advanced_settings_title">Ajustes avanzados</string>
<string name="keep_force_encryption">Mantener cifrado forzado</string> <string name="keep_force_encryption">Mantener cifrado forzado</string>
<string name="keep_dm_verity">Mantener AVB 2.0/dm-verity</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="current_installed">Instalada: %1$s</string>
<string name="latest_version">Última: %1$s</string> <string name="latest_version">Última: %1$s</string>
<string name="uninstall">Desinstalar</string> <string name="uninstall">Desinstalar</string>
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
<string name="reboot_recovery">Reiniciar en Modo Recovery</string> <string name="reboot_recovery">Reiniciar en Modo Recovery</string>
<string name="reboot_bootloader">Reiniciar en Modo Bootloader</string> <string name="reboot_bootloader">Reiniciar en Modo Bootloader</string>
<string name="reboot_download">Reiniciar en Modo Download</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--> <!--Repo Fragment-->
<string name="update_available">Actualización Disponible</string> <string name="update_available">Actualización Disponible</string>
...@@ -72,21 +72,20 @@ ...@@ -72,21 +72,20 @@
<string name="download_file_error">Error descargando archivo</string> <string name="download_file_error">Error descargando archivo</string>
<string name="magisk_update_title">Actualización de Magisk disponible!</string> <string name="magisk_update_title">Actualización de Magisk disponible!</string>
<string name="manager_update_title">Actualización de Magisk Manager disponible!</string> <string name="manager_update_title">Actualización de Magisk Manager disponible!</string>
<!-- Installation --> <!-- Installation -->
<string name="manager_download_install">Pulse para descargar e instalar</string> <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="download_zip_only">Descargar sólo el archivo ZIP</string>
<string name="direct_install">Instalación Directa (Recomendado)</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">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="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="select_method">Seleccionar Método</string>
<string name="setup_title">Configuración Adicional</string> <string name="setup_title">Configuración Adicional</string>
<string name="select_patch_file">Seleccionar y parchear un archivo</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="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> <string name="reboot_delay_toast">Reiniciando en 5 segundos…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Cerrar</string>
<string name="repo_install_title">Instalar %1$s</string> <string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">¿Quieres instalar %1$s ahora?</string> <string name="repo_install_msg">¿Quieres instalar %1$s ahora?</string>
<string name="download">Descargar</string> <string name="download">Descargar</string>
...@@ -121,7 +120,7 @@ ...@@ -121,7 +120,7 @@
<string name="settings_dark_theme_title">Tema oscuro</string> <string name="settings_dark_theme_title">Tema oscuro</string>
<string name="settings_dark_theme_summary">Habilitar el 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_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_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_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> <string name="settings_hide_manager_title">Ocultar Magisk Manager</string>
...@@ -180,7 +179,6 @@ ...@@ -180,7 +179,6 @@
<string name="global_summary">Todas las sesiones de root utilizan el soporte Global Namespace</string> <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="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="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="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> <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 @@ ...@@ -218,5 +216,5 @@
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">Mostrar sistema</string> <string name="show_system_app">Mostrar sistema</string>
</resources> </resources>
...@@ -88,7 +88,6 @@ ...@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Taaskäivitamine 5 sekundi pärast…</string> <string name="reboot_delay_toast">Taaskäivitamine 5 sekundi pärast…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Sulge</string>
<string name="repo_install_title">Installi %1$s</string> <string name="repo_install_title">Installi %1$s</string>
<string name="repo_install_msg">Kas soovid kohe installida %1$s?</string> <string name="repo_install_msg">Kas soovid kohe installida %1$s?</string>
<string name="download">Allalaadimine</string> <string name="download">Allalaadimine</string>
...@@ -183,7 +182,6 @@ ...@@ -183,7 +182,6 @@
<string name="global_summary">Kõik juurkasutaja sessioonid kasutavad globaalset monteerimise nimeruumi.</string> <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="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="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="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> <string name="settings_download_path_error">Faili loomisel esines viga. See peab olema ligipääsetav mäluruumi juurkaustast ning ei tohi olla fail.</string>
......
...@@ -88,7 +88,6 @@ ...@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Redémarrage dans 5 secondes…</string> <string name="reboot_delay_toast">Redémarrage dans 5 secondes…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Fermer</string>
<string name="repo_install_title">Installer %1$s</string> <string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Voulez‐vous installer %1$s maintenant ?</string> <string name="repo_install_msg">Voulez‐vous installer %1$s maintenant ?</string>
<string name="download">Télécharger</string> <string name="download">Télécharger</string>
...@@ -183,7 +182,6 @@ ...@@ -183,7 +182,6 @@
<string name="global_summary">Toutes les sessions super‐utilisateur utilisent l’espace de noms global du montage.</string> <string name="global_summary">Toutes les sessions super‐utilisateur utilisent l’espace de noms global du montage.</string>
<string name="requester_summary">Les sessions super‐utilisateur hériteront de l’espace de noms de leur demandeur.</string> <string name="requester_summary">Les sessions super‐utilisateur hériteront de l’espace de noms de leur demandeur.</string>
<string name="isolate_summary">Chaque session super‐utilisateur aura son propre espace de noms isolé.</string> <string name="isolate_summary">Chaque session super‐utilisateur 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 n’a été définie ou le lecteur d’empreinte n’est pas pris en charge.</string> <string name="disable_fingerprint">Aucune empreinte digitale n’a été définie ou le lecteur d’empreinte n’est 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> <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>
......
This diff is collapsed.
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
<string name="app_changelog">Popis izmjena aplikacije</string> <string name="app_changelog">Popis izmjena aplikacije</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Zatvori</string>
<string name="repo_install_title">Instaliraj %1$s</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="repo_install_msg">Da li želite instalirati %1$s sada?</string>
<string name="download">Preuzmi</string> <string name="download">Preuzmi</string>
......
...@@ -86,7 +86,6 @@ ...@@ -86,7 +86,6 @@
<string name="reboot_delay_toast">Me-reboot dalam 5 detik…</string> <string name="reboot_delay_toast">Me-reboot dalam 5 detik…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Tutup</string>
<string name="repo_install_title">Pasang %1$s</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="repo_install_msg">Apakah Anda ingin memasang %1$s sekarang?</string>
<string name="download">Unduh</string> <string name="download">Unduh</string>
...@@ -181,7 +180,6 @@ ...@@ -181,7 +180,6 @@
<string name="global_summary">Semua sesi root menggunakan mount ruang nama global.</string> <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="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="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="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> <string name="settings_download_path_error">Kesalahan membuat folder. Folder harus dapat diakses dari direktori penyimpanan root dan bukan merupakan file.</string>
......
This diff is collapsed.
...@@ -72,7 +72,6 @@ ...@@ -72,7 +72,6 @@
<string name="manager_update_title">Magisk Managerの更新があります!</string> <string name="manager_update_title">Magisk Managerの更新があります!</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">閉じる</string>
<string name="repo_install_title">%1$s をインストール</string> <string name="repo_install_title">%1$s をインストール</string>
<string name="repo_install_msg">%1$s をインストールしますか?</string> <string name="repo_install_msg">%1$s をインストールしますか?</string>
<string name="download">ダウンロード</string> <string name="download">ダウンロード</string>
...@@ -169,7 +168,6 @@ ...@@ -169,7 +168,6 @@
<string name="global_summary">すべてのrootセッションがグローバル名前空間を使用します</string> <string name="global_summary">すべてのrootセッションがグローバル名前空間を使用します</string>
<string name="requester_summary">rootセッションはリクエスト者の名前空間を継承します</string> <string name="requester_summary">rootセッションはリクエスト者の名前空間を継承します</string>
<string name="isolate_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="disable_fingerprint">指紋が登録されていないか、お使いの端末でサポートされていません。</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -83,7 +83,6 @@ ...@@ -83,7 +83,6 @@
<string name="patch_file_msg">원시 이미지 (*.img) 또는 오딘 tar 파일 (*.tar) 선택</string> <string name="patch_file_msg">원시 이미지 (*.img) 또는 오딘 tar 파일 (*.tar) 선택</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">닫기</string>
<string name="repo_install_title">%1$s 설치</string> <string name="repo_install_title">%1$s 설치</string>
<string name="repo_install_msg">정말 %1$s을(를) 설치하시겠습니까?</string> <string name="repo_install_msg">정말 %1$s을(를) 설치하시겠습니까?</string>
<string name="download">다운로드</string> <string name="download">다운로드</string>
...@@ -176,7 +175,6 @@ ...@@ -176,7 +175,6 @@
<string name="global_summary">모든 루트 세션이 전역 마운트 이름공간을 사용합니다.</string> <string name="global_summary">모든 루트 세션이 전역 마운트 이름공간을 사용합니다.</string>
<string name="requester_summary">루트 세션은 요청자의 이름공간을 상속합니다.</string> <string name="requester_summary">루트 세션은 요청자의 이름공간을 상속합니다.</string>
<string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 이름공간을 사용합니다.</string> <string name="isolate_summary">각각의 루트 세션은 자신만의 독립된 이름공간을 사용합니다.</string>
<string name="android_o_not_support">안드로이드 8.0 이상 버전에서 사용할 수 없습니다.</string>
<string name="disable_fingerprint">지문이 등록되지 않았거나 기기가 지문 인식을 지원하지 않습니다.</string> <string name="disable_fingerprint">지문이 등록되지 않았거나 기기가 지문 인식을 지원하지 않습니다.</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
<string name="app_changelog">Pakeitimų sąrašas</string> <string name="app_changelog">Pakeitimų sąrašas</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Uždaryti</string>
<string name="repo_install_title">Instaliuoti %1$s</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="repo_install_msg">Ar jūs norite instaliuoti %1$s?</string>
<string name="download">Atsisiųsti</string> <string name="download">Atsisiųsti</string>
...@@ -156,7 +155,6 @@ ...@@ -156,7 +155,6 @@
<string name="global_summary">Visos root sesijos naudoja globalią vardų sritį</string> <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="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="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> <string name="disable_fingerprint">Jūsų įrenginyje nebuvo surasta pirštų antspaudų arba jūsų įrenginys neturi pirštų antspaudų skaitytuvo</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -84,7 +84,6 @@ ...@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">Рестартирање за 5 секунди…</string> <string name="reboot_delay_toast">Рестартирање за 5 секунди…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Затвори</string>
<string name="repo_install_title">Инсталирај %1$s</string> <string name="repo_install_title">Инсталирај %1$s</string>
<string name="repo_install_msg">Дали сакате да го инсталирате %1$s сега?</string> <string name="repo_install_msg">Дали сакате да го инсталирате %1$s сега?</string>
<string name="download">Преземи</string> <string name="download">Преземи</string>
...@@ -175,7 +174,6 @@ ...@@ -175,7 +174,6 @@
<string name="global_summary">Сите рут сесии го користат глобалниот именски простор.</string> <string name="global_summary">Сите рут сесии го користат глобалниот именски простор.</string>
<string name="requester_summary">Рут сесиите ќе го наследат именскиот простор на нивниот барател.</string> <string name="requester_summary">Рут сесиите ќе го наследат именскиот простор на нивниот барател.</string>
<string name="isolate_summary">Секоја рут сесија ќе има свој изолиран именски простор.</string> <string name="isolate_summary">Секоја рут сесија ќе има свој изолиран именски простор.</string>
<string name="android_o_not_support">Не е поддржано на Android 8.0+.</string>
<string name="disable_fingerprint">Нема регистрирано отпечатоци од прсти или уредот не ја поддржува оваа функција.</string> <string name="disable_fingerprint">Нема регистрирано отпечатоци од прсти или уредот не ја поддржува оваа функција.</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -69,7 +69,6 @@ ...@@ -69,7 +69,6 @@
<string name="manager_update_title">En Magisk Manager-oppdatering er tilgjengelig!</string> <string name="manager_update_title">En Magisk Manager-oppdatering er tilgjengelig!</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Lukk</string>
<string name="repo_install_title">Installer %1$s</string> <string name="repo_install_title">Installer %1$s</string>
<string name="repo_install_msg">Vil du installere %1$s nå?</string> <string name="repo_install_msg">Vil du installere %1$s nå?</string>
<string name="download">Last ned</string> <string name="download">Last ned</string>
...@@ -166,7 +165,6 @@ ...@@ -166,7 +165,6 @@
<string name="global_summary">Alle root-økter benytter det altdekkende monteringsnavnefeltet.</string> <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="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="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> <string name="disable_fingerprint">Ingen fingeravtrykk ble gitt, eller så støttes det ikke av enheten.</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
<string name="app_changelog">App\'s changelog</string> <string name="app_changelog">App\'s changelog</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Sluiten</string>
<string name="repo_install_title">%1$s installeren</string> <string name="repo_install_title">%1$s installeren</string>
<string name="repo_install_msg">Zeker weten %1$s installeren?</string> <string name="repo_install_msg">Zeker weten %1$s installeren?</string>
<string name="download">Downloaden</string> <string name="download">Downloaden</string>
...@@ -151,7 +150,6 @@ ...@@ -151,7 +150,6 @@
<string name="global_summary">Alle rootsessies gebruiken de globale naamruimte</string> <string name="global_summary">Alle rootsessies gebruiken de globale naamruimte</string>
<string name="requester_summary">Rootsessies verkrijgen de verzoeker\'s 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="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> <string name="disable_fingerprint">Geen vingerafdrukken ingesteld, of geen apparaatondersteuning</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
<string name="install">Instaluj</string> <string name="install">Instaluj</string>
<string name="unsupport_magisk_title">Nieobsługiwana Wersja Magisk</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> <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="magisk_version_error">Magisk nie jest zainstalowany.</string>
<string name="checking_for_updates">Sprawdzanie aktualizacji…</string> <string name="checking_for_updates">Sprawdzanie aktualizacji…</string>
<string name="invalid_update_channel">Nieprawidłowy Kanał 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="checking_safetyNet_status">Sprawdzanie statusu SafetyNet…</string>
<string name="safetyNet_check_success">SafetyNet Poprawny</string> <string name="safetyNet_check_success">SafetyNet Poprawny</string>
<string name="safetyNet_api_error">SafetyNet API Błędny</string> <string name="safetyNet_api_error">SafetyNet API Błędny</string>
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
<string name="latest_version">Ostatnia: %1$s</string> <string name="latest_version">Ostatnia: %1$s</string>
<string name="uninstall">Odinstaluj</string> <string name="uninstall">Odinstaluj</string>
<string name="uninstall_magisk_title">Odinstaluj Magisk</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="update">Pobierz</string>
<string name="core_only_enabled">(Włączony tylko tryb jądra)</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_info_provided">(Nie umieszczono informacji)</string>
<string name="no_modules_found">Nie znaleziono modułów.</string> <string name="no_modules_found">Nie znaleziono modułów.</string>
<string name="update_file_created">Moduł zostanie zaktualizowany przy następnym restarcie.</string> <string name="update_file_created">Moduł zostanie zaktualizowany przy następnym restarcie.</string>
...@@ -45,12 +45,12 @@ ...@@ -45,12 +45,12 @@
<string name="reboot_bootloader">Restart do Bootloadera</string> <string name="reboot_bootloader">Restart do Bootloadera</string>
<string name="reboot_download">Restart do Download</string> <string name="reboot_download">Restart do Download</string>
<string name="reboot_edl">Restart do EDL</string> <string name="reboot_edl">Restart do EDL</string>
<!--Repo Fragment--> <!--Repo Fragment-->
<string name="update_available">Aktualizacja dostępna</string> <string name="update_available">Aktualizacja dostępna</string>
<string name="installed">Zainstalowany</string> <string name="installed">Zainstalowany</string>
<string name="not_installed">Nie 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="sorting_order">Kolejność Sortowania</string>
<string name="sort_by_name">Sortuj po nazwie</string> <string name="sort_by_name">Sortuj po nazwie</string>
<string name="sort_by_update">Sortuj po ostatniej aktualizacji</string> <string name="sort_by_update">Sortuj po ostatniej aktualizacji</string>
...@@ -71,23 +71,22 @@ ...@@ -71,23 +71,22 @@
<string name="download_file_error">Błąd pobierania pliku</string> <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_parent">Pokaż w folderze nadrzędnym</string>
<string name="download_open_self">Pokaż pliki</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> <string name="manager_update_title">Nowa Wersja Magisk Manager Dostępna!</string>
<!-- Installation --> <!-- Installation -->
<string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string> <string name="manager_download_install">Naciśnij aby pobrać i zainstalować</string>
<string name="download_zip_only">Pobierz Tylko Zip</string> <string name="download_zip_only">Pobierz Tylko Zip</string>
<string name="direct_install">Bezpośrednia instalacja (Zalecane)</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="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="select_method">Wybierz Metodę</string>
<string name="setup_title">Dodatkowa konfiguracja</string> <string name="setup_title">Dodatkowa konfiguracja</string>
<string name="select_patch_file">Wybierz i Wgraj Plik</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="patch_file_msg">Wybierz obraz raw (*.img) lub plik ODIN tar (*.tar)</string>
<string name="reboot_delay_toast">Ponowne uruchomienie za 5 sekund…</string> <string name="reboot_delay_toast">Ponowne uruchomienie za 5 sekund…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Zamknij</string>
<string name="repo_install_title">Instaluj %1$s</string> <string name="repo_install_title">Instaluj %1$s</string>
<string name="repo_install_msg">Czy chcesz zainstalować %1$s ?</string> <string name="repo_install_msg">Czy chcesz zainstalować %1$s ?</string>
<string name="download">Pobierz</string> <string name="download">Pobierz</string>
...@@ -100,14 +99,14 @@ ...@@ -100,14 +99,14 @@
<string name="dtbo_patched_reboot">Magisk Manager wgrał dtbo.img. Uruchom ponownie</string> <string name="dtbo_patched_reboot">Magisk Manager wgrał dtbo.img. Uruchom ponownie</string>
<string name="flashing">Flashowanie</string> <string name="flashing">Flashowanie</string>
<string name="done">Gotowe!</string> <string name="done">Gotowe!</string>
<string name="failure">Błąd</string> <string name="failure">Błąd</string>
<string name="hide_manager_title">Ukryj Magisk Manager…</string> <string name="hide_manager_title">Ukryj Magisk Manager…</string>
<string name="hide_manager_fail_toast">Błąd Ukrycia Magisk Managera.</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="warning">Uwaga</string>
<string name="complete_uninstall">Odinstalowywanie Zakończone</string> <string name="complete_uninstall">Odinstalowywanie Zakończone</string>
<string name="restore_img">Przywróć Obraz</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_done">Przywracanie zakończone!</string>
<string name="restore_fail">Stock backup nie istnieje!</string> <string name="restore_fail">Stock backup nie istnieje!</string>
<string name="proprietary_title">Pobierz Kod</string> <string name="proprietary_title">Pobierz Kod</string>
...@@ -123,7 +122,7 @@ ...@@ -123,7 +122,7 @@
<string name="settings_dark_theme_summary">Włącz ciemny motyw</string> <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_title">Pobierz dodatek</string>
<string name="settings_download_path_message">Pliki zostaną zapisane w %1$s</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_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_title">Ukryj Magisk Manager</string>
<string name="settings_hide_manager_summary">Przepakowanie Magisk Manager z losową nazwą pakietu</string> <string name="settings_hide_manager_summary">Przepakowanie Magisk Manager z losową nazwą pakietu</string>
...@@ -145,7 +144,7 @@ ...@@ -145,7 +144,7 @@
<string name="settings_hosts_title">Włącz systemless hosts</string> <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_summary">Wsparcie systemless dla aplikacji Adblock</string>
<string name="settings_hosts_toast">Dodano moduł systemless hosts</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_adb">Aplikacje i ADB</string>
<string name="settings_su_app">Tylko Aplikacje</string> <string name="settings_su_app">Tylko Aplikacje</string>
<string name="settings_su_adb">Tylko ADB</string> <string name="settings_su_adb">Tylko ADB</string>
...@@ -166,8 +165,8 @@ ...@@ -166,8 +165,8 @@
<string name="settings_su_fingerprint_title">Włącz Uwierzytelnienie Odciskiem Palca</string> <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="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="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_only">Tylko Właściciel Urządzenia</string>
<string name="settings_owner_manage">Zarządzanie Właścicielami 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> <string name="settings_user_independent">Niezależny Użytkownik</string>
...@@ -182,11 +181,10 @@ ...@@ -182,11 +181,10 @@
<string name="global_summary">Wszystkie sesje root za pomocą globalnej przestrzeni montowań nazw</string> <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="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="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="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> <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="su_request_title">Prośba o dostęp Superusera</string>
<string name="deny">Odmów</string> <string name="deny">Odmów</string>
<string name="prompt">Zapytaj</string> <string name="prompt">Zapytaj</string>
...@@ -220,5 +218,5 @@ ...@@ -220,5 +218,5 @@
<!-- MagiskHide --> <!-- MagiskHide -->
<string name="show_system_app">Pokaż aplikacje systemowe</string> <string name="show_system_app">Pokaż aplikacje systemowe</string>
</resources> </resources>
...@@ -63,7 +63,6 @@ ...@@ -63,7 +63,6 @@
<string name="app_changelog">Registro de mudanças</string> <string name="app_changelog">Registro de mudanças</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string> <string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Instalar %1$s agora?</string> <string name="repo_install_msg">Instalar %1$s agora?</string>
<string name="download">Baixar</string> <string name="download">Baixar</string>
...@@ -153,7 +152,6 @@ ...@@ -153,7 +152,6 @@
<string name="global_summary">Todas as sessões root usam montagem de espaço de nome global</string> <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="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="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> <string name="disable_fingerprint">Nenhuma impressão digital foi definida ou o dispostivo não tem suporte</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -53,7 +53,6 @@ ...@@ -53,7 +53,6 @@
<string name="app_changelog">Lista de alterações da aplicação</string> <string name="app_changelog">Lista de alterações da aplicação</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Fechar</string>
<string name="repo_install_title">Instalar %1$s</string> <string name="repo_install_title">Instalar %1$s</string>
<string name="repo_install_msg">Deseja instalar%1$s agora?</string> <string name="repo_install_msg">Deseja instalar%1$s agora?</string>
<string name="download">Transferir</string> <string name="download">Transferir</string>
......
...@@ -87,7 +87,6 @@ ...@@ -87,7 +87,6 @@
<string name="reboot_delay_toast">Repornire în 5 secunde…</string> <string name="reboot_delay_toast">Repornire în 5 secunde…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Închide</string>
<string name="repo_install_title">Instalează %1$s</string> <string name="repo_install_title">Instalează %1$s</string>
<string name="repo_install_msg">Vrei să instalezi acum %1$s?</string> <string name="repo_install_msg">Vrei să instalezi acum %1$s?</string>
<string name="download">Descarcă</string> <string name="download">Descarcă</string>
...@@ -182,7 +181,6 @@ ...@@ -182,7 +181,6 @@
<string name="global_summary">Toate sesiunile de root folosesc spațiul de nume global.</string> <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="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="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="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> <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>
......
This diff is collapsed.
...@@ -72,7 +72,6 @@ ...@@ -72,7 +72,6 @@
<string name="manager_update_title">Je dostupná aktualizácia Magisk Manager!</string> <string name="manager_update_title">Je dostupná aktualizácia Magisk Manager!</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Zavrieť</string>
<string name="repo_install_title">Nainštalovať %1$s</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="repo_install_msg">Chcete teraz nainštalovať %1$s?</string>
<string name="download">Stiahnuť</string> <string name="download">Stiahnuť</string>
...@@ -167,7 +166,6 @@ ...@@ -167,7 +166,6 @@
<string name="global_summary">Všetky relácie root použijú globálne mount namespace</string> <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="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="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> <string name="disable_fingerprint">Neboli odoslané žiadne odtlačky prsta alebo ich zariadenie nepodporuje</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
<string name="app_changelog">Дневник промена апликације</string> <string name="app_changelog">Дневник промена апликације</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Затвори</string>
<string name="repo_install_title">Инсталирај %1$s</string> <string name="repo_install_title">Инсталирај %1$s</string>
<string name="repo_install_msg">Да ли желите да инсталирате %1$s?</string> <string name="repo_install_msg">Да ли желите да инсталирате %1$s?</string>
<string name="download">Преузми</string> <string name="download">Преузми</string>
......
...@@ -53,7 +53,6 @@ ...@@ -53,7 +53,6 @@
<string name="app_changelog">Ändringslogg</string> <string name="app_changelog">Ändringslogg</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Stäng</string>
<string name="repo_install_title">Installera %1$s</string> <string name="repo_install_title">Installera %1$s</string>
<string name="repo_install_msg">Vill du installera %1$s ?</string> <string name="repo_install_msg">Vill du installera %1$s ?</string>
<string name="download">Ladda ner</string> <string name="download">Ladda ner</string>
...@@ -62,7 +61,7 @@ ...@@ -62,7 +61,7 @@
<string name="settings_reboot_toast">Starta om för att tillämpa inställningar</string> <string name="settings_reboot_toast">Starta om för att tillämpa inställningar</string>
<string name="release_notes">Release notes</string> <string name="release_notes">Release notes</string>
<string name="repo_cache_cleared">Repo-cache rensad</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="manager_download_install">Tryck för att ladda ner och installera</string>
<string name="update_channel">Magiska uppdateringar</string> <string name="update_channel">Magiska uppdateringar</string>
<string name="download_file_error">Fel vid nerladdning av fil</string> <string name="download_file_error">Fel vid nerladdning av fil</string>
......
...@@ -69,7 +69,6 @@ ...@@ -69,7 +69,6 @@
<string name="manager_update_title">มีการอัพเดต Magisk Manager!</string> <string name="manager_update_title">มีการอัพเดต Magisk Manager!</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">ปิด</string>
<string name="repo_install_title">ติดตั้ง %1$s</string> <string name="repo_install_title">ติดตั้ง %1$s</string>
<string name="repo_install_msg">ต้องการติดตั้ง %1$s ตอนนี้หรือไม่?</string> <string name="repo_install_msg">ต้องการติดตั้ง %1$s ตอนนี้หรือไม่?</string>
<string name="download">ดาวน์โหลด</string> <string name="download">ดาวน์โหลด</string>
...@@ -166,7 +165,6 @@ ...@@ -166,7 +165,6 @@
<string name="global_summary">All root sessions use the global mount 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="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="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> <string name="disable_fingerprint">ไม่มีลายนิ้วมือหรืออุปกรณ์แสกน</string>
<!--Superuser--> <!--Superuser-->
......
...@@ -88,7 +88,6 @@ ...@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">5 saniye içinde yeniden başlatılacak...</string> <string name="reboot_delay_toast">5 saniye içinde yeniden başlatılacak...</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Kapat</string>
<string name="repo_install_title">%1$s yükle</string> <string name="repo_install_title">%1$s yükle</string>
<string name="repo_install_msg">%1$s yüklensin mi?</string> <string name="repo_install_msg">%1$s yüklensin mi?</string>
<string name="download">İndir</string> <string name="download">İndir</string>
...@@ -147,6 +146,10 @@ ...@@ -147,6 +146,10 @@
<string name="settings_hosts_summary">Reklam engelleme uygulamaları için sistemsiz host desteği</string> <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_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_adb">Uygulamalar ve ADB</string>
<string name="settings_su_app">Sadece uygulamalar</string> <string name="settings_su_app">Sadece uygulamalar</string>
<string name="settings_su_adb">Sadece ADB</string> <string name="settings_su_adb">Sadece ADB</string>
...@@ -183,9 +186,8 @@ ...@@ -183,9 +186,8 @@
<string name="global_summary">Tüm kök oturumları genel bağlama ad alanını kullanır</string> <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="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="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="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--> <!--Superuser-->
<string name="su_request_title">Yetkili Kullanıcı İsteği</string> <string name="su_request_title">Yetkili Kullanıcı İsteği</string>
......
...@@ -88,7 +88,6 @@ ...@@ -88,7 +88,6 @@
<string name="reboot_delay_toast">Перезавантаження через 5 секунд…</string> <string name="reboot_delay_toast">Перезавантаження через 5 секунд…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Закрити</string>
<string name="repo_install_title">Встановити %1$s</string> <string name="repo_install_title">Встановити %1$s</string>
<string name="repo_install_msg">Бажаєте встановити %1$s ?</string> <string name="repo_install_msg">Бажаєте встановити %1$s ?</string>
<string name="download">Завантажити</string> <string name="download">Завантажити</string>
...@@ -106,8 +105,8 @@ ...@@ -106,8 +105,8 @@
<string name="hide_manager_fail_toast">Не вдалося приховати 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="warning">Попередження</string>
<string name="complete_uninstall">Видалення виконано</string> <string name="complete_uninstall">Повне видалення</string>
<string name="restore_img">Відновити образи</string> <string name="restore_img">Відновити розділи</string>
<string name="restore_img_msg">Відновлення…</string> <string name="restore_img_msg">Відновлення…</string>
<string name="restore_done">Відновлення завершено!</string> <string name="restore_done">Відновлення завершено!</string>
<string name="restore_fail">Немає резервної копії оригінального boot образу</string> <string name="restore_fail">Немає резервної копії оригінального boot образу</string>
...@@ -140,13 +139,17 @@ ...@@ -140,13 +139,17 @@
<string name="settings_update_beta">Бета реліз</string> <string name="settings_update_beta">Бета реліз</string>
<string name="settings_update_custom">Власний</string> <string name="settings_update_custom">Власний</string>
<string name="settings_update_custom_msg">Вставте власний URL</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_core_only_summary">Увімкнути тільки можливості ядра. MagiskSU i Magisk Hide залишуться увімкненими, проте ніякі модулі не будуть завантажені.</string>
<string name="settings_magiskhide_summary">Приховати Magisk від різних форм виявлень.</string> <string name="settings_magiskhide_summary">Приховати Magisk від різних форм виявлень.</string>
<string name="settings_hosts_title">Позасистемні хости</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_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_adb">Програми і ADB</string>
<string name="settings_su_app">Програми</string> <string name="settings_su_app">Програми</string>
<string name="settings_su_adb">ADB</string> <string name="settings_su_adb">ADB</string>
...@@ -183,7 +186,6 @@ ...@@ -183,7 +186,6 @@
<string name="global_summary">Всі сеанси Суперкористувача використовують глобальний простір імен.</string> <string name="global_summary">Всі сеанси Суперкористувача використовують глобальний простір імен.</string>
<string name="requester_summary">Сеанси Суперкористувача наслідують простір імен запитувача.</string> <string name="requester_summary">Сеанси Суперкористувача наслідують простір імен запитувача.</string>
<string name="isolate_summary">Кожнен сеанс Суперкористувача має власний ізольований простір імен.</string> <string name="isolate_summary">Кожнен сеанс Суперкористувача має власний ізольований простір імен.</string>
<string name="android_o_not_support">Не працює на Android 8.0+.</string>
<string name="disable_fingerprint">Немає відбитків пальця або пристрій не підтримується.</string> <string name="disable_fingerprint">Немає відбитків пальця або пристрій не підтримується.</string>
<string name="settings_download_path_error">Помилка створення папки. Вона повинна бути доступна з кореневої директорії сховища і не повинна бути файлом.</string> <string name="settings_download_path_error">Помилка створення папки. Вона повинна бути доступна з кореневої директорії сховища і не повинна бути файлом.</string>
......
...@@ -61,7 +61,6 @@ ...@@ -61,7 +61,6 @@
<string name="app_changelog">Nhật ký thay đổi của ứng dụng</string> <string name="app_changelog">Nhật ký thay đổi của ứng dụng</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Đóng</string>
<string name="repo_install_title">Cài đặt %1$s</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="repo_install_msg">Bạn muốn cài đặt %1$s ?</string>
<string name="download">Tải xuống</string> <string name="download">Tải xuống</string>
...@@ -159,7 +158,6 @@ ...@@ -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="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="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="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> <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--> <!--Superuser-->
......
...@@ -88,12 +88,11 @@ ...@@ -88,12 +88,11 @@
<string name="reboot_delay_toast">5 秒后重启</string> <string name="reboot_delay_toast">5 秒后重启</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">关闭</string>
<string name="repo_install_title">安装 %1$s</string> <string name="repo_install_title">安装 %1$s</string>
<string name="repo_install_msg">是否安装 %1$s ?</string> <string name="repo_install_msg">是否安装 %1$s ?</string>
<string name="download">下载</string> <string name="download">下载</string>
<string name="reboot">重启</string> <string name="reboot">重启</string>
<string name="settings_reboot_toast">重启以应用设置</string> <string name="settings_reboot_toast">重启设备以应用设置</string>
<string name="release_notes">发布说明</string> <string name="release_notes">发布说明</string>
<string name="repo_cache_cleared">仓库缓存已清除</string> <string name="repo_cache_cleared">仓库缓存已清除</string>
...@@ -147,6 +146,10 @@ ...@@ -147,6 +146,10 @@
<string name="settings_hosts_summary">为广告屏蔽应用提供 Systemless hosts 支持</string> <string name="settings_hosts_summary">为广告屏蔽应用提供 Systemless hosts 支持</string>
<string name="settings_hosts_toast">已添加 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_adb">应用和 ADB</string>
<string name="settings_su_app">仅应用</string> <string name="settings_su_app">仅应用</string>
<string name="settings_su_adb">仅 ADB</string> <string name="settings_su_adb">仅 ADB</string>
...@@ -183,7 +186,6 @@ ...@@ -183,7 +186,6 @@
<string name="global_summary">所有的 ROOT 会话使用全局挂载命名空间</string> <string name="global_summary">所有的 ROOT 会话使用全局挂载命名空间</string>
<string name="requester_summary">ROOT 会话继承原程序的命名空间</string> <string name="requester_summary">ROOT 会话继承原程序的命名空间</string>
<string name="isolate_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="disable_fingerprint">没有设置指纹或设备不支持</string>
<string name="settings_download_path_error">创建文件夹出错。路径需要位于内部存储空间,并且不能有同名文件。</string> <string name="settings_download_path_error">创建文件夹出错。路径需要位于内部存储空间,并且不能有同名文件。</string>
......
...@@ -84,7 +84,6 @@ ...@@ -84,7 +84,6 @@
<string name="reboot_delay_toast">將在 5 秒後重新啟動…</string> <string name="reboot_delay_toast">將在 5 秒後重新啟動…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">關閉</string>
<string name="repo_install_title">安裝 %1$s</string> <string name="repo_install_title">安裝 %1$s</string>
<string name="repo_install_msg">即將安裝 %1$s</string> <string name="repo_install_msg">即將安裝 %1$s</string>
<string name="download">下載</string> <string name="download">下載</string>
...@@ -177,7 +176,6 @@ ...@@ -177,7 +176,6 @@
<string name="global_summary">所有 Root 工作階段皆使用全域 Namespace</string> <string name="global_summary">所有 Root 工作階段皆使用全域 Namespace</string>
<string name="requester_summary">所有 Root 工作階段皆繼承原程式 Namespace</string> <string name="requester_summary">所有 Root 工作階段皆繼承原程式 Namespace</string>
<string name="isolate_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> <string name="disable_fingerprint">未設定指紋或無指紋辨識器</string>
<!--Superuser--> <!--Superuser-->
......
<?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!--Not translatable-->
<!-- Static strings -->
<string name="app_name" translatable="false">Magisk Manager</string> <string name="app_name" translatable="false">Magisk Manager</string>
<string name="re_app_name" translatable="false">Manager</string> <string name="re_app_name" translatable="false">Manager</string>
<string name="magisk" translatable="false">Magisk</string> <string name="magisk" translatable="false">Magisk</string>
<string name="magiskhide" translatable="false">Magisk Hide</string> <string name="magiskhide" translatable="false">Magisk Hide</string>
<string name="empty" translatable="false"/> <string name="empty" translatable="false"/>
<string name="no_thanks">No thanks</string>
<string name="yes">Yes</string>
<string name="ok">OK</string>
<string name="upgrade_msg">Upgrade to full Magisk Manager to finish the setup. Download and install?</string>
<string name="no_internet_msg">Please connect to the Internet! Upgrading to full Magisk Manager is required.</string>
</resources> </resources>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<string name="checking_safetyNet_status">Checking SafetyNet status…</string> <string name="checking_safetyNet_status">Checking SafetyNet status…</string>
<string name="safetyNet_check_success">SafetyNet Check Success</string> <string name="safetyNet_check_success">SafetyNet Check Success</string>
<string name="safetyNet_api_error">SafetyNet API Error</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="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="manager_up_to_date">Magisk Manager is up to date</string>
<string name="advanced_settings_title">Advanced Settings</string> <string name="advanced_settings_title">Advanced Settings</string>
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<string name="latest_version">Latest: %1$s</string> <string name="latest_version">Latest: %1$s</string>
<string name="uninstall">Uninstall</string> <string name="uninstall">Uninstall</string>
<string name="uninstall_magisk_title">Uninstall Magisk</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="update">Update</string>
<string name="core_only_enabled">(Core only mode enabled)</string> <string name="core_only_enabled">(Core only mode enabled)</string>
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
<string name="manager_update_title">Magisk Manager Update Available!</string> <string name="manager_update_title">Magisk Manager Update Available!</string>
<!-- Installation --> <!-- 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="download_zip_only">Download Zip Only</string>
<string name="direct_install">Direct Install (Recommended)</string> <string name="direct_install">Direct Install (Recommended)</string>
<string name="install_inactive_slot">Install to Inactive Slot (After OTA)</string> <string name="install_inactive_slot">Install to Inactive Slot (After OTA)</string>
...@@ -88,12 +88,11 @@ ...@@ -88,12 +88,11 @@
<string name="reboot_delay_toast">Rebooting in 5 seconds…</string> <string name="reboot_delay_toast">Rebooting in 5 seconds…</string>
<!--Toasts, Dialogs--> <!--Toasts, Dialogs-->
<string name="close">Close</string>
<string name="repo_install_title">Install %1$s</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="repo_install_msg">Do you want to install %1$s now?</string>
<string name="download">Download</string> <string name="download">Download</string>
<string name="reboot">Reboot</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="release_notes">Release notes</string>
<string name="repo_cache_cleared">Repo cache cleared</string> <string name="repo_cache_cleared">Repo cache cleared</string>
...@@ -104,7 +103,7 @@ ...@@ -104,7 +103,7 @@
<string name="failure">Failed</string> <string name="failure">Failed</string>
<string name="hide_manager_title">Hiding Magisk Manager…</string> <string name="hide_manager_title">Hiding Magisk Manager…</string>
<string name="hide_manager_fail_toast">Hide Magisk Manager failed.</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="warning">Warning</string>
<string name="complete_uninstall">Complete Uninstall</string> <string name="complete_uninstall">Complete Uninstall</string>
<string name="restore_img">Restore Images</string> <string name="restore_img">Restore Images</string>
...@@ -113,7 +112,7 @@ ...@@ -113,7 +112,7 @@
<string name="restore_fail">Stock backup does not exist!</string> <string name="restore_fail">Stock backup does not exist!</string>
<string name="proprietary_title">Download Proprietary Code</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="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_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="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> <string name="setup_msg">Running environment setup…</string>
...@@ -121,32 +120,36 @@ ...@@ -121,32 +120,36 @@
<!--Settings Activity --> <!--Settings Activity -->
<string name="settings_general_category">General</string> <string name="settings_general_category">General</string>
<string name="settings_dark_theme_title">Dark Theme</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_title">Download path</string>
<string name="settings_download_path_message">Files will be saved to %1$s</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_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_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_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="language">Language</string>
<string name="system_default">(System Default)</string> <string name="system_default">(System Default)</string>
<string name="settings_update">Update Settings</string> <string name="settings_update">Update Settings</string>
<string name="settings_check_update_title">Check Updates</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_channel_title">Update Channel</string>
<string name="settings_update_stable">Stable</string> <string name="settings_update_stable">Stable</string>
<string name="settings_update_beta">Beta</string> <string name="settings_update_beta">Beta</string>
<string name="settings_update_custom">Custom</string> <string name="settings_update_custom">Custom</string>
<string name="settings_update_custom_msg">Insert a custom URL</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_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_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_magiskhide_summary">Hide Magisk from various forms of detection</string>
<string name="settings_hosts_title">Systemless hosts</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_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_adb">Apps and ADB</string>
<string name="settings_su_app">Apps only</string> <string name="settings_su_app">Apps only</string>
<string name="settings_su_adb">ADB only</string> <string name="settings_su_adb">ADB only</string>
...@@ -172,19 +175,18 @@ ...@@ -172,19 +175,18 @@
<string name="settings_owner_only">Device Owner Only</string> <string name="settings_owner_only">Device Owner Only</string>
<string name="settings_owner_manage">Device Owner Managed</string> <string name="settings_owner_manage">Device Owner Managed</string>
<string name="settings_user_independent">User-Independent</string> <string name="settings_user_independent">User-Independent</string>
<string name="owner_only_summary">Only owner has root access.</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="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="user_indepenent_summary">Each user has his/her own separate root rules</string>
<string name="mount_namespace_mode">Mount Namespace Mode</string> <string name="mount_namespace_mode">Mount Namespace Mode</string>
<string name="settings_ns_global">Global Namespace</string> <string name="settings_ns_global">Global Namespace</string>
<string name="settings_ns_requester">Inherit Namespace</string> <string name="settings_ns_requester">Inherit Namespace</string>
<string name="settings_ns_isolate">Isolated 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="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="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="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="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> <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--> <!--Superuser-->
......
...@@ -62,7 +62,7 @@ subprojects { ...@@ -62,7 +62,7 @@ subprojects {
android { android {
signingConfigs { signingConfigs {
config { config {
storeFile rootProject.file('release-key.jks') storeFile new File(props['keyStore'])
storePassword props['keyStorePass'] storePassword props['keyStorePass']
keyAlias props['keyAlias'] keyAlias props['keyAlias']
keyPassword props['keyPass'] keyPassword props['keyPass']
...@@ -85,13 +85,12 @@ subprojects { ...@@ -85,13 +85,12 @@ subprojects {
} }
aaptOptions { aaptOptions {
// Preserve stub resource IDs // Handle resource IDs
File publicTxt = rootProject.file('stub-public.txt') File resId = project.file('res-ids.txt')
if (publicTxt.exists()) { if (resId.exists())
additionalParameters "--stable-ids", "${publicTxt.absolutePath}" additionalParameters "--stable-ids", "${resId.absolutePath}"
} else if (module.name == 'stub') { else
additionalParameters "--emit-ids", "${publicTxt.absolutePath}" additionalParameters "--emit-ids", "${resId.absolutePath}"
}
} }
} }
} }
......
This diff is collapsed.
...@@ -13,8 +13,9 @@ outdir=out ...@@ -13,8 +13,9 @@ outdir=out
prettyName=false prettyName=false
# Only used when building with release flag # 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 # keyPass is the pwd for the specified keyAlias
keyStore=release-key.jks
keyStorePass= keyStorePass=
keyAlias= keyAlias=
keyPass= keyPass=
# Magisk Documentations # Magisk Documentation
(Updated on 2019.9.19) (Updated on 2019.9.19)
- [Installation](install.md) - [Installation](install.md)
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
- [OTA Installation](tutorials.md#ota-installation) - [OTA Installation](tutorials.md#ota-installation)
- [Best Practices for MagiskHide](tutorials.md#best-practices-for-magiskhide) - [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 Details](details.md)
- [Magisk Tools](tools.md) - [Magisk Tools](tools.md)
......
...@@ -54,6 +54,7 @@ static void *request_handler(void *args) { ...@@ -54,6 +54,7 @@ static void *request_handler(void *args) {
case BOOT_COMPLETE: case BOOT_COMPLETE:
case SQLITE_CMD: case SQLITE_CMD:
case BROADCAST_ACK: case BROADCAST_ACK:
case BROADCAST_TEST:
if (credential.uid != 0) { if (credential.uid != 0) {
write_int(client, ROOT_REQUIRED); write_int(client, ROOT_REQUIRED);
close(client); close(client);
...@@ -91,9 +92,10 @@ static void *request_handler(void *args) { ...@@ -91,9 +92,10 @@ static void *request_handler(void *args) {
exec_sql(client); exec_sql(client);
break; break;
case BROADCAST_ACK: case BROADCAST_ACK:
LOGD("* Use broadcasts for su logging and notify\n"); broadcast_ack(client);
CONNECT_BROADCAST = true; break;
close(client); case BROADCAST_TEST:
broadcast_test(client);
break; break;
case REMOVE_MODULES: case REMOVE_MODULES:
if (credential.uid == UID_SHELL || credential.uid == UID_ROOT) { if (credential.uid == UID_SHELL || credential.uid == UID_ROOT) {
......
...@@ -219,7 +219,6 @@ int get_db_strings(db_strings &str, int key) { ...@@ -219,7 +219,6 @@ int get_db_strings(db_strings &str, int key) {
char *err; char *err;
auto string_cb = [&](db_row &row) -> bool { auto string_cb = [&](db_row &row) -> bool {
str[row["key"]] = row["value"]; str[row["key"]] = row["value"];
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
return true; return true;
}; };
if (key >= 0) { if (key >= 0) {
...@@ -273,6 +272,7 @@ int validate_manager(string &alt_pkg, int userid, struct stat *st) { ...@@ -273,6 +272,7 @@ int validate_manager(string &alt_pkg, int userid, struct stat *st) {
} }
void exec_sql(int client) { void exec_sql(int client) {
run_finally f([=]{ close(client); });
char *sql = read_string(client); char *sql = read_string(client);
char *err = db_exec(sql, [&](db_row &row) -> bool { char *err = db_exec(sql, [&](db_row &row) -> bool {
string out; string out;
...@@ -289,9 +289,6 @@ void exec_sql(int client) { ...@@ -289,9 +289,6 @@ void exec_sql(int client) {
return true; return true;
}); });
free(sql); free(sql);
db_err_cmd(err, write_int(client, 0);
write_int(client, 0); db_err_cmd(err, return; );
return;
);
close(client);
} }
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <magisk.h> #include <magisk.h>
#include <daemon.h> #include <daemon.h>
#include <selinux.h> #include <selinux.h>
#include <db.h>
#include <flags.h> #include <flags.h>
using namespace std::literals; using namespace std::literals;
...@@ -36,7 +35,8 @@ Advanced Options (Internal APIs): ...@@ -36,7 +35,8 @@ Advanced Options (Internal APIs):
--clone-attr SRC DEST clone permission, owner, and selinux context --clone-attr SRC DEST clone permission, owner, and selinux context
--clone SRC DEST clone SRC to DEST --clone SRC DEST clone SRC to DEST
--sqlite SQL exec SQL commands to Magisk database --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: Supported init triggers:
post-fs-data, service, boot-complete post-fs-data, service, boot-complete
...@@ -79,12 +79,10 @@ int magisk_main(int argc, char *argv[]) { ...@@ -79,12 +79,10 @@ int magisk_main(int argc, char *argv[]) {
restore_rootcon(); restore_rootcon();
restorecon(); restorecon();
return 0; return 0;
} else if (argv[1] == "--clone-attr"sv) { } else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
if (argc < 4) usage();
clone_attr(argv[2], argv[3]); clone_attr(argv[2], argv[3]);
return 0; return 0;
} else if (argv[1] == "--clone"sv) { } else if (argc >= 4 && argv[1] == "--clone"sv) {
if (argc < 4) usage();
cp_afc(argv[2], argv[3]); cp_afc(argv[2], argv[3]);
return 0; return 0;
} else if (argv[1] == "--daemon"sv) { } else if (argv[1] == "--daemon"sv) {
...@@ -103,7 +101,7 @@ int magisk_main(int argc, char *argv[]) { ...@@ -103,7 +101,7 @@ int magisk_main(int argc, char *argv[]) {
int fd = connect_daemon(true); int fd = connect_daemon(true);
write_int(fd, BOOT_COMPLETE); write_int(fd, BOOT_COMPLETE);
return read_int(fd); return read_int(fd);
} else if (argv[1] == "--sqlite"sv) { } else if (argc >= 3 && argv[1] == "--sqlite"sv) {
int fd = connect_daemon(); int fd = connect_daemon();
write_int(fd, SQLITE_CMD); write_int(fd, SQLITE_CMD);
write_string(fd, argv[2]); write_string(fd, argv[2]);
...@@ -115,14 +113,23 @@ int magisk_main(int argc, char *argv[]) { ...@@ -115,14 +113,23 @@ int magisk_main(int argc, char *argv[]) {
printf("%s\n", res); printf("%s\n", res);
free(res); free(res);
} }
} else if (argv[1] == "--use-broadcast"sv) { } else if (argv[1] == "--connect-mode"sv) {
int fd = connect_daemon(); int fd = connect_daemon();
write_int(fd, BROADCAST_ACK); 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) { } else if (argv[1] == "--remove-modules"sv) {
int fd = connect_daemon(); int fd = connect_daemon();
write_int(fd, REMOVE_MODULES); write_int(fd, REMOVE_MODULES);
return read_int(fd); 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 #if 0
/* Entry point for testing stuffs */ /* Entry point for testing stuffs */
......
...@@ -19,6 +19,7 @@ enum { ...@@ -19,6 +19,7 @@ enum {
SQLITE_CMD, SQLITE_CMD,
BROADCAST_ACK, BROADCAST_ACK,
REMOVE_MODULES, REMOVE_MODULES,
BROADCAST_TEST,
}; };
// Return codes for daemon // Return codes for daemon
...@@ -84,10 +85,13 @@ void magiskhide_handler(int client); ...@@ -84,10 +85,13 @@ void magiskhide_handler(int client);
*************/ *************/
void su_daemon_handler(int client, struct ucred *credential); 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 int SDK_INT;
extern bool RECOVERY_MODE; extern bool RECOVERY_MODE;
extern bool CONNECT_BROADCAST;
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user") #define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")
...@@ -215,7 +215,7 @@ int main(int argc, char *argv[]) { ...@@ -215,7 +215,7 @@ int main(int argc, char *argv[]) {
init = make_unique<SARInit>(argv, &cmd); init = make_unique<SARInit>(argv, &cmd);
} else { } else {
decompress_ramdisk(); decompress_ramdisk();
if (access("/sbin/recovery", F_OK) == 0) if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0)
init = make_unique<RecoveryInit>(argv, &cmd); init = make_unique<RecoveryInit>(argv, &cmd);
else if (access("/apex", F_OK) == 0) else if (access("/apex", F_OK) == 0)
init = make_unique<AFirstStageInit>(argv, &cmd); init = make_unique<AFirstStageInit>(argv, &cmd);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment