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