Commit 1060dd29 authored by topjohnwu's avatar topjohnwu

Random refactoring

parent 2e0f7a82
...@@ -73,7 +73,7 @@ open class App() : Application() { ...@@ -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 ...@@ -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,23 +28,22 @@ fun AssetManager.addAssetPath(path: String) { ...@@ -27,23 +28,22 @@ 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) ...@@ -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 { ...@@ -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() { ...@@ -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 @@ ...@@ -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 ?: ...@@ -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) { ...@@ -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) { ...@@ -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() { ...@@ -86,5 +82,5 @@ fun refreshLocale() {
else -> localeConfig.langTagToLocale() else -> localeConfig.langTagToLocale()
} }
Locale.setDefault(currentLocale) Locale.setDefault(currentLocale)
ResMgr.resource.updateConfig() AssetHack.resource.updateConfig()
} }
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") ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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() { ...@@ -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() { ...@@ -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)
} }
} }
......
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