diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4d76d7753..b4d2737fa 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -97,6 +97,12 @@
android:name="com.google.android.gms.version"
android:value="12451000" />
+
+
+
diff --git a/app/src/main/java/a/w.java b/app/src/main/java/a/w.java
index 6fa3e50f6..f1307a025 100644
--- a/app/src/main/java/a/w.java
+++ b/app/src/main/java/a/w.java
@@ -6,8 +6,8 @@ import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
+import com.topjohnwu.magisk.HacksKt;
import com.topjohnwu.magisk.base.DelegateWorker;
-import com.topjohnwu.magisk.utils.ResourceMgrKt;
import java.lang.reflect.ParameterizedType;
@@ -19,7 +19,7 @@ public abstract class w extends Worker {
@SuppressWarnings("unchecked")
w(@NonNull Context context, @NonNull WorkerParameters workerParams) {
- super(ResourceMgrKt.wrap(context, false), workerParams);
+ super(HacksKt.wrap(context, false), workerParams);
try {
base = ((Class) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0]).newInstance();
diff --git a/app/src/main/java/com/topjohnwu/magisk/App.kt b/app/src/main/java/com/topjohnwu/magisk/App.kt
index 8c448a784..b70f6d753 100644
--- a/app/src/main/java/com/topjohnwu/magisk/App.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/App.kt
@@ -6,6 +6,7 @@ import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex
import androidx.room.Room
+import androidx.work.WorkManager
import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkDatabase_Impl
import com.topjohnwu.magisk.data.database.RepoDatabase
@@ -14,10 +15,7 @@ import com.topjohnwu.magisk.di.ActivityTracker
import com.topjohnwu.magisk.di.koinModules
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.unwrap
-import com.topjohnwu.magisk.utils.ResourceMgr
import com.topjohnwu.magisk.utils.RootInit
-import com.topjohnwu.magisk.utils.isRunningAsStub
-import com.topjohnwu.magisk.utils.wrap
import com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
@@ -72,6 +70,7 @@ open class App() : Application() {
}
ResourceMgr.reload()
app.registerActivityLifecycleCallbacks(get())
+ WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build())
}
// This is required as some platforms expect ContextImpl
diff --git a/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt b/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt
deleted file mode 100644
index 79217a2d2..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/ClassMap.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.topjohnwu.magisk
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-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
-
-object ClassMap {
-
- private val classMap = 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
- )
-
- // This will be set if running as guest app
- var componentMap: Map? = null
-
- operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() }
-}
-
-fun Class<*>.cmp(pkg: String = BuildConfig.APPLICATION_ID): ComponentName {
- val name = ClassMap[this].name
- return ComponentName(pkg, ClassMap.componentMap?.get(name) ?: name)
-}
-
-fun Context.intent(c: Class<*>): Intent {
- val cls = ClassMap[c]
- return ClassMap.componentMap?.let {
- val className = it.getOrElse(cls.name) { cls.name }
- Intent().setComponent(ComponentName(this, className))
- } ?: Intent(this, cls)
-}
diff --git a/app/src/main/java/com/topjohnwu/magisk/Hacks.kt b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt
new file mode 100644
index 000000000..4f12a5b56
--- /dev/null
+++ b/app/src/main/java/com/topjohnwu/magisk/Hacks.kt
@@ -0,0 +1,223 @@
+@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.DynAPK
+import com.topjohnwu.magisk.utils.currentLocale
+import com.topjohnwu.magisk.utils.defaultLocale
+import java.util.*
+
+var isRunningAsStub = false
+
+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) ResContext(this) else GlobalResContext(this)
+
+fun Context.wrapJob(): Context = object : GlobalResContext(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, ClassMap.componentMap?.get(name)
+ ?: name)
+}
+
+fun Context.intent(c: Class<*>): Intent {
+ val cls = ClassMap[c]
+ return ClassMap.componentMap?.let {
+ val className = it.getOrElse(cls.name) { cls.name }
+ Intent().setComponent(ComponentName(this, className))
+ } ?: Intent(this, cls)
+}
+
+private open class GlobalResContext(base: Context) : ContextWrapper(base) {
+ open val mRes: Resources get() = ResourceMgr.resource
+ private val loader by lazy { javaClass.classLoader!! }
+
+ override fun getApplicationContext(): Context {
+ return this
+ }
+
+ 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 {
+ return base.allPendingJobs
+ }
+
+ override fun getPendingJob(jobId: Int): JobInfo? {
+ return base.getPendingJob(jobId)
+ }
+
+ 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, ClassMap.componentMap?.get(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 classMap = 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
+ )
+
+ // This will be set if running as guest app
+ var componentMap: Map? = null
+
+ operator fun get(c: Class<*>) = classMap.getOrElse(c) { throw IllegalArgumentException() }
+}
diff --git a/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt b/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt
index 0b8fed26f..0c4435dee 100644
--- a/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/base/BaseActivity.kt
@@ -21,7 +21,7 @@ import com.topjohnwu.magisk.extensions.set
import com.topjohnwu.magisk.model.events.EventHandler
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
import com.topjohnwu.magisk.utils.currentLocale
-import com.topjohnwu.magisk.utils.wrap
+import com.topjohnwu.magisk.wrap
import kotlin.random.Random
typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit
diff --git a/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt
index 2e96a6b11..e3f07e620 100644
--- a/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/base/BaseReceiver.kt
@@ -4,7 +4,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
-import com.topjohnwu.magisk.utils.wrap
+import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent
abstract class BaseReceiver : BroadcastReceiver(), KoinComponent {
diff --git a/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt b/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt
index dc7801664..b7a65ccc2 100644
--- a/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/base/BaseService.kt
@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.base
import android.app.Service
import android.content.Context
-import com.topjohnwu.magisk.utils.wrap
+import com.topjohnwu.magisk.wrap
import org.koin.core.KoinComponent
abstract class BaseService : Service(), KoinComponent {
diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt
index 70adc04e3..f22ba0af7 100644
--- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt
@@ -20,7 +20,7 @@ import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
import com.topjohnwu.magisk.ui.flash.FlashActivity
import com.topjohnwu.magisk.utils.APKInstall
import com.topjohnwu.magisk.utils.DynAPK
-import com.topjohnwu.magisk.utils.isRunningAsStub
+import com.topjohnwu.magisk.isRunningAsStub
import org.koin.core.get
import java.io.File
import kotlin.random.Random.Default.nextInt
diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt
index ceb35cc85..8e6dfa6be 100644
--- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt
@@ -12,7 +12,7 @@ import com.topjohnwu.magisk.extensions.writeTo
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
import com.topjohnwu.magisk.utils.ProgressInputStream
-import com.topjohnwu.magisk.utils.isRunningAsStub
+import com.topjohnwu.magisk.isRunningAsStub
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.ShellUtils
import io.reactivex.Completable
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
index 6a43ddb73..75d814ce2 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/SplashActivity.kt
@@ -7,7 +7,7 @@ import android.text.TextUtils
import androidx.appcompat.app.AlertDialog
import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.utils.Utils
-import com.topjohnwu.magisk.utils.wrap
+import com.topjohnwu.magisk.wrap
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
index a3457ddd0..c67ce091a 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
@@ -13,10 +13,7 @@ import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreferenceCompat
-import com.topjohnwu.magisk.BuildConfig
-import com.topjohnwu.magisk.Config
-import com.topjohnwu.magisk.Const
-import com.topjohnwu.magisk.R
+import com.topjohnwu.magisk.*
import com.topjohnwu.magisk.base.BasePreferenceFragment
import com.topjohnwu.magisk.data.database.RepoDao
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt b/app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt
new file mode 100644
index 000000000..f5fe0c8ea
--- /dev/null
+++ b/app/src/main/java/com/topjohnwu/magisk/utils/Locales.kt
@@ -0,0 +1,49 @@
+package com.topjohnwu.magisk.utils
+
+import android.annotation.SuppressLint
+import android.content.res.Configuration
+import android.content.res.Resources
+import com.topjohnwu.magisk.R
+import com.topjohnwu.magisk.ResourceMgr
+import com.topjohnwu.magisk.extensions.langTagToLocale
+import io.reactivex.Single
+import java.util.*
+import kotlin.Comparator
+
+var currentLocale: Locale = Locale.getDefault()
+
+@SuppressLint("ConstantLocale")
+val defaultLocale: Locale = Locale.getDefault()
+
+@Suppress("DEPRECATION")
+val availableLocales = Single.fromCallable {
+ val compareId = R.string.app_changelog
+ mutableListOf().apply {
+ // Add default locale
+ add(Locale.ENGLISH)
+
+ // Add some special locales
+ add(Locale.TAIWAN)
+ add(Locale("pt", "BR"))
+
+ val config = Configuration()
+ val metrics = ResourceMgr.resource.displayMetrics
+ val res = Resources(ResourceMgr.resource.assets, metrics, config)
+
+ // Other locales
+ val otherLocales = ResourceMgr.resource.assets.locales
+ .map { it.langTagToLocale() }
+ .distinctBy {
+ config.setLocale(it)
+ res.updateConfiguration(config, metrics)
+ res.getString(compareId)
+ }
+
+ listOf("", "").toTypedArray()
+
+ addAll(otherLocales)
+ }.sortedWith(Comparator { a, b ->
+ a.getDisplayName(a).toLowerCase(a)
+ .compareTo(b.getDisplayName(b).toLowerCase(b))
+ })
+}.cache()!!
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt b/app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt
deleted file mode 100644
index fb3d7d503..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/utils/ResourceMgr.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-@file:Suppress("DEPRECATION")
-
-package com.topjohnwu.magisk.utils
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.content.ContextWrapper
-import android.content.res.AssetManager
-import android.content.res.Configuration
-import android.content.res.Resources
-import androidx.annotation.StringRes
-import com.topjohnwu.magisk.Config
-import com.topjohnwu.magisk.R
-import com.topjohnwu.magisk.extensions.langTagToLocale
-import io.reactivex.Single
-import java.util.*
-
-var isRunningAsStub = false
-
-var currentLocale: Locale = Locale.getDefault()
- private set
-
-@SuppressLint("ConstantLocale")
-val defaultLocale: Locale = Locale.getDefault()
-
-val availableLocales = Single.fromCallable {
- val compareId = R.string.app_changelog
- mutableListOf().apply {
- // Add default locale
- add(Locale.ENGLISH)
-
- // Add some special locales
- add(Locale.TAIWAN)
- add(Locale("pt", "BR"))
-
- val config = Configuration()
- val metrics = ResourceMgr.resource.displayMetrics
- val res = Resources(ResourceMgr.resource.assets, metrics, config)
-
- // Other locales
- val otherLocales = ResourceMgr.resource.assets.locales
- .map { it.langTagToLocale() }
- .distinctBy {
- config.setLocale(it)
- res.updateConfiguration(config, metrics)
- res.getString(compareId)
- }
-
- listOf("", "").toTypedArray()
-
- addAll(otherLocales)
- }.sortedWith(Comparator { a, b ->
- a.getDisplayName(a).toLowerCase(a)
- .compareTo(b.getDisplayName(b).toLowerCase(b))
- })
-}.cache()!!
-
-private val addAssetPath by lazy {
- AssetManager::class.java.getMethod("addAssetPath", String::class.java)
-}
-
-fun AssetManager.addAssetPath(path: String) {
- addAssetPath.invoke(this, path)
-}
-
-fun Context.wrap(global: Boolean = true): Context
- = if (!global) ResourceMgr.ResContext(this) else ResourceMgr.GlobalResContext(this)
-
-object ResourceMgr {
-
- lateinit var resource: Resources
- private lateinit var resApk: String
-
- fun init(context: Context) {
- resource = context.resources
- if (isRunningAsStub)
- resApk = DynAPK.current(context).path
- }
-
- // Override locale and inject resources from dynamic APK
- private fun Resources.patch(config: Configuration = Configuration(configuration)): Resources {
- config.setLocale(currentLocale)
- updateConfiguration(config, displayMetrics)
- if (isRunningAsStub)
- assets.addAssetPath(resApk)
- return this
- }
-
- fun reload(config: Configuration = Configuration(resource.configuration)) {
- val localeConfig = Config.locale
- currentLocale = when {
- localeConfig.isEmpty() -> defaultLocale
- else -> localeConfig.langTagToLocale()
- }
- Locale.setDefault(currentLocale)
- resource.patch(config)
- }
-
- fun getString(locale: Locale, @StringRes id: Int): String {
- val config = Configuration()
- config.setLocale(locale)
- return Resources(resource.assets, resource.displayMetrics, config).getString(id)
- }
-
- open class GlobalResContext(base: Context) : ContextWrapper(base) {
- open val mRes: Resources get() = resource
- private val loader by lazy { javaClass.classLoader!! }
-
- override fun getResources(): Resources {
- return mRes
- }
-
- override fun getClassLoader(): ClassLoader {
- return loader
- }
-
- override fun createConfigurationContext(config: Configuration): Context {
- return ResContext(super.createConfigurationContext(config))
- }
- }
-
- class ResContext(base: Context) : GlobalResContext(base) {
- override val mRes by lazy { base.resources.patch() }
- }
-
-}
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt
index c4bbfde4e..481ce2d02 100644
--- a/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/utils/RootInit.kt
@@ -5,6 +5,7 @@ import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.rawResource
+import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.io.SuFile
diff --git a/stub/src/main/AndroidManifest.xml b/stub/src/main/AndroidManifest.xml
index e29f2888d..36428315f 100644
--- a/stub/src/main/AndroidManifest.xml
+++ b/stub/src/main/AndroidManifest.xml
@@ -75,36 +75,14 @@
android:name="com.google.android.gms.version"
android:value="12451000" />
-
-
-
+
-
-
-
-
-
-
+ android:permission="android.permission.BIND_JOB_SERVICE" />
diff --git a/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java b/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java
index dfd03b253..bc067e09b 100644
--- a/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java
+++ b/stub/src/main/java/com/topjohnwu/magisk/ComponentMap.java
@@ -4,7 +4,7 @@ import java.util.HashMap;
import java.util.Map;
class ComponentMap {
- private static Map map = new HashMap<>(6);
+ private static Map map = new HashMap<>();
// This mapping will be sent into the guest app
static Map inverseMap;
@@ -16,7 +16,7 @@ class ComponentMap {
map.put("a.g", "a.m");
map.put(a.w.class.getName(), "a.h");
map.put("a.v", "a.j");
- map.put("a.s", "androidx.work.impl.WorkManagerInitializer");
+ map.put("a.j", "androidx.work.impl.background.systemjob.SystemJobService");
inverseMap = new HashMap<>(map.size());
for (Map.Entry e : map.entrySet()) {