Random refactoring
This commit is contained in:
parent
2e0f7a82fa
commit
1060dd2906
@ -73,7 +73,7 @@ open class App() : Application() {
|
||||
androidContext(wrapped)
|
||||
modules(koinModules)
|
||||
}
|
||||
ResMgr.init(impl)
|
||||
AssetHack.init(impl)
|
||||
app.registerActivityLifecycleCallbacks(ForegroundTracker)
|
||||
WorkManager.initialize(impl.wrapJob(), androidx.work.Configuration.Builder().build())
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import android.content.Intent
|
||||
import android.content.res.AssetManager
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.util.DisplayMetrics
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.R
|
||||
@ -27,23 +28,22 @@ 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.wrap(inject: Boolean = false): Context =
|
||||
if (inject) ReInjectedContext(this) else InjectedContext(this)
|
||||
|
||||
fun Context.wrapJob(): Context = object : GlobalResContext(this) {
|
||||
fun Context.wrapJob(): Context = object : InjectedContext(this) {
|
||||
|
||||
override fun getApplicationContext(): Context {
|
||||
return this
|
||||
}
|
||||
override fun getApplicationContext() = 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)
|
||||
return super.getSystemService(name).let {
|
||||
when {
|
||||
!isRunningAsStub -> it
|
||||
name == JOB_SCHEDULER_SERVICE -> JobSchedulerWrapper(it as JobScheduler)
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,34 +58,27 @@ inline fun <reified T> Activity.redirect() = Intent(intent)
|
||||
|
||||
inline fun <reified T> Context.intent() = Intent().setComponent(T::class.java.cmp(packageName))
|
||||
|
||||
private open class GlobalResContext(base: Context) : ContextWrapper(base) {
|
||||
open val mRes: Resources get() = ResMgr.resource
|
||||
|
||||
override fun getResources(): Resources {
|
||||
return mRes
|
||||
}
|
||||
|
||||
override fun getClassLoader(): ClassLoader {
|
||||
return javaClass.classLoader!!
|
||||
}
|
||||
|
||||
private open class InjectedContext(base: Context) : ContextWrapper(base) {
|
||||
open val res: Resources get() = AssetHack.resource
|
||||
override fun getAssets(): AssetManager = res.assets
|
||||
override fun getResources() = res
|
||||
override fun getClassLoader() = javaClass.classLoader!!
|
||||
override fun createConfigurationContext(config: Configuration): Context {
|
||||
return ResContext(super.createConfigurationContext(config))
|
||||
return super.createConfigurationContext(config).wrap(true)
|
||||
}
|
||||
}
|
||||
|
||||
private class ResContext(base: Context) : GlobalResContext(base) {
|
||||
override val mRes by lazy { base.resources.patch() }
|
||||
|
||||
private class ReInjectedContext(base: Context) : InjectedContext(base) {
|
||||
override val res by lazy { base.resources.patch() }
|
||||
private fun Resources.patch(): Resources {
|
||||
updateConfig()
|
||||
if (isRunningAsStub)
|
||||
assets.addAssetPath(ResMgr.apk)
|
||||
assets.addAssetPath(AssetHack.apk)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
object ResMgr {
|
||||
object AssetHack {
|
||||
|
||||
lateinit var resource: Resources
|
||||
lateinit var apk: String
|
||||
@ -100,37 +93,27 @@ object ResMgr {
|
||||
apk = context.packageResourcePath
|
||||
}
|
||||
}
|
||||
|
||||
fun newResource(): Resources {
|
||||
val asset = AssetManager::class.java.newInstance()
|
||||
asset.addAssetPath(apk)
|
||||
val config = Configuration(resource.configuration)
|
||||
val metrics = DisplayMetrics()
|
||||
metrics.setTo(resource.displayMetrics)
|
||||
return Resources(asset, metrics, config)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(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)
|
||||
}
|
||||
|
||||
override fun schedule(job: JobInfo) = base.schedule(job.patch())
|
||||
override fun enqueue(job: JobInfo, work: JobWorkItem) = base.enqueue(job.patch(), work)
|
||||
override fun cancel(jobId: Int) = base.cancel(jobId)
|
||||
override fun cancelAll() = base.cancelAll()
|
||||
override fun getAllPendingJobs(): List<JobInfo> = base.allPendingJobs
|
||||
override fun getPendingJob(jobId: Int) = base.getPendingJob(jobId)
|
||||
private fun JobInfo.patch(): JobInfo {
|
||||
// We need to swap out the service of JobInfo
|
||||
// Swap out the service of JobInfo
|
||||
val name = service.className
|
||||
val component = ComponentName(
|
||||
service.packageName,
|
||||
|
@ -34,7 +34,7 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
super.attachBaseContext(base.wrap(false))
|
||||
super.attachBaseContext(base.wrap(true))
|
||||
}
|
||||
|
||||
fun withPermission(permission: String, builder: PermissionRequestBuilder.() -> Unit) {
|
||||
|
@ -3,20 +3,16 @@
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.AssetManager
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import android.util.DisplayMetrics
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.AssetHack
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.ResMgr
|
||||
import com.topjohnwu.magisk.core.addAssetPath
|
||||
import com.topjohnwu.magisk.ktx.langTagToLocale
|
||||
import com.topjohnwu.magisk.ktx.toLangTag
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import kotlin.Comparator
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
var currentLocale: Locale = Locale.getDefault()
|
||||
@ -30,11 +26,8 @@ suspend fun availableLocales() = cachedLocales ?:
|
||||
withContext(Dispatchers.Default) {
|
||||
val compareId = R.string.app_changelog
|
||||
|
||||
// Create a completely new resource to prevent cross talk over app's configs
|
||||
val asset = AssetManager::class.java.newInstance().apply { addAssetPath(ResMgr.apk) }
|
||||
val config = Configuration(ResMgr.resource.configuration)
|
||||
val metrics = DisplayMetrics().apply { setTo(ResMgr.resource.displayMetrics) }
|
||||
val res = Resources(asset, metrics, config)
|
||||
// Create a completely new resource to prevent cross talk over active configs
|
||||
val res = AssetHack.newResource()
|
||||
|
||||
val locales = ArrayList<String>().apply {
|
||||
// Add default locale
|
||||
@ -49,15 +42,13 @@ withContext(Dispatchers.Default) {
|
||||
}.map {
|
||||
it.langTagToLocale()
|
||||
}.distinctBy {
|
||||
config.setLocale(it)
|
||||
res.updateConfiguration(config, metrics)
|
||||
res.updateLocale(it)
|
||||
res.getString(compareId)
|
||||
}.sortedWith(Comparator { a, b ->
|
||||
}.sortedWith { a, b ->
|
||||
a.getDisplayName(a).compareTo(b.getDisplayName(b), true)
|
||||
})
|
||||
}
|
||||
|
||||
config.setLocale(defaultLocale)
|
||||
res.updateConfiguration(config, metrics)
|
||||
res.updateLocale(defaultLocale)
|
||||
val defName = res.getString(R.string.system_default)
|
||||
|
||||
val names = ArrayList<String>(locales.size + 1)
|
||||
@ -79,6 +70,11 @@ fun Resources.updateConfig(config: Configuration = configuration) {
|
||||
updateConfiguration(config, displayMetrics)
|
||||
}
|
||||
|
||||
fun Resources.updateLocale(locale: Locale) {
|
||||
configuration.setLocale(locale)
|
||||
updateConfiguration(configuration, displayMetrics)
|
||||
}
|
||||
|
||||
fun refreshLocale() {
|
||||
val localeConfig = Config.locale
|
||||
currentLocale = when {
|
||||
@ -86,5 +82,5 @@ fun refreshLocale() {
|
||||
else -> localeConfig.langTagToLocale()
|
||||
}
|
||||
Locale.setDefault(currentLocale)
|
||||
ResMgr.resource.updateConfig()
|
||||
AssetHack.resource.updateConfig()
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.topjohnwu.magisk.di
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.topjohnwu.magisk.core.ResMgr
|
||||
import com.topjohnwu.magisk.core.AssetHack
|
||||
import com.topjohnwu.magisk.ktx.deviceProtectedContext
|
||||
import org.koin.core.qualifier.named
|
||||
import org.koin.dsl.module
|
||||
|
||||
@ -11,15 +11,9 @@ val SUTimeout = named("su_timeout")
|
||||
val Protected = named("protected")
|
||||
|
||||
val applicationModule = module {
|
||||
factory { ResMgr.resource }
|
||||
factory { AssetHack.resource }
|
||||
factory { get<Context>().packageManager }
|
||||
factory(Protected) { createDEContext(get()) }
|
||||
factory(Protected) { get<Context>().deviceProtectedContext }
|
||||
single(SUTimeout) { get<Context>(Protected).getSharedPreferences("su_timeout", 0) }
|
||||
single { PreferenceManager.getDefaultSharedPreferences(get<Context>(Protected)) }
|
||||
}
|
||||
|
||||
private fun createDEContext(context: Context): Context {
|
||||
return if (Build.VERSION.SDK_INT >= 24)
|
||||
context.createDeviceProtectedStorageContext()
|
||||
else context
|
||||
single { PreferenceManager.getDefaultSharedPreferences(get(Protected)) }
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.ResMgr
|
||||
import com.topjohnwu.magisk.core.AssetHack
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.utils.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
@ -366,6 +366,6 @@ var TextView.precomputedText: CharSequence
|
||||
}
|
||||
|
||||
fun Int.dpInPx(): Int {
|
||||
val scale = ResMgr.resource.displayMetrics.density
|
||||
val scale = AssetHack.resource.displayMetrics.density
|
||||
return (this * scale + 0.5).toInt()
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import android.widget.TextView
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.caverock.androidsvg.SVG
|
||||
import com.caverock.androidsvg.SVGParseException
|
||||
import com.topjohnwu.magisk.core.ResMgr
|
||||
import com.topjohnwu.magisk.core.AssetHack
|
||||
import com.topjohnwu.superuser.internal.WaitRunnable
|
||||
import io.noties.markwon.AbstractMarkwonPlugin
|
||||
import io.noties.markwon.MarkwonSpansFactory
|
||||
@ -216,7 +216,7 @@ class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() {
|
||||
return PictureDrawable(picture)
|
||||
}
|
||||
|
||||
val density: Float = ResMgr.resource.displayMetrics.density
|
||||
val density: Float = AssetHack.resource.displayMetrics.density
|
||||
|
||||
val width = (w * density + .5f).toInt()
|
||||
val height = (h * density + .5f).toInt()
|
||||
@ -226,7 +226,7 @@ class MarkwonImagePlugin(okHttp: OkHttpClient) : AbstractMarkwonPlugin() {
|
||||
canvas.scale(density, density)
|
||||
svg.renderToCanvas(canvas)
|
||||
|
||||
return BitmapDrawable(ResMgr.resource, bitmap)
|
||||
return BitmapDrawable(AssetHack.resource, bitmap)
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user