Cleanup more code

This commit is contained in:
topjohnwu 2019-08-04 13:47:14 -07:00
parent 33b7ab593c
commit 71d855e836
14 changed files with 221 additions and 306 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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()
}
} }

View File

@ -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) }

View File

@ -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);
}
}

View File

@ -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
} }

View File

@ -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()

View File

@ -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?) {

View File

@ -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") }
} }
} }

View File

@ -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)
} }
} }

View File

@ -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)
} }
} }

View File

@ -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)
} }

View File

@ -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;
}
}

View 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
}
}