Cleanup more code
This commit is contained in:
parent
33b7ab593c
commit
71d855e836
@ -1,6 +1,5 @@
|
|||||||
package com.topjohnwu.magisk
|
package com.topjohnwu.magisk
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
@ -39,7 +38,6 @@ open class App : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deContext = base
|
deContext = base
|
||||||
self = this
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= 24) {
|
if (Build.VERSION.SDK_INT >= 24) {
|
||||||
deContext = base.createDeviceProtectedStorageContext()
|
deContext = base.createDeviceProtectedStorageContext()
|
||||||
@ -61,11 +59,6 @@ open class App : Application() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
@Deprecated("Use dependency injection")
|
|
||||||
@JvmStatic
|
|
||||||
lateinit var self: App
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
|
||||||
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER or Shell.FLAG_USE_MAGISK_BUSYBOX)
|
Shell.Config.setFlags(Shell.FLAG_MOUNT_MASTER or Shell.FLAG_USE_MAGISK_BUSYBOX)
|
||||||
|
@ -55,7 +55,7 @@ val ApplicationInfo.packageInfo: PackageInfo?
|
|||||||
val Uri.fileName: String
|
val Uri.fileName: String
|
||||||
get() {
|
get() {
|
||||||
var name: String? = null
|
var name: String? = null
|
||||||
App.self.contentResolver.query(this, null, null, null, null)?.use { c ->
|
get<Context>().contentResolver.query(this, null, null, null, null)?.use { c ->
|
||||||
val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
val nameIndex = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
||||||
if (nameIndex != -1) {
|
if (nameIndex != -1) {
|
||||||
c.moveToFirst()
|
c.moveToFirst()
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package com.topjohnwu.magisk.extensions
|
package com.topjohnwu.magisk.extensions
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
import androidx.core.net.toFile
|
import androidx.core.net.toFile
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
import java.util.*
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import java.util.zip.ZipInputStream
|
import java.util.zip.ZipInputStream
|
||||||
|
import kotlin.NoSuchElementException
|
||||||
|
|
||||||
fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) {
|
fun ZipInputStream.forEach(callback: (ZipEntry) -> Unit) {
|
||||||
var entry: ZipEntry? = nextEntry
|
var entry: ZipEntry? = nextEntry
|
||||||
@ -38,4 +41,63 @@ inline fun <T, R> List<T>.firstMap(mapper: (T) -> R?): R {
|
|||||||
return mapper(item) ?: continue
|
return mapper(item) ?: continue
|
||||||
}
|
}
|
||||||
throw NoSuchElementException("Collection contains no element matching the predicate.")
|
throw NoSuchElementException("Collection contains no element matching the predicate.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.langTagToLocale(): Locale {
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
return Locale.forLanguageTag(this)
|
||||||
|
} else {
|
||||||
|
val tok = split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
if (tok.isEmpty()) {
|
||||||
|
return Locale("")
|
||||||
|
}
|
||||||
|
val language = when (tok[0]) {
|
||||||
|
"und" -> "" // Undefined
|
||||||
|
"fil" -> "tl" // Filipino
|
||||||
|
else -> tok[0]
|
||||||
|
}
|
||||||
|
if (language.length != 2 && language.length != 3)
|
||||||
|
return Locale("")
|
||||||
|
if (tok.size == 1)
|
||||||
|
return Locale(language)
|
||||||
|
val country = tok[1]
|
||||||
|
|
||||||
|
return if (country.length != 2 && country.length != 3) Locale(language)
|
||||||
|
else Locale(language, country)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Locale.toLangTag(): String {
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
return toLanguageTag()
|
||||||
|
} else {
|
||||||
|
var language = language
|
||||||
|
var country = country
|
||||||
|
var variant = variant
|
||||||
|
when {
|
||||||
|
language.isEmpty() || !language.matches("\\p{Alpha}{2,8}".toRegex()) ->
|
||||||
|
language = "und" // Follow the Locale#toLanguageTag() implementation
|
||||||
|
language == "iw" -> language = "he" // correct deprecated "Hebrew"
|
||||||
|
language == "in" -> language = "id" // correct deprecated "Indonesian"
|
||||||
|
language == "ji" -> language = "yi" // correct deprecated "Yiddish"
|
||||||
|
}
|
||||||
|
// ensure valid country code, if not well formed, it's omitted
|
||||||
|
|
||||||
|
// variant subtags that begin with a letter must be at least 5 characters long
|
||||||
|
// ensure valid country code, if not well formed, it's omitted
|
||||||
|
if (!country.matches("\\p{Alpha}{2}|\\p{Digit}{3}".toRegex())) {
|
||||||
|
country = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// variant subtags that begin with a letter must be at least 5 characters long
|
||||||
|
if (!variant.matches("\\p{Alnum}{5,8}|\\p{Digit}\\p{Alnum}{3}".toRegex())) {
|
||||||
|
variant = ""
|
||||||
|
}
|
||||||
|
val tag = StringBuilder(language)
|
||||||
|
if (country.isNotEmpty())
|
||||||
|
tag.append('-').append(country)
|
||||||
|
if (variant.isNotEmpty())
|
||||||
|
tag.append('-').append(variant)
|
||||||
|
return tag.toString()
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.extensions
|
package com.topjohnwu.magisk.extensions
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager
|
import com.topjohnwu.magisk.utils.currentLocale
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -14,8 +14,7 @@ fun String.toTime(format: DateFormat) = try {
|
|||||||
-1L
|
-1L
|
||||||
}
|
}
|
||||||
|
|
||||||
private val locale get() = LocaleManager.locale
|
val timeFormatFull by lazy { SimpleDateFormat("yyyy/MM/dd_HH:mm:ss", currentLocale) }
|
||||||
val timeFormatFull by lazy { SimpleDateFormat("yyyy/MM/dd_HH:mm:ss", locale) }
|
val timeFormatStandard by lazy { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", currentLocale) }
|
||||||
val timeFormatStandard by lazy { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", locale) }
|
val timeFormatMedium by lazy { DateFormat.getDateInstance(DateFormat.MEDIUM, currentLocale) }
|
||||||
val timeFormatMedium by lazy { DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.locale) }
|
val timeFormatTime by lazy { SimpleDateFormat("h:mm a", currentLocale) }
|
||||||
val timeFormatTime by lazy { SimpleDateFormat("h:mm a", LocaleManager.locale) }
|
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.model.entity;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class SuLogEntry {
|
|
||||||
|
|
||||||
public int fromUid, toUid, fromPid;
|
|
||||||
public String packageName, appName, command;
|
|
||||||
public boolean action;
|
|
||||||
public Date date;
|
|
||||||
|
|
||||||
public SuLogEntry(MagiskPolicy policy) {
|
|
||||||
fromUid = policy.getUid();
|
|
||||||
packageName = policy.getPackageName();
|
|
||||||
appName = policy.getAppName();
|
|
||||||
action = policy.getPolicy() == Policy.ALLOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SuLogEntry(ContentValues values) {
|
|
||||||
fromUid = values.getAsInteger("from_uid");
|
|
||||||
packageName = values.getAsString("package_name");
|
|
||||||
appName = values.getAsString("app_name");
|
|
||||||
fromPid = values.getAsInteger("from_pid");
|
|
||||||
command = values.getAsString("command");
|
|
||||||
toUid = values.getAsInteger("to_uid");
|
|
||||||
action = values.getAsInteger("action") != 0;
|
|
||||||
date = new Date(values.getAsLong("time"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContentValues getContentValues() {
|
|
||||||
ContentValues values = new ContentValues();
|
|
||||||
values.put("from_uid", fromUid);
|
|
||||||
values.put("package_name", packageName);
|
|
||||||
values.put("app_name", appName);
|
|
||||||
values.put("from_pid", fromPid);
|
|
||||||
values.put("command", command);
|
|
||||||
values.put("to_uid", toUid);
|
|
||||||
values.put("action", action ? 1 : 0);
|
|
||||||
values.put("time", date.getTime());
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDateString() {
|
|
||||||
return DateFormat.getDateInstance(DateFormat.MEDIUM, LocaleManager.getLocale()).format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTimeString() {
|
|
||||||
return new SimpleDateFormat("h:mm a", LocaleManager.getLocale()).format(date);
|
|
||||||
}
|
|
||||||
}
|
|
@ -47,7 +47,7 @@ open class GeneralReceiver : BroadcastReceiver() {
|
|||||||
// Actual boot completed event
|
// Actual boot completed event
|
||||||
Shell.su("mm_patch_dtbo").submit { result ->
|
Shell.su("mm_patch_dtbo").submit { result ->
|
||||||
if (result.isSuccess)
|
if (result.isSuccess)
|
||||||
Notifications.dtboPatched()
|
Notifications.dtboPatched(context)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ class UpdateCheckService : DelegateWorker() {
|
|||||||
return runCatching {
|
return runCatching {
|
||||||
magiskRepo.fetchUpdate().blockingGet()
|
magiskRepo.fetchUpdate().blockingGet()
|
||||||
if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode)
|
if (BuildConfig.VERSION_CODE < Info.remote.app.versionCode)
|
||||||
Notifications.managerUpdate()
|
Notifications.managerUpdate(applicationContext)
|
||||||
else if (Info.magiskVersionCode < Info.remote.magisk.versionCode)
|
else if (Info.magiskVersionCode < Info.remote.magisk.versionCode)
|
||||||
Notifications.magiskUpdate()
|
Notifications.magiskUpdate(applicationContext)
|
||||||
ListenableWorker.Result.success()
|
ListenableWorker.Result.success()
|
||||||
}.getOrElse {
|
}.getOrElse {
|
||||||
ListenableWorker.Result.failure()
|
ListenableWorker.Result.failure()
|
||||||
|
@ -32,6 +32,7 @@ import com.topjohnwu.magisk.model.navigation.Navigator
|
|||||||
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
|
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager
|
import com.topjohnwu.magisk.utils.LocaleManager
|
||||||
import com.topjohnwu.magisk.utils.Utils
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
|
import com.topjohnwu.magisk.utils.currentLocale
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -68,12 +69,12 @@ abstract class MagiskActivity<ViewModel : MagiskViewModel, Binding : ViewDataBin
|
|||||||
|
|
||||||
override fun applyOverrideConfiguration(config: Configuration?) {
|
override fun applyOverrideConfiguration(config: Configuration?) {
|
||||||
// Force applying our preferred local
|
// Force applying our preferred local
|
||||||
config?.setLocale(LocaleManager.locale)
|
config?.setLocale(currentLocale)
|
||||||
super.applyOverrideConfiguration(config)
|
super.applyOverrideConfiguration(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context) {
|
override fun attachBaseContext(base: Context) {
|
||||||
super.attachBaseContext(LocaleManager.getLocaleContext(base, LocaleManager.locale))
|
super.attachBaseContext(LocaleManager.getLocaleContext(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
package com.topjohnwu.magisk.ui.home
|
package com.topjohnwu.magisk.ui.home
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.skoumal.teanity.extensions.subscribeK
|
import com.skoumal.teanity.extensions.subscribeK
|
||||||
import com.skoumal.teanity.viewevents.ViewEvent
|
import com.skoumal.teanity.viewevents.ViewEvent
|
||||||
import com.topjohnwu.magisk.*
|
import com.topjohnwu.magisk.BuildConfig
|
||||||
|
import com.topjohnwu.magisk.Const
|
||||||
|
import com.topjohnwu.magisk.Info
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
||||||
import com.topjohnwu.magisk.databinding.FragmentMagiskBinding
|
import com.topjohnwu.magisk.databinding.FragmentMagiskBinding
|
||||||
|
import com.topjohnwu.magisk.extensions.get
|
||||||
import com.topjohnwu.magisk.extensions.inject
|
import com.topjohnwu.magisk.extensions.inject
|
||||||
import com.topjohnwu.magisk.extensions.writeTo
|
import com.topjohnwu.magisk.extensions.writeTo
|
||||||
import com.topjohnwu.magisk.model.events.*
|
import com.topjohnwu.magisk.model.events.*
|
||||||
@ -114,7 +119,7 @@ class HomeFragment : MagiskFragment<HomeViewModel, FragmentMagiskBinding>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EXT_APK = File("${App.self.filesDir.parent}/snet", "snet.apk")
|
val EXT_APK by lazy { File("${get<Context>().filesDir.parent}/snet", "snet.apk") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,15 +21,13 @@ import com.topjohnwu.magisk.Const
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.data.database.RepoDao
|
import com.topjohnwu.magisk.data.database.RepoDao
|
||||||
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
|
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
|
||||||
|
import com.topjohnwu.magisk.extensions.toLangTag
|
||||||
import com.topjohnwu.magisk.model.download.DownloadService
|
import com.topjohnwu.magisk.model.download.DownloadService
|
||||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||||
import com.topjohnwu.magisk.model.observer.Observer
|
import com.topjohnwu.magisk.model.observer.Observer
|
||||||
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment
|
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment
|
||||||
import com.topjohnwu.magisk.utils.FingerprintHelper
|
import com.topjohnwu.magisk.utils.*
|
||||||
import com.topjohnwu.magisk.utils.LocaleManager
|
|
||||||
import com.topjohnwu.magisk.utils.PatchAPK
|
|
||||||
import com.topjohnwu.magisk.utils.Utils
|
|
||||||
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
|
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
|
||||||
import com.topjohnwu.net.Networking
|
import com.topjohnwu.net.Networking
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
@ -226,21 +224,18 @@ class SettingsFragment : BasePreferenceFragment() {
|
|||||||
|
|
||||||
private fun setLocalePreference(lp: ListPreference) {
|
private fun setLocalePreference(lp: ListPreference) {
|
||||||
lp.isEnabled = false
|
lp.isEnabled = false
|
||||||
LocaleManager.availableLocales
|
availableLocales.map {
|
||||||
.map {
|
|
||||||
val names = mutableListOf<String>()
|
val names = mutableListOf<String>()
|
||||||
val values = mutableListOf<String>()
|
val values = mutableListOf<String>()
|
||||||
|
|
||||||
names.add(
|
names.add(
|
||||||
LocaleManager.getString(
|
LocaleManager.getString(defaultLocale, R.string.system_default)
|
||||||
LocaleManager.defaultLocale, R.string.system_default
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
values.add("")
|
values.add("")
|
||||||
|
|
||||||
it.forEach { locale ->
|
it.forEach { locale ->
|
||||||
names.add(locale.getDisplayName(locale))
|
names.add(locale.getDisplayName(locale))
|
||||||
values.add(LocaleManager.toLanguageTag(locale))
|
values.add(locale.toLangTag())
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair(names.toTypedArray(), values.toTypedArray())
|
Pair(names.toTypedArray(), values.toTypedArray())
|
||||||
@ -248,7 +243,7 @@ class SettingsFragment : BasePreferenceFragment() {
|
|||||||
lp.isEnabled = true
|
lp.isEnabled = true
|
||||||
lp.entries = names
|
lp.entries = names
|
||||||
lp.entryValues = values
|
lp.entryValues = values
|
||||||
lp.summary = LocaleManager.locale.getDisplayName(LocaleManager.locale)
|
lp.summary = currentLocale.getDisplayName(currentLocale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,133 +4,65 @@ import android.content.Context
|
|||||||
import android.content.ContextWrapper
|
import android.content.ContextWrapper
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.os.Build
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.topjohnwu.magisk.App
|
|
||||||
import com.topjohnwu.magisk.Config
|
import com.topjohnwu.magisk.Config
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.extensions.get
|
||||||
import com.topjohnwu.magisk.extensions.inject
|
import com.topjohnwu.magisk.extensions.inject
|
||||||
|
import com.topjohnwu.magisk.extensions.langTagToLocale
|
||||||
import com.topjohnwu.superuser.internal.InternalUtils
|
import com.topjohnwu.superuser.internal.InternalUtils
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
object LocaleManager {
|
var currentLocale = Locale.getDefault()!!
|
||||||
@JvmStatic
|
private set
|
||||||
var locale = Locale.getDefault()
|
|
||||||
@JvmStatic
|
|
||||||
val defaultLocale = Locale.getDefault()
|
|
||||||
|
|
||||||
@JvmStatic
|
val defaultLocale = Locale.getDefault()!!
|
||||||
val availableLocales = Single.fromCallable {
|
|
||||||
val compareId = R.string.app_changelog
|
|
||||||
val res: Resources by inject()
|
|
||||||
mutableListOf<Locale>().apply {
|
|
||||||
// Add default locale
|
|
||||||
add(Locale.ENGLISH)
|
|
||||||
|
|
||||||
// Add some special locales
|
val availableLocales = Single.fromCallable {
|
||||||
add(Locale.TAIWAN)
|
val compareId = R.string.app_changelog
|
||||||
add(Locale("pt", "BR"))
|
val res: Resources by inject()
|
||||||
|
mutableListOf<Locale>().apply {
|
||||||
|
// Add default locale
|
||||||
|
add(Locale.ENGLISH)
|
||||||
|
|
||||||
// Other locales
|
// Add some special locales
|
||||||
val otherLocales = res.assets.locales
|
add(Locale.TAIWAN)
|
||||||
.map { forLanguageTag(it) }
|
add(Locale("pt", "BR"))
|
||||||
.distinctBy { getString(it, compareId) }
|
|
||||||
|
|
||||||
listOf("", "").toTypedArray()
|
// Other locales
|
||||||
|
val otherLocales = res.assets.locales
|
||||||
|
.map { it.langTagToLocale() }
|
||||||
|
.distinctBy { LocaleManager.getString(it, compareId) }
|
||||||
|
|
||||||
addAll(otherLocales)
|
listOf("", "").toTypedArray()
|
||||||
}.sortedWith(Comparator { a, b ->
|
|
||||||
a.getDisplayName(a).toLowerCase(a)
|
addAll(otherLocales)
|
||||||
|
}.sortedWith(Comparator { a, b ->
|
||||||
|
a.getDisplayName(a).toLowerCase(a)
|
||||||
.compareTo(b.getDisplayName(b).toLowerCase(b))
|
.compareTo(b.getDisplayName(b).toLowerCase(b))
|
||||||
})
|
})
|
||||||
}.cache()
|
}.cache()!!
|
||||||
|
|
||||||
private fun forLanguageTag(tag: String): Locale {
|
object LocaleManager {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
return Locale.forLanguageTag(tag)
|
|
||||||
} else {
|
|
||||||
val tok = tag.split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
|
||||||
if (tok.isEmpty()) {
|
|
||||||
return Locale("")
|
|
||||||
}
|
|
||||||
val language = when (tok[0]) {
|
|
||||||
"und" -> "" // Undefined
|
|
||||||
"fil" -> "tl" // Filipino
|
|
||||||
else -> tok[0]
|
|
||||||
}
|
|
||||||
if (language.length != 2 && language.length != 3)
|
|
||||||
return Locale("")
|
|
||||||
if (tok.size == 1)
|
|
||||||
return Locale(language)
|
|
||||||
val country = tok[1]
|
|
||||||
|
|
||||||
return if (country.length != 2 && country.length != 3) Locale(language)
|
|
||||||
else Locale(language, country)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun toLanguageTag(loc: Locale): String {
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
return loc.toLanguageTag()
|
|
||||||
} else {
|
|
||||||
var language = loc.language
|
|
||||||
var country = loc.country
|
|
||||||
var variant = loc.variant
|
|
||||||
when {
|
|
||||||
language.isEmpty() || !language.matches("\\p{Alpha}{2,8}".toRegex()) ->
|
|
||||||
language = "und" // Follow the Locale#toLanguageTag() implementation
|
|
||||||
language == "iw" -> language = "he" // correct deprecated "Hebrew"
|
|
||||||
language == "in" -> language = "id" // correct deprecated "Indonesian"
|
|
||||||
language == "ji" -> language = "yi" // correct deprecated "Yiddish"
|
|
||||||
}
|
|
||||||
// ensure valid country code, if not well formed, it's omitted
|
|
||||||
|
|
||||||
// variant subtags that begin with a letter must be at least 5 characters long
|
|
||||||
// ensure valid country code, if not well formed, it's omitted
|
|
||||||
if (!country.matches("\\p{Alpha}{2}|\\p{Digit}{3}".toRegex())) {
|
|
||||||
country = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// variant subtags that begin with a letter must be at least 5 characters long
|
|
||||||
if (!variant.matches("\\p{Alnum}{5,8}|\\p{Digit}\\p{Alnum}{3}".toRegex())) {
|
|
||||||
variant = ""
|
|
||||||
}
|
|
||||||
val tag = StringBuilder(language)
|
|
||||||
if (country.isNotEmpty())
|
|
||||||
tag.append('-').append(country)
|
|
||||||
if (variant.isNotEmpty())
|
|
||||||
tag.append('-').append(variant)
|
|
||||||
return tag.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun setLocale(wrapper: ContextWrapper) {
|
fun setLocale(wrapper: ContextWrapper) {
|
||||||
val localeConfig = Config.locale
|
val localeConfig = Config.locale
|
||||||
locale = when {
|
currentLocale = when {
|
||||||
localeConfig.isEmpty() -> defaultLocale
|
localeConfig.isEmpty() -> defaultLocale
|
||||||
else -> forLanguageTag(localeConfig)
|
else -> localeConfig.langTagToLocale()
|
||||||
}
|
}
|
||||||
Locale.setDefault(locale)
|
Locale.setDefault(currentLocale)
|
||||||
InternalUtils.replaceBaseContext(wrapper, getLocaleContext(locale))
|
InternalUtils.replaceBaseContext(wrapper, getLocaleContext(wrapper, currentLocale))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
fun getLocaleContext(context: Context, locale: Locale = currentLocale): Context {
|
||||||
fun getLocaleContext(context: Context, locale: Locale): Context {
|
|
||||||
val config = Configuration(context.resources.configuration)
|
val config = Configuration(context.resources.configuration)
|
||||||
config.setLocale(locale)
|
config.setLocale(locale)
|
||||||
return context.createConfigurationContext(config)
|
return context.createConfigurationContext(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getLocaleContext(locale: Locale): Context {
|
|
||||||
return getLocaleContext(App.self.baseContext, locale)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getString(locale: Locale, @StringRes id: Int): String {
|
fun getString(locale: Locale, @StringRes id: Int): String {
|
||||||
return getLocaleContext(locale).getString(id)
|
return getLocaleContext(get(), locale).getString(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import com.topjohnwu.magisk.*
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.extensions.get
|
import com.topjohnwu.magisk.extensions.get
|
||||||
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
||||||
import com.topjohnwu.net.Networking
|
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -24,8 +23,7 @@ import java.util.concurrent.TimeUnit
|
|||||||
|
|
||||||
object Utils {
|
object Utils {
|
||||||
|
|
||||||
val isCanary: Boolean
|
val isCanary: Boolean = BuildConfig.VERSION_NAME.contains("-")
|
||||||
get() = BuildConfig.VERSION_NAME.contains("-")
|
|
||||||
|
|
||||||
fun toast(msg: CharSequence, duration: Int) {
|
fun toast(msg: CharSequence, duration: Int) {
|
||||||
UiThreadHandler.run { Toast.makeText(get(), msg, duration).show() }
|
UiThreadHandler.run { Toast.makeText(get(), msg, duration).show() }
|
||||||
@ -35,11 +33,6 @@ object Utils {
|
|||||||
UiThreadHandler.run { Toast.makeText(get(), resId, duration).show() }
|
UiThreadHandler.run { Toast.makeText(get(), resId, duration).show() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dlString(url: String): String {
|
|
||||||
val s = Networking.get(url).execForString().result
|
|
||||||
return s ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPrefsInt(prefs: SharedPreferences, key: String, def: Int = 0): Int {
|
fun getPrefsInt(prefs: SharedPreferences, key: String, def: Int = 0): Int {
|
||||||
return prefs.getString(key, def.toString())!!.toInt()
|
return prefs.getString(key, def.toString())!!.toInt()
|
||||||
}
|
}
|
||||||
@ -58,7 +51,7 @@ object Utils {
|
|||||||
if (info.labelRes > 0) {
|
if (info.labelRes > 0) {
|
||||||
val res = pm.getResourcesForApplication(info)
|
val res = pm.getResourcesForApplication(info)
|
||||||
val config = Configuration()
|
val config = Configuration()
|
||||||
config.setLocale(LocaleManager.locale)
|
config.setLocale(currentLocale)
|
||||||
res.updateConfiguration(config, res.displayMetrics)
|
res.updateConfiguration(config, res.displayMetrics)
|
||||||
return res.getString(info.labelRes)
|
return res.getString(info.labelRes)
|
||||||
}
|
}
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.view;
|
|
||||||
|
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
|
||||||
import androidx.core.app.TaskStackBuilder;
|
|
||||||
|
|
||||||
import com.topjohnwu.magisk.App;
|
|
||||||
import com.topjohnwu.magisk.ClassMap;
|
|
||||||
import com.topjohnwu.magisk.Const;
|
|
||||||
import com.topjohnwu.magisk.Info;
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver;
|
|
||||||
import com.topjohnwu.magisk.ui.SplashActivity;
|
|
||||||
|
|
||||||
public class Notifications {
|
|
||||||
|
|
||||||
public static NotificationManagerCompat mgr = NotificationManagerCompat.from(App.self);
|
|
||||||
|
|
||||||
public static void setup(Context c) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
mgr.deleteNotificationChannel("magisk_notification");
|
|
||||||
NotificationChannel channel =
|
|
||||||
new NotificationChannel(Const.ID.UPDATE_NOTIFICATION_CHANNEL,
|
|
||||||
c.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT);
|
|
||||||
mgr.createNotificationChannel(channel);
|
|
||||||
channel = new NotificationChannel(Const.ID.PROGRESS_NOTIFICATION_CHANNEL,
|
|
||||||
c.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW);
|
|
||||||
mgr.createNotificationChannel(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void magiskUpdate() {
|
|
||||||
App app = App.self;
|
|
||||||
|
|
||||||
Intent intent = new Intent(app, ClassMap.get(SplashActivity.class));
|
|
||||||
intent.putExtra(Const.Key.OPEN_SECTION, "magisk");
|
|
||||||
TaskStackBuilder stackBuilder = TaskStackBuilder.create(app);
|
|
||||||
stackBuilder.addParentStack(ClassMap.get(SplashActivity.class));
|
|
||||||
stackBuilder.addNextIntent(intent);
|
|
||||||
PendingIntent pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL);
|
|
||||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
|
||||||
.setContentTitle(app.getString(R.string.magisk_update_title))
|
|
||||||
.setContentText(app.getString(R.string.manager_download_install))
|
|
||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentIntent(pendingIntent);
|
|
||||||
|
|
||||||
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void managerUpdate() {
|
|
||||||
App app = App.self;
|
|
||||||
|
|
||||||
Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class));
|
|
||||||
intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE);
|
|
||||||
intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.getApp());
|
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
|
|
||||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL);
|
|
||||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
|
||||||
.setContentTitle(app.getString(R.string.manager_update_title))
|
|
||||||
.setContentText(app.getString(R.string.manager_download_install))
|
|
||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentIntent(pendingIntent);
|
|
||||||
|
|
||||||
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void dtboPatched() {
|
|
||||||
App app = App.self;
|
|
||||||
|
|
||||||
Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class))
|
|
||||||
.setAction(Const.Key.BROADCAST_REBOOT);
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
|
|
||||||
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(app, Const.ID.UPDATE_NOTIFICATION_CHANNEL);
|
|
||||||
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
|
||||||
.setContentTitle(app.getString(R.string.dtbo_patched_title))
|
|
||||||
.setContentText(app.getString(R.string.dtbo_patched_reboot))
|
|
||||||
.setVibrate(new long[]{0, 100, 100, 100})
|
|
||||||
.addAction(R.drawable.ic_refresh, app.getString(R.string.reboot), pendingIntent);
|
|
||||||
|
|
||||||
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NotificationCompat.Builder progress(Context context, CharSequence title) {
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, Const.ID.PROGRESS_NOTIFICATION_CHANNEL);
|
|
||||||
builder.setPriority(NotificationCompat.PRIORITY_LOW)
|
|
||||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setProgress(0, 0, true)
|
|
||||||
.setOngoing(true);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
}
|
|
100
app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
Normal file
100
app/src/main/java/com/topjohnwu/magisk/view/Notifications.kt
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package com.topjohnwu.magisk.view
|
||||||
|
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.app.TaskStackBuilder
|
||||||
|
import com.topjohnwu.magisk.ClassMap
|
||||||
|
import com.topjohnwu.magisk.Const
|
||||||
|
import com.topjohnwu.magisk.Info
|
||||||
|
import com.topjohnwu.magisk.R
|
||||||
|
import com.topjohnwu.magisk.extensions.get
|
||||||
|
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||||
|
import com.topjohnwu.magisk.ui.SplashActivity
|
||||||
|
|
||||||
|
object Notifications {
|
||||||
|
|
||||||
|
val mgr by lazy { NotificationManagerCompat.from(get()) }
|
||||||
|
|
||||||
|
fun setup(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
mgr.deleteNotificationChannel("magisk_notification")
|
||||||
|
var channel = NotificationChannel(Const.ID.UPDATE_NOTIFICATION_CHANNEL,
|
||||||
|
context.getString(R.string.update_channel), NotificationManager.IMPORTANCE_DEFAULT)
|
||||||
|
mgr.createNotificationChannel(channel)
|
||||||
|
channel = NotificationChannel(Const.ID.PROGRESS_NOTIFICATION_CHANNEL,
|
||||||
|
context.getString(R.string.progress_channel), NotificationManager.IMPORTANCE_LOW)
|
||||||
|
mgr.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun magiskUpdate(context: Context) {
|
||||||
|
val intent = Intent(context, ClassMap[SplashActivity::class.java])
|
||||||
|
intent.putExtra(Const.Key.OPEN_SECTION, "magisk")
|
||||||
|
val stackBuilder = TaskStackBuilder.create(context)
|
||||||
|
stackBuilder.addParentStack(ClassMap.get<Class<*>>(SplashActivity::class.java))
|
||||||
|
stackBuilder.addNextIntent(intent)
|
||||||
|
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
|
||||||
|
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
||||||
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
|
.setContentTitle(context.getString(R.string.magisk_update_title))
|
||||||
|
.setContentText(context.getString(R.string.manager_download_install))
|
||||||
|
.setVibrate(longArrayOf(0, 100, 100, 100))
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
|
||||||
|
mgr.notify(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun managerUpdate(context: Context) {
|
||||||
|
val intent = Intent(context, ClassMap[GeneralReceiver::class.java])
|
||||||
|
intent.action = Const.Key.BROADCAST_MANAGER_UPDATE
|
||||||
|
intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
|
||||||
|
|
||||||
|
val pendingIntent = PendingIntent.getBroadcast(context,
|
||||||
|
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
|
||||||
|
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
||||||
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
|
.setContentTitle(context.getString(R.string.manager_update_title))
|
||||||
|
.setContentText(context.getString(R.string.manager_download_install))
|
||||||
|
.setVibrate(longArrayOf(0, 100, 100, 100))
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
|
||||||
|
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dtboPatched(context: Context) {
|
||||||
|
val intent = Intent(context, ClassMap[GeneralReceiver::class.java])
|
||||||
|
.setAction(Const.Key.BROADCAST_REBOOT)
|
||||||
|
val pendingIntent = PendingIntent.getBroadcast(context,
|
||||||
|
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
|
|
||||||
|
val builder = NotificationCompat.Builder(context, Const.ID.UPDATE_NOTIFICATION_CHANNEL)
|
||||||
|
builder.setSmallIcon(R.drawable.ic_magisk_outline)
|
||||||
|
.setContentTitle(context.getString(R.string.dtbo_patched_title))
|
||||||
|
.setContentText(context.getString(R.string.dtbo_patched_reboot))
|
||||||
|
.setVibrate(longArrayOf(0, 100, 100, 100))
|
||||||
|
.addAction(R.drawable.ic_refresh, context.getString(R.string.reboot), pendingIntent)
|
||||||
|
|
||||||
|
mgr.notify(Const.ID.DTBO_NOTIFICATION_ID, builder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun progress(context: Context, title: CharSequence): NotificationCompat.Builder {
|
||||||
|
val builder = NotificationCompat.Builder(context, Const.ID.PROGRESS_NOTIFICATION_CHANNEL)
|
||||||
|
builder.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
|
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setProgress(0, 0, true)
|
||||||
|
.setOngoing(true)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user