Simplify context hacks

This commit is contained in:
topjohnwu 2022-06-02 04:22:25 -07:00
parent 9ab7550970
commit 5c6a7ffa6f
12 changed files with 61 additions and 67 deletions

View File

@ -2,10 +2,8 @@
package com.topjohnwu.magisk.core package com.topjohnwu.magisk.core
import android.app.Activity
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import android.content.res.AssetManager import android.content.res.AssetManager
import android.content.res.Configuration import android.content.res.Configuration
@ -20,13 +18,9 @@ lateinit var AppApkPath: String
fun Resources.addAssetPath(path: String) = StubApk.addAssetPath(this, path) fun Resources.addAssetPath(path: String) = StubApk.addAssetPath(this, path)
fun Context.wrap(): Context = if (this is PatchedContext) this else PatchedContext(this) fun Context.patch(): Context {
resources.patch()
private class PatchedContext(base: Context) : ContextWrapper(base) { return this
init { base.resources.patch() }
override fun getClassLoader() = javaClass.classLoader!!
override fun createConfigurationContext(config: Configuration) =
super.createConfigurationContext(config).wrap()
} }
fun Resources.patch(): Resources { fun Resources.patch(): Resources {
@ -49,10 +43,6 @@ fun createNewResources(): Resources {
fun Class<*>.cmp(pkg: String) = fun Class<*>.cmp(pkg: String) =
ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name) ComponentName(pkg, Info.stub?.classToComponent?.get(name) ?: name)
inline fun <reified T> Activity.redirect() = Intent(intent)
.setComponent(T::class.java.cmp(packageName))
.setFlags(0)
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))
// Keep a reference to these resources to prevent it from // Keep a reference to these resources to prevent it from

View File

@ -1,22 +1,14 @@
package com.topjohnwu.magisk.core package com.topjohnwu.magisk.core
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.content.pm.ProviderInfo
import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.os.ParcelFileDescriptor.MODE_READ_ONLY import android.os.ParcelFileDescriptor.MODE_READ_ONLY
import com.topjohnwu.magisk.core.base.BaseProvider
import com.topjohnwu.magisk.core.su.SuCallbackHandler import com.topjohnwu.magisk.core.su.SuCallbackHandler
import java.io.File import java.io.File
class Provider : ContentProvider() { class Provider : BaseProvider() {
override fun attachInfo(context: Context, info: ProviderInfo) {
super.attachInfo(context.wrap(), info)
}
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? { override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
SuCallbackHandler.run(context!!, method, extras) SuCallbackHandler.run(context!!, method, extras)
@ -38,11 +30,4 @@ class Provider : ContentProvider() {
fun PREFS_URI(pkg: String) = fun PREFS_URI(pkg: String) =
Uri.Builder().scheme("content").authority("$pkg.provider").path("prefs_file").build() Uri.Builder().scheme("content").authority("$pkg.provider").path("prefs_file").build()
} }
override fun onCreate() = true
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?) = 0
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?) = 0
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? = null
} }

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.core package com.topjohnwu.magisk.core
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ContextWrapper import android.content.Context
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.core.base.BaseReceiver import com.topjohnwu.magisk.core.base.BaseReceiver
import com.topjohnwu.magisk.core.di.ServiceLocator import com.topjohnwu.magisk.core.di.ServiceLocator
@ -26,8 +26,9 @@ open class Receiver : BaseReceiver() {
return if (uid == -1) null else uid return if (uid == -1) null else uid
} }
override fun onReceive(context: ContextWrapper, intent: Intent?) { override fun onReceive(context: Context, intent: Intent?) {
intent ?: return intent ?: return
super.onReceive(context, intent)
fun rmPolicy(uid: Int) = GlobalScope.launch { fun rmPolicy(uid: Int) = GlobalScope.launch {
policyDB.delete(uid) policyDB.delete(uid)

View File

@ -18,10 +18,9 @@ import androidx.annotation.WorkerThread
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.isRunningAsStub import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.patch
import com.topjohnwu.magisk.core.utils.RequestInstall import com.topjohnwu.magisk.core.utils.RequestInstall
import com.topjohnwu.magisk.core.utils.UninstallPackage import com.topjohnwu.magisk.core.utils.UninstallPackage
import com.topjohnwu.magisk.core.utils.currentLocale
import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.ktx.reflectField import com.topjohnwu.magisk.ktx.reflectField
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.Utils
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@ -56,14 +55,12 @@ abstract class BaseActivity : AppCompatActivity() {
uninstallLatch.countDown() uninstallLatch.countDown()
} }
override fun applyOverrideConfiguration(config: Configuration?) { override fun attachBaseContext(base: Context) {
// Force applying our preferred local super.attachBaseContext(base.patch())
config?.setLocale(currentLocale)
super.applyOverrideConfiguration(config)
} }
override fun attachBaseContext(base: Context) { override fun createConfigurationContext(config: Configuration): Context {
super.attachBaseContext(base.wrap()) return super.createConfigurationContext(config).patch()
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -2,10 +2,10 @@ package com.topjohnwu.magisk.core.base
import android.app.job.JobService import android.app.job.JobService
import android.content.Context import android.content.Context
import com.topjohnwu.magisk.core.wrap import com.topjohnwu.magisk.core.patch
abstract class BaseJobService : JobService() { abstract class BaseJobService : JobService() {
override fun attachBaseContext(base: Context) { override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap()) super.attachBaseContext(base.patch())
} }
} }

View File

@ -0,0 +1,21 @@
package com.topjohnwu.magisk.core.base
import android.content.ContentProvider
import android.content.ContentValues
import android.content.Context
import android.content.pm.ProviderInfo
import android.database.Cursor
import android.net.Uri
import com.topjohnwu.magisk.core.patch
open class BaseProvider : ContentProvider() {
override fun attachInfo(context: Context, info: ProviderInfo) {
super.attachInfo(context.patch(), info)
}
override fun onCreate() = true
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?) = 0
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?) = 0
override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? = null
}

View File

@ -2,15 +2,13 @@ package com.topjohnwu.magisk.core.base
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.core.wrap import androidx.annotation.CallSuper
import com.topjohnwu.magisk.core.patch
abstract class BaseReceiver : BroadcastReceiver() { abstract class BaseReceiver : BroadcastReceiver() {
@CallSuper
final override fun onReceive(context: Context, intent: Intent?) { override fun onReceive(context: Context, intent: Intent?) {
onReceive(context.wrap() as ContextWrapper, intent) context.patch()
} }
abstract fun onReceive(context: ContextWrapper, intent: Intent?)
} }

View File

@ -2,10 +2,13 @@ package com.topjohnwu.magisk.core.base
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import com.topjohnwu.magisk.core.wrap import android.content.Intent
import android.os.IBinder
import com.topjohnwu.magisk.core.patch
abstract class BaseService : Service() { open class BaseService : Service() {
override fun attachBaseContext(base: Context) { override fun attachBaseContext(base: Context) {
super.attachBaseContext(base.wrap()) super.attachBaseContext(base.patch())
} }
override fun onBind(intent: Intent?): IBinder? = null
} }

View File

@ -2,7 +2,6 @@ package com.topjohnwu.magisk.core.download
import android.app.Notification import android.app.Notification
import android.content.Intent import android.content.Intent
import android.os.IBinder
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.base.BaseService import com.topjohnwu.magisk.core.base.BaseService
@ -20,8 +19,6 @@ open class NotificationService : BaseService() {
protected val service get() = ServiceLocator.networkService protected val service get() = ServiceLocator.networkService
override fun onBind(intent: Intent?): IBinder? = null
override fun onTaskRemoved(rootIntent: Intent?) { override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent) super.onTaskRemoved(rootIntent)
notifications.forEach { Notifications.mgr.cancel(it.key) } notifications.forEach { Notifications.mgr.cancel(it.key) }

View File

@ -6,6 +6,7 @@ import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.ActivityTracker
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.createNewResources import com.topjohnwu.magisk.core.createNewResources
import com.topjohnwu.magisk.core.di.AppContext import com.topjohnwu.magisk.core.di.AppContext
@ -27,6 +28,11 @@ withContext(Dispatchers.Default) {
// Create a completely new resource to prevent cross talk over active configs // Create a completely new resource to prevent cross talk over active configs
val res = createNewResources() val res = createNewResources()
fun changeLocale(locale: Locale) {
res.configuration.setLocale(locale)
res.updateConfiguration(res.configuration, res.displayMetrics)
}
val locales = ArrayList<String>().apply { val locales = ArrayList<String>().apply {
// Add default locale // Add default locale
add("en") add("en")
@ -40,13 +46,13 @@ withContext(Dispatchers.Default) {
}.map { }.map {
Locale.forLanguageTag(it) Locale.forLanguageTag(it)
}.distinctBy { }.distinctBy {
res.setLocale(it) changeLocale(it)
res.getString(compareId) res.getString(compareId)
}.sortedWith { a, b -> }.sortedWith { a, b ->
a.getDisplayName(a).compareTo(b.getDisplayName(b), true) a.getDisplayName(a).compareTo(b.getDisplayName(b), true)
} }
res.setLocale(defaultLocale) changeLocale(defaultLocale)
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)
@ -70,11 +76,6 @@ fun Resources.setConfig(config: Configuration) {
fun Resources.syncLocale() = setConfig(configuration) fun Resources.syncLocale() = setConfig(configuration)
fun Resources.setLocale(locale: Locale) {
configuration.setLocale(locale)
updateConfiguration(configuration, displayMetrics)
}
fun refreshLocale() { fun refreshLocale() {
val localeConfig = Config.locale val localeConfig = Config.locale
currentLocale = when { currentLocale = when {
@ -83,4 +84,5 @@ fun refreshLocale() {
} }
Locale.setDefault(currentLocale) Locale.setDefault(currentLocale)
AppContext.resources.syncLocale() AppContext.resources.syncLocale()
ActivityTracker.foreground?.recreate()
} }

View File

@ -37,9 +37,10 @@ object Customization : BaseSettingsItem.Section() {
} }
object Language : BaseSettingsItem.Selector() { object Language : BaseSettingsItem.Selector() {
override var value = -1 override var value
get() = index
set(value) { set(value) {
field = value index = value
Config.locale = entryValues[value] Config.locale = entryValues[value]
} }
@ -47,6 +48,7 @@ object Language : BaseSettingsItem.Selector() {
private var entries = emptyArray<String>() private var entries = emptyArray<String>()
private var entryValues = emptyArray<String>() private var entryValues = emptyArray<String>()
private var index = -1
override fun entries(res: Resources) = entries override fun entries(res: Resources) = entries
override fun descriptions(res: Resources) = entries override fun descriptions(res: Resources) = entries
@ -62,7 +64,7 @@ object Language : BaseSettingsItem.Selector() {
entries = names entries = names
entryValues = values entryValues = values
val selectedLocale = currentLocale.getDisplayName(currentLocale) val selectedLocale = currentLocale.getDisplayName(currentLocale)
value = names.indexOfFirst { it == selectedLocale }.let { if (it == -1) 0 else it } index = names.indexOfFirst { it == selectedLocale }.let { if (it == -1) 0 else it }
notifyPropertyChanged(BR.description) notifyPropertyChanged(BR.description)
} }
} }

View File

@ -17,7 +17,6 @@ import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.databinding.adapterOf import com.topjohnwu.magisk.databinding.adapterOf
import com.topjohnwu.magisk.databinding.itemBindingOf import com.topjohnwu.magisk.databinding.itemBindingOf
import com.topjohnwu.magisk.events.AddHomeIconEvent import com.topjohnwu.magisk.events.AddHomeIconEvent
import com.topjohnwu.magisk.events.RecreateEvent
import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.SnackbarEvent
import com.topjohnwu.magisk.events.dialog.BiometricEvent import com.topjohnwu.magisk.events.dialog.BiometricEvent
import com.topjohnwu.magisk.ktx.activity import com.topjohnwu.magisk.ktx.activity
@ -108,7 +107,6 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
override fun onItemAction(view: View, item: BaseSettingsItem) { override fun onItemAction(view: View, item: BaseSettingsItem) {
when (item) { when (item) {
Language -> RecreateEvent().publish()
UpdateChannel -> openUrlIfNecessary(view) UpdateChannel -> openUrlIfNecessary(view)
is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) } is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) }
Restore -> viewModelScope.launch { HideAPK.restore(view.activity) } Restore -> viewModelScope.launch { HideAPK.restore(view.activity) }