mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 20:15:29 +00:00
Separate core components
This commit is contained in:
parent
ba1a2fbce4
commit
707d7b3342
10
app/proguard-rules.pro
vendored
10
app/proguard-rules.pro
vendored
@ -17,9 +17,9 @@
|
||||
#}
|
||||
|
||||
# Snet
|
||||
-keepclassmembers class com.topjohnwu.magisk.utils.SafetyNetHelper { *; }
|
||||
-keep,allowobfuscation interface com.topjohnwu.magisk.utils.SafetyNetHelper$Callback
|
||||
-keepclassmembers class * implements com.topjohnwu.magisk.utils.SafetyNetHelper$Callback {
|
||||
-keepclassmembers class com.topjohnwu.magisk.core.utils.SafetyNetHelper { *; }
|
||||
-keep,allowobfuscation interface com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback
|
||||
-keepclassmembers class * implements com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback {
|
||||
void onResponse(int);
|
||||
}
|
||||
|
||||
@ -29,13 +29,13 @@
|
||||
}
|
||||
|
||||
# DelegateWorker
|
||||
-keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker
|
||||
-keep,allowobfuscation class * extends com.topjohnwu.magisk.core.base.BaseWorkerWrapper
|
||||
|
||||
# BootSigner
|
||||
-keep class a.a { *; }
|
||||
|
||||
# Workaround R8 bug
|
||||
-keep,allowobfuscation class com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||
-keep,allowobfuscation class com.topjohnwu.magisk.core.GeneralReceiver
|
||||
-keepclassmembers class a.e { *; }
|
||||
|
||||
# Strip logging
|
||||
|
@ -1,6 +1,6 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.utils.PatchAPK;
|
||||
import com.topjohnwu.magisk.core.utils.PatchAPK;
|
||||
import com.topjohnwu.signing.BootSigner;
|
||||
|
||||
public class a {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.ui.SplashActivity;
|
||||
import com.topjohnwu.magisk.core.SplashActivity;
|
||||
|
||||
public class c extends SplashActivity {
|
||||
/* stub */
|
||||
|
@ -1,6 +1,6 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.App;
|
||||
import com.topjohnwu.magisk.core.App;
|
||||
|
||||
public class e extends App {
|
||||
public e() {
|
||||
|
@ -5,7 +5,7 @@ import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import com.topjohnwu.magisk.model.update.UpdateCheckService;
|
||||
import com.topjohnwu.magisk.core.UpdateCheckService;
|
||||
|
||||
public class g extends w<UpdateCheckService> {
|
||||
/* Stub */
|
||||
|
@ -1,6 +1,6 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver;
|
||||
import com.topjohnwu.magisk.core.GeneralReceiver;
|
||||
|
||||
public class h extends GeneralReceiver {
|
||||
/* stub */
|
||||
|
@ -1,6 +1,6 @@
|
||||
package a;
|
||||
|
||||
import com.topjohnwu.magisk.model.download.DownloadService;
|
||||
import com.topjohnwu.magisk.core.download.DownloadService;
|
||||
|
||||
public class j extends DownloadService {
|
||||
/* stub */
|
||||
|
@ -6,11 +6,11 @@ import androidx.annotation.NonNull;
|
||||
import androidx.work.Worker;
|
||||
import androidx.work.WorkerParameters;
|
||||
|
||||
import com.topjohnwu.magisk.base.DelegateWorker;
|
||||
import com.topjohnwu.magisk.core.base.BaseWorkerWrapper;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
||||
public abstract class w<T extends DelegateWorker> extends Worker {
|
||||
public abstract class w<T extends BaseWorkerWrapper> extends Worker {
|
||||
|
||||
/* Wrapper class to workaround Proguard -keep class * extends Worker */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
@ -9,6 +9,12 @@ import androidx.room.Room
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.impl.WorkDatabase
|
||||
import androidx.work.impl.WorkDatabase_Impl
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.FileProvider
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||
import com.topjohnwu.magisk.core.utils.RootInit
|
||||
import com.topjohnwu.magisk.core.utils.updateConfig
|
||||
import com.topjohnwu.magisk.data.database.RepoDatabase
|
||||
import com.topjohnwu.magisk.data.database.RepoDatabase_Impl
|
||||
import com.topjohnwu.magisk.data.database.SuLogDatabase
|
||||
@ -17,9 +23,6 @@ import com.topjohnwu.magisk.di.ActivityTracker
|
||||
import com.topjohnwu.magisk.di.koinModules
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.unwrap
|
||||
import com.topjohnwu.magisk.utils.RootInit
|
||||
import com.topjohnwu.magisk.utils.SuHandler
|
||||
import com.topjohnwu.magisk.utils.updateConfig
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.core.context.startKoin
|
||||
@ -37,7 +40,7 @@ open class App() : Application() {
|
||||
Shell.Config.verboseLogging(BuildConfig.DEBUG)
|
||||
Shell.Config.addInitializers(RootInit::class.java)
|
||||
Shell.Config.setTimeout(2)
|
||||
FileProvider.callHandler = SuHandler
|
||||
FileProvider.callHandler = SuCallbackHandler
|
||||
Room.setFactory {
|
||||
when (it) {
|
||||
WorkDatabase::class.java -> WorkDatabase_Impl()
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
@ -6,16 +6,17 @@ import android.os.Environment
|
||||
import android.util.Xml
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.edit
|
||||
import com.topjohnwu.magisk.data.database.SettingsDao
|
||||
import com.topjohnwu.magisk.data.database.StringDao
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.core.magiskdb.SettingsDao
|
||||
import com.topjohnwu.magisk.core.magiskdb.StringDao
|
||||
import com.topjohnwu.magisk.data.repository.DBConfig
|
||||
import com.topjohnwu.magisk.di.Protected
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.model.preference.PreferenceModel
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import com.topjohnwu.magisk.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||
@ -115,12 +116,24 @@ object Config : PreferenceModel, DBConfig {
|
||||
var bootId by preference(Key.BOOT_ID, "")
|
||||
|
||||
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
|
||||
var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE)
|
||||
var repoOrder by preference(
|
||||
Key.REPO_ORDER,
|
||||
Value.ORDER_DATE
|
||||
)
|
||||
|
||||
var suDefaultTimeout by preferenceStrInt(Key.SU_REQUEST_TIMEOUT, 10)
|
||||
var suAutoReponse by preferenceStrInt(Key.SU_AUTO_RESPONSE, Value.SU_PROMPT)
|
||||
var suNotification by preferenceStrInt(Key.SU_NOTIFICATION, Value.NOTIFICATION_TOAST)
|
||||
var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel)
|
||||
var suAutoReponse by preferenceStrInt(
|
||||
Key.SU_AUTO_RESPONSE,
|
||||
Value.SU_PROMPT
|
||||
)
|
||||
var suNotification by preferenceStrInt(
|
||||
Key.SU_NOTIFICATION,
|
||||
Value.NOTIFICATION_TOAST
|
||||
)
|
||||
var updateChannel by preferenceStrInt(
|
||||
Key.UPDATE_CHANNEL,
|
||||
defaultChannel
|
||||
)
|
||||
|
||||
var safetyNotice by preference(Key.SAFETY, true)
|
||||
var darkThemeExtended by preference(
|
||||
@ -139,9 +152,18 @@ object Config : PreferenceModel, DBConfig {
|
||||
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
|
||||
var locale by preference(Key.LOCALE, "")
|
||||
|
||||
var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB)
|
||||
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER)
|
||||
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY)
|
||||
var rootMode by dbSettings(
|
||||
Key.ROOT_ACCESS,
|
||||
Value.ROOT_ACCESS_APPS_AND_ADB
|
||||
)
|
||||
var suMntNamespaceMode by dbSettings(
|
||||
Key.SU_MNT_NS,
|
||||
Value.NAMESPACE_MODE_REQUESTER
|
||||
)
|
||||
var suMultiuserMode by dbSettings(
|
||||
Key.SU_MULTIUSER_MODE,
|
||||
Value.MULTIUSER_MODE_OWNER_ONLY
|
||||
)
|
||||
var suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
|
||||
var suManager by dbStrings(Key.SU_MANAGER, "", true)
|
||||
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
|
||||
@ -177,7 +199,9 @@ object Config : PreferenceModel, DBConfig {
|
||||
}
|
||||
|
||||
private fun parsePrefs(editor: SharedPreferences.Editor) = editor.apply {
|
||||
val config = SuFile.open("/data/adb", Const.MANAGER_CONFIGS)
|
||||
val config = SuFile.open("/data/adb",
|
||||
Const.MANAGER_CONFIGS
|
||||
)
|
||||
if (config.exists()) runCatching {
|
||||
val input = SuFileInputStream(config)
|
||||
val parser = Xml.newPullParser()
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.os.Process
|
||||
import java.io.File
|
@ -1,19 +1,16 @@
|
||||
package com.topjohnwu.magisk.model.receiver
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.base.BaseReceiver
|
||||
import com.topjohnwu.magisk.data.database.PolicyDao
|
||||
import com.topjohnwu.magisk.core.base.BaseReceiver
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||
import com.topjohnwu.magisk.extensions.reboot
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.entity.ManagerJson
|
||||
import com.topjohnwu.magisk.core.model.ManagerJson
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.utils.SuHandler
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.magisk.core.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.core.inject
|
||||
|
||||
@ -30,7 +27,11 @@ open class GeneralReceiver : BaseReceiver() {
|
||||
|
||||
when (intent.action ?: return) {
|
||||
Intent.ACTION_REBOOT -> {
|
||||
SuHandler(context, intent.getStringExtra("action"), intent.extras)
|
||||
SuCallbackHandler(
|
||||
context,
|
||||
intent.getStringExtra("action"),
|
||||
intent.extras
|
||||
)
|
||||
}
|
||||
Intent.ACTION_PACKAGE_REPLACED -> {
|
||||
// This will only work pre-O
|
@ -1,6 +1,6 @@
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.topjohnwu.magisk
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.job.JobInfo
|
||||
@ -14,16 +14,15 @@ import android.content.res.AssetManager
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.ProcessPhoenix
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.utils.refreshLocale
|
||||
import com.topjohnwu.magisk.core.utils.updateConfig
|
||||
import com.topjohnwu.magisk.extensions.forceGetDeclaredField
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
import com.topjohnwu.magisk.ui.SplashActivity
|
||||
import com.topjohnwu.magisk.legacy.flash.FlashActivity
|
||||
import com.topjohnwu.magisk.legacy.surequest.SuRequestActivity
|
||||
import com.topjohnwu.magisk.utils.refreshLocale
|
||||
import com.topjohnwu.magisk.utils.updateConfig
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
|
||||
fun AssetManager.addAssetPath(path: String) {
|
||||
DynAPK.addAssetPath(this, path)
|
@ -1,9 +1,10 @@
|
||||
package com.topjohnwu.magisk
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.model.entity.UpdateInfo
|
||||
import com.topjohnwu.magisk.utils.CachedValue
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.superuser.Shell
|
@ -1,16 +1,13 @@
|
||||
package com.topjohnwu.magisk.ui
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.model.navigation.Navigation
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.magisk.wrap
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import com.topjohnwu.magisk.core.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
|
@ -1,15 +1,14 @@
|
||||
package com.topjohnwu.magisk.model.update
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import androidx.work.ListenableWorker
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.base.DelegateWorker
|
||||
import com.topjohnwu.magisk.core.base.BaseWorkerWrapper
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
class UpdateCheckService : DelegateWorker() {
|
||||
class UpdateCheckService : BaseWorkerWrapper() {
|
||||
|
||||
private val magiskRepo: MagiskRepository by inject()
|
||||
|
@ -1,47 +1,26 @@
|
||||
package com.topjohnwu.magisk.base
|
||||
package com.topjohnwu.magisk.core.base
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.collection.SparseArrayCompat
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import com.topjohnwu.magisk.extensions.set
|
||||
import com.topjohnwu.magisk.model.events.EventHandler
|
||||
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
|
||||
import com.topjohnwu.magisk.utils.currentLocale
|
||||
import com.topjohnwu.magisk.wrap
|
||||
import kotlin.random.Random
|
||||
|
||||
typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit
|
||||
typealias RequestCallback = BaseActivity.(Int, Intent?) -> Unit
|
||||
|
||||
abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
AppCompatActivity(), EventHandler {
|
||||
|
||||
protected lateinit var binding: Binding
|
||||
protected abstract val layoutRes: Int
|
||||
protected abstract val viewModel: ViewModel
|
||||
protected open val themeRes: Int = R.style.MagiskTheme
|
||||
|
||||
open val snackbarView get() = binding.root
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
||||
private val resultCallbacks by lazy { SparseArrayCompat<RequestCallback>() }
|
||||
|
||||
init {
|
||||
val theme = Config.darkThemeExtended
|
||||
AppCompatDelegate.setDefaultNightMode(theme)
|
||||
}
|
||||
|
||||
override fun applyOverrideConfiguration(config: Configuration?) {
|
||||
// Force applying our preferred local
|
||||
config?.setLocale(currentLocale)
|
||||
@ -52,18 +31,6 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
|
||||
super.attachBaseContext(base.wrap(false))
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(themeRes)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel.viewEvents.observe(this, viewEventObserver)
|
||||
|
||||
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).apply {
|
||||
setVariable(BR.viewModel, viewModel)
|
||||
lifecycleOwner = this@BaseActivity
|
||||
}
|
||||
}
|
||||
|
||||
fun withPermissions(vararg permissions: String, builder: PermissionRequestBuilder.() -> Unit) {
|
||||
val request = PermissionRequestBuilder().apply(builder).build()
|
||||
val ungranted = permissions.filter {
|
||||
@ -89,7 +56,7 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
var success = true
|
||||
for (res in grantResults) {
|
||||
if (res != PackageManager.PERMISSION_GRANTED) {
|
||||
@ -97,18 +64,18 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
|
||||
break
|
||||
}
|
||||
}
|
||||
resultCallbacks[requestCode]?.apply {
|
||||
resultCallbacks[requestCode]?.also {
|
||||
resultCallbacks.remove(requestCode)
|
||||
invoke(this@BaseActivity, if (success) 1 else -1, null)
|
||||
it(this@BaseActivity, if (success) 1 else -1, null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
resultCallbacks[requestCode]?.apply {
|
||||
resultCallbacks[requestCode]?.also {
|
||||
resultCallbacks.remove(requestCode)
|
||||
invoke(this@BaseActivity, resultCode, data)
|
||||
it(this@BaseActivity, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.topjohnwu.magisk.base
|
||||
package com.topjohnwu.magisk.core.base
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import com.topjohnwu.magisk.wrap
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import org.koin.core.KoinComponent
|
||||
|
||||
abstract class BaseReceiver : BroadcastReceiver(), KoinComponent {
|
@ -1,8 +1,8 @@
|
||||
package com.topjohnwu.magisk.base
|
||||
package com.topjohnwu.magisk.core.base
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import com.topjohnwu.magisk.wrap
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import org.koin.core.KoinComponent
|
||||
|
||||
abstract class BaseService : Service(), KoinComponent {
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.base
|
||||
package com.topjohnwu.magisk.core.base
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Network
|
||||
@ -10,7 +10,7 @@ import androidx.work.ListenableWorker
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import java.util.*
|
||||
|
||||
abstract class DelegateWorker {
|
||||
abstract class BaseWorkerWrapper {
|
||||
|
||||
private lateinit var worker: ListenableWorker
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.model.download
|
||||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
@ -8,15 +8,15 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.webkit.MimeTypeMap
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.extensions.chooser
|
||||
import com.topjohnwu.magisk.extensions.exists
|
||||
import com.topjohnwu.magisk.extensions.provide
|
||||
import com.topjohnwu.magisk.intent
|
||||
import com.topjohnwu.magisk.legacy.flash.FlashActivity
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.*
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
|
||||
import com.topjohnwu.magisk.legacy.flash.FlashActivity
|
||||
import com.topjohnwu.magisk.utils.APKInstall
|
||||
import org.koin.core.get
|
||||
import java.io.File
|
@ -1,11 +1,18 @@
|
||||
package com.topjohnwu.magisk.model.download
|
||||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.ProcessPhoenix
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.utils.PatchAPK
|
||||
import com.topjohnwu.magisk.extensions.writeTo
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.utils.PatchAPK
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.File
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.model.download
|
||||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import com.topjohnwu.magisk.extensions.withStreams
|
||||
import java.io.File
|
||||
@ -41,4 +41,4 @@ fun InputStream.toModule(file: File, installer: InputStream) {
|
||||
entry = zin.nextEntry
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package com.topjohnwu.magisk.model.download
|
||||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import com.topjohnwu.magisk.base.BaseService
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.core.base.BaseService
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import org.koin.core.KoinComponent
|
||||
import java.util.*
|
||||
import kotlin.random.Random.Default.nextInt
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.model.download
|
||||
package com.topjohnwu.magisk.core.download
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Notification
|
||||
@ -13,8 +13,8 @@ import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.extensions.writeTo
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
|
||||
import com.topjohnwu.magisk.utils.ProgressInputStream
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.core.utils.ProgressInputStream
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
import io.reactivex.Completable
|
||||
import okhttp3.ResponseBody
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.data.database.magiskdb
|
||||
package com.topjohnwu.magisk.core.magiskdb
|
||||
|
||||
import androidx.annotation.StringDef
|
||||
import com.topjohnwu.superuser.Shell
|
@ -1,16 +1,12 @@
|
||||
package com.topjohnwu.magisk.data.database
|
||||
package com.topjohnwu.magisk.core.magiskdb
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Delete
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Replace
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Select
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||
import com.topjohnwu.magisk.core.model.toMap
|
||||
import com.topjohnwu.magisk.core.model.toPolicy
|
||||
import com.topjohnwu.magisk.extensions.now
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.entity.toMap
|
||||
import com.topjohnwu.magisk.model.entity.toPolicy
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.data.database.magiskdb
|
||||
package com.topjohnwu.magisk.core.magiskdb
|
||||
|
||||
import androidx.annotation.StringDef
|
||||
|
@ -1,9 +1,4 @@
|
||||
package com.topjohnwu.magisk.data.database
|
||||
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Delete
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Replace
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Select
|
||||
package com.topjohnwu.magisk.core.magiskdb
|
||||
|
||||
class SettingsDao : BaseDao() {
|
||||
|
@ -1,9 +1,4 @@
|
||||
package com.topjohnwu.magisk.data.database
|
||||
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Delete
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Replace
|
||||
import com.topjohnwu.magisk.data.database.magiskdb.Select
|
||||
package com.topjohnwu.magisk.core.magiskdb
|
||||
|
||||
class StringDao : BaseDao() {
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.topjohnwu.magisk.model.entity
|
||||
package com.topjohnwu.magisk.core.model
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.INTERACTIVE
|
||||
import com.topjohnwu.magisk.extensions.getLabel
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy.Companion.INTERACTIVE
|
||||
|
||||
|
||||
data class MagiskPolicy(
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.model.entity
|
||||
package com.topjohnwu.magisk.core.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.android.parcel.Parcelize
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.model.entity.module
|
||||
package com.topjohnwu.magisk.core.model.module
|
||||
|
||||
abstract class BaseModule : Comparable<BaseModule> {
|
||||
abstract var id: String
|
@ -1,7 +1,7 @@
|
||||
package com.topjohnwu.magisk.model.entity.module
|
||||
package com.topjohnwu.magisk.core.model.module
|
||||
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.topjohnwu.magisk.model.entity.module
|
||||
package com.topjohnwu.magisk.core.model.module
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.data.repository.StringRepository
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.legalFilename
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.su
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -6,20 +6,26 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Process
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.ProviderCallHandler
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||
import com.topjohnwu.magisk.core.model.toPolicy
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import com.topjohnwu.magisk.data.repository.LogRepository
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.startActivity
|
||||
import com.topjohnwu.magisk.extensions.startActivityWithRoot
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.entity.toLog
|
||||
import com.topjohnwu.magisk.model.entity.toPolicy
|
||||
import com.topjohnwu.magisk.legacy.surequest.SuRequestActivity
|
||||
import com.topjohnwu.magisk.model.entity.toLog
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import timber.log.Timber
|
||||
|
||||
object SuHandler : ProviderCallHandler {
|
||||
object SuCallbackHandler : ProviderCallHandler {
|
||||
|
||||
const val REQUEST = "request"
|
||||
const val LOG = "log"
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.su
|
||||
|
||||
import android.net.LocalSocket
|
||||
import android.net.LocalSocketAddress
|
@ -0,0 +1,103 @@
|
||||
package com.topjohnwu.magisk.core.su
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.CountDownTimer
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||
import com.topjohnwu.magisk.core.model.toPolicy
|
||||
import com.topjohnwu.magisk.extensions.now
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class SuRequestHandler(
|
||||
private val packageManager: PackageManager,
|
||||
private val policyDB: PolicyDao
|
||||
) {
|
||||
protected var timer: CountDownTimer = object : CountDownTimer(
|
||||
TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1)) {
|
||||
override fun onFinish() {
|
||||
respond(MagiskPolicy.DENY, 0)
|
||||
}
|
||||
override fun onTick(remains: Long) {}
|
||||
}
|
||||
set(value) {
|
||||
field.cancel()
|
||||
field = value
|
||||
field.start()
|
||||
}
|
||||
|
||||
protected lateinit var policy: MagiskPolicy
|
||||
|
||||
private val cleanupTasks = mutableListOf<() -> Unit>()
|
||||
private lateinit var connector: SuConnector
|
||||
|
||||
abstract fun onStart()
|
||||
abstract fun onRespond()
|
||||
|
||||
fun start(intent: Intent): Boolean {
|
||||
val socketName = intent.getStringExtra("socket") ?: return false
|
||||
|
||||
try {
|
||||
connector = object : SuConnector(socketName) {
|
||||
override fun onResponse() {
|
||||
out.writeInt(policy.policy)
|
||||
}
|
||||
}
|
||||
val map = connector.readRequest()
|
||||
val uid = map["uid"]?.toIntOrNull() ?: return false
|
||||
policy = uid.toPolicy(packageManager)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
|
||||
// Never allow com.topjohnwu.magisk (could be malware)
|
||||
if (policy.packageName == BuildConfig.APPLICATION_ID)
|
||||
return false
|
||||
|
||||
when (Config.suAutoReponse) {
|
||||
Config.Value.SU_AUTO_DENY -> {
|
||||
respond(MagiskPolicy.DENY, 0)
|
||||
return true
|
||||
}
|
||||
Config.Value.SU_AUTO_ALLOW -> {
|
||||
respond(MagiskPolicy.ALLOW, 0)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
timer.start()
|
||||
cleanupTasks.add {
|
||||
timer.cancel()
|
||||
}
|
||||
|
||||
onStart()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun respond() {
|
||||
connector.response()
|
||||
cleanupTasks.forEach { it() }
|
||||
onRespond()
|
||||
}
|
||||
|
||||
fun respond(action: Int, time: Int) {
|
||||
val until = if (time > 0)
|
||||
TimeUnit.MILLISECONDS.toSeconds(now) + TimeUnit.MINUTES.toSeconds(time.toLong())
|
||||
else
|
||||
time.toLong()
|
||||
|
||||
policy.policy = action
|
||||
policy.until = until
|
||||
policy.uid = policy.uid % 100000 + Const.USER_ID * 100000
|
||||
|
||||
if (until >= 0)
|
||||
policyDB.update(policy).blockingAwait()
|
||||
|
||||
respond()
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
package com.topjohnwu.magisk.tasks
|
||||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.extensions.fileName
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.extensions.readUri
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.utils.unzip
|
||||
import com.topjohnwu.magisk.core.utils.unzip
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import io.reactivex.Single
|
||||
import java.io.File
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.tasks
|
||||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
@ -6,11 +6,13 @@ import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Info
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.di.Protected
|
||||
import com.topjohnwu.magisk.extensions.*
|
||||
import com.topjohnwu.magisk.net.Networking
|
||||
import com.topjohnwu.signing.SignBoot
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
@ -34,10 +36,10 @@ import java.util.zip.ZipInputStream
|
||||
|
||||
abstract class MagiskInstaller {
|
||||
|
||||
protected lateinit var srcBoot: String
|
||||
protected lateinit var destFile: File
|
||||
protected lateinit var installDir: File
|
||||
protected lateinit var zipUri: Uri
|
||||
private lateinit var srcBoot: String
|
||||
private lateinit var destFile: File
|
||||
private lateinit var zipUri: Uri
|
||||
|
||||
private val console: MutableList<String>
|
||||
private val logs: MutableList<String>
|
||||
@ -60,7 +62,7 @@ abstract class MagiskInstaller {
|
||||
installDir.mkdirs()
|
||||
}
|
||||
|
||||
protected fun findImage(): Boolean {
|
||||
private fun findImage(): Boolean {
|
||||
srcBoot = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh()
|
||||
if (srcBoot.isEmpty()) {
|
||||
console.add("! Unable to detect target image")
|
||||
@ -70,7 +72,7 @@ abstract class MagiskInstaller {
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun findSecondaryImage(): Boolean {
|
||||
private fun findSecondaryImage(): Boolean {
|
||||
val slot = "echo \$SLOT".fsh()
|
||||
val target = if (slot == "_a") "_b" else "_a"
|
||||
console.add("- Target slot: $target")
|
||||
@ -87,7 +89,7 @@ abstract class MagiskInstaller {
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun extractZip(): Boolean {
|
||||
private fun extractZip(): Boolean {
|
||||
val arch: String
|
||||
arch = if (Build.VERSION.SDK_INT >= 21) {
|
||||
val abis = listOf(*Build.SUPPORTED_ABIS)
|
||||
@ -208,7 +210,7 @@ abstract class MagiskInstaller {
|
||||
}
|
||||
}
|
||||
|
||||
protected fun handleFile(uri: Uri): Boolean {
|
||||
private fun handleFile(uri: Uri): Boolean {
|
||||
try {
|
||||
context.readUri(uri).buffered().use {
|
||||
it.mark(500)
|
||||
@ -238,7 +240,7 @@ abstract class MagiskInstaller {
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun patchBoot(): Boolean {
|
||||
private fun patchBoot(): Boolean {
|
||||
var isSigned = false
|
||||
try {
|
||||
SuFileInputStream(srcBoot).use {
|
||||
@ -284,7 +286,7 @@ abstract class MagiskInstaller {
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun flashBoot(): Boolean {
|
||||
private fun flashBoot(): Boolean {
|
||||
if (!"direct_install $installDir $srcBoot".sh().isSuccess)
|
||||
return false
|
||||
arrayOf(
|
||||
@ -294,7 +296,7 @@ abstract class MagiskInstaller {
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun storeBoot(): Boolean {
|
||||
private fun storeBoot(): Boolean {
|
||||
val patched = SuFile.open(installDir, "new-boot.img")
|
||||
try {
|
||||
val os = tarOut?.let {
|
||||
@ -320,7 +322,7 @@ abstract class MagiskInstaller {
|
||||
return true
|
||||
}
|
||||
|
||||
protected fun postOTA(): Boolean {
|
||||
private fun postOTA(): Boolean {
|
||||
val bootctl = SuFile("/data/adb/bootctl")
|
||||
try {
|
||||
withStreams(service.fetchBootctl().blockingGet().byteStream(), bootctl.suOutputStream()) {
|
||||
@ -345,6 +347,28 @@ abstract class MagiskInstaller {
|
||||
private fun String.fsh() = ShellUtils.fastCmd(this)
|
||||
private fun Array<String>.fsh() = ShellUtils.fastCmd(*this)
|
||||
|
||||
protected fun doPatchFile(patchFile: Uri) =
|
||||
extractZip() && handleFile(patchFile) && patchBoot() && storeBoot()
|
||||
|
||||
protected fun direct() = findImage() && extractZip() && patchBoot() && flashBoot()
|
||||
|
||||
protected fun secondSlot() =
|
||||
findSecondaryImage() && extractZip() && patchBoot() && flashBoot() && postOTA()
|
||||
|
||||
protected fun fixEnv(): Boolean {
|
||||
val context = get<Context>()
|
||||
val zip: File = context.cachedFile("magisk.zip")
|
||||
|
||||
installDir = SuFile("/data/adb/magisk")
|
||||
Shell.su("rm -rf /data/adb/magisk/*").exec()
|
||||
|
||||
if (!ShellUtils.checkSum("MD5", zip, Info.remote.magisk.md5))
|
||||
Networking.get(Info.remote.magisk.link).execForFile(zip)
|
||||
|
||||
zipUri = zip.toUri()
|
||||
return extractZip() && Shell.su("fix_env").exec().isSuccess
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
protected abstract fun operations(): Boolean
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.topjohnwu.magisk.tasks
|
||||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.data.database.RepoDao
|
||||
import com.topjohnwu.magisk.data.network.GithubApiServices
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.rxkotlin.toFlowable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import se.ansman.kotshi.JsonSerializable
|
||||
@ -19,18 +19,17 @@ class RepoUpdater(
|
||||
private val api: GithubApiServices,
|
||||
private val repoDB: RepoDao
|
||||
) {
|
||||
|
||||
private fun loadRepos(repos: List<GithubRepoInfo>, cached: MutableSet<String>) =
|
||||
repos.toFlowable().parallel().runOn(Schedulers.io()).map {
|
||||
// Skip submission
|
||||
if (it.id == "submission")
|
||||
return@map
|
||||
(repoDB.getRepo(it.id)?.apply { cached.remove(it.id) } ?:
|
||||
Repo(it.id)).runCatching {
|
||||
update(it.pushDate)
|
||||
repoDB.addRepo(this)
|
||||
}.getOrElse { Timber.e(it) }
|
||||
}.sequential()
|
||||
repos.toFlowable().parallel().runOn(Schedulers.io()).map {
|
||||
// Skip submission
|
||||
if (it.id == "submission")
|
||||
return@map
|
||||
(repoDB.getRepo(it.id)?.apply { cached.remove(it.id) } ?:
|
||||
Repo(it.id)).runCatching {
|
||||
update(it.pushDate)
|
||||
repoDB.addRepo(this)
|
||||
}.getOrElse { Timber.e(it) }
|
||||
}.sequential()
|
||||
|
||||
private fun loadPage(
|
||||
cached: MutableSet<String>,
|
||||
@ -55,16 +54,16 @@ class RepoUpdater(
|
||||
}
|
||||
|
||||
private fun forcedReload(cached: MutableSet<String>) =
|
||||
cached.toFlowable().parallel().runOn(Schedulers.io()).map {
|
||||
runCatching {
|
||||
Repo(it).update()
|
||||
}.getOrElse { Timber.e(it) }
|
||||
}.sequential()
|
||||
cached.toFlowable().parallel().runOn(Schedulers.io()).map {
|
||||
runCatching {
|
||||
Repo(it).update()
|
||||
}.getOrElse { Timber.e(it) }
|
||||
}.sequential()
|
||||
|
||||
private fun String.trimEtag() = substring(indexOf('\"'), lastIndexOf('\"') + 1)
|
||||
|
||||
@Suppress("RedundantLambdaArrow")
|
||||
operator fun invoke(forced: Boolean = false) : Single<Unit> {
|
||||
operator fun invoke(forced: Boolean = false) : Completable {
|
||||
val cached = Collections.synchronizedSet(HashSet(repoDB.repoIDList))
|
||||
return loadPage(cached, etag = repoDB.etagKey).doOnComplete {
|
||||
repoDB.removeRepos(cached)
|
||||
@ -76,16 +75,16 @@ class RepoUpdater(
|
||||
Timber.e(it)
|
||||
}
|
||||
Flowable.empty()
|
||||
}.ignoreElements().toSingleDefault(Unit)
|
||||
}.ignoreElements()
|
||||
}
|
||||
|
||||
object CachedException : Exception()
|
||||
}
|
||||
|
||||
private val dateFormat: SimpleDateFormat =
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).apply {
|
||||
timeZone = TimeZone.getTimeZone("UTC")
|
||||
}
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).apply {
|
||||
timeZone = TimeZone.getTimeZone("UTC")
|
||||
}
|
||||
|
||||
@JsonSerializable
|
||||
data class GithubRepoInfo(
|
@ -1,11 +1,11 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import androidx.biometric.BiometricManager
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.get
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Base64
|
||||
import android.util.Base64OutputStream
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.utils.PatchAPK.ALPHANUM
|
||||
import com.topjohnwu.magisk.di.koinModules
|
||||
import com.topjohnwu.magisk.utils.PatchAPK.ALPHANUM
|
||||
import com.topjohnwu.signing.CryptoUtils.readCertificate
|
||||
import com.topjohnwu.signing.CryptoUtils.readPrivateKey
|
||||
import com.topjohnwu.superuser.internal.InternalUtils
|
||||
@ -50,10 +50,14 @@ class Keygen: CertKeyProvider {
|
||||
|
||||
private val provider: CertKeyProvider
|
||||
|
||||
inner class KeyStoreProvider : CertKeyProvider {
|
||||
inner class KeyStoreProvider :
|
||||
CertKeyProvider {
|
||||
private val ks by lazy { init() }
|
||||
override val cert by lazy { ks.getCertificate(ALIAS) as X509Certificate }
|
||||
override val key by lazy { ks.getKey(ALIAS, PASSWORD) as PrivateKey }
|
||||
override val key by lazy { ks.getKey(
|
||||
ALIAS,
|
||||
PASSWORD
|
||||
) as PrivateKey }
|
||||
}
|
||||
|
||||
class TestProvider : CertKeyProvider {
|
||||
@ -113,8 +117,12 @@ class Keygen: CertKeyProvider {
|
||||
if (raw.isEmpty()) {
|
||||
ks.load(null)
|
||||
} else {
|
||||
GZIPInputStream(Base64.decode(raw, BASE64_FLAG).inputStream()).use {
|
||||
ks.load(it, PASSWORD)
|
||||
GZIPInputStream(Base64.decode(raw,
|
||||
BASE64_FLAG
|
||||
).inputStream()).use {
|
||||
ks.load(it,
|
||||
PASSWORD
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,10 +139,16 @@ class Keygen: CertKeyProvider {
|
||||
val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer))
|
||||
|
||||
// Store them into keystore
|
||||
ks.setKeyEntry(ALIAS, kp.private, PASSWORD, arrayOf(cert))
|
||||
ks.setKeyEntry(
|
||||
ALIAS, kp.private,
|
||||
PASSWORD, arrayOf(cert))
|
||||
val bytes = ByteArrayOutputStream()
|
||||
GZIPOutputStream(Base64OutputStream(bytes, BASE64_FLAG)).use {
|
||||
ks.store(it, PASSWORD)
|
||||
GZIPOutputStream(Base64OutputStream(bytes,
|
||||
BASE64_FLAG
|
||||
)).use {
|
||||
ks.store(it,
|
||||
PASSWORD
|
||||
)
|
||||
}
|
||||
Config.keyStoreRaw = bytes.toString("UTF-8")
|
||||
|
@ -1,13 +1,13 @@
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.ResourceMgr
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.ResourceMgr
|
||||
import com.topjohnwu.magisk.extensions.langTagToLocale
|
||||
import com.topjohnwu.magisk.extensions.toLangTag
|
||||
import io.reactivex.Single
|
@ -1,15 +1,20 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.extensions.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.extensions.writeTo
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import com.topjohnwu.signing.JarMap
|
||||
import com.topjohnwu.signing.SignAPK
|
||||
import com.topjohnwu.superuser.Shell
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import java.io.FilterInputStream
|
||||
@ -41,4 +41,4 @@ class ProgressInputStream(
|
||||
}
|
||||
return sz
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.wrap
|
||||
import com.topjohnwu.magisk.extensions.rawResource
|
||||
import com.topjohnwu.magisk.wrap
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
interface SafetyNetHelper {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -7,10 +7,10 @@ import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.widget.Toast
|
||||
import androidx.work.*
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.*
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.model.update.UpdateCheckService
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -62,7 +62,10 @@ object Utils {
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT)
|
||||
toast(
|
||||
R.string.open_link_failed_toast,
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.utils
|
||||
package com.topjohnwu.magisk.core.utils
|
||||
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.view
|
||||
package com.topjohnwu.magisk.core.view
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
@ -9,13 +9,12 @@ import android.os.Build.VERSION.SDK_INT
|
||||
import androidx.core.app.TaskStackBuilder
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.toIcon
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
|
||||
import com.topjohnwu.magisk.Const.ID.UPDATE_NOTIFICATION_CHANNEL
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.*
|
||||
import com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
|
||||
import com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.extensions.getBitmap
|
||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
|
||||
import com.topjohnwu.magisk.ui.SplashActivity
|
||||
|
||||
object Notifications {
|
||||
|
||||
@ -52,10 +51,13 @@ object Notifications {
|
||||
val stackBuilder = TaskStackBuilder.create(context)
|
||||
stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName))
|
||||
stackBuilder.addNextIntent(intent)
|
||||
val pendingIntent = stackBuilder.getPendingIntent(Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
||||
val pendingIntent = stackBuilder.getPendingIntent(
|
||||
Const.ID.MAGISK_UPDATE_NOTIFICATION_ID,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val builder = updateBuilder(context)
|
||||
val builder = updateBuilder(
|
||||
context
|
||||
)
|
||||
.setContentTitle(context.getString(R.string.magisk_update_title))
|
||||
.setContentText(context.getString(R.string.manager_download_install))
|
||||
.setAutoCancel(true)
|
||||
@ -72,7 +74,9 @@ object Notifications {
|
||||
val pendingIntent = PendingIntent.getBroadcast(context,
|
||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val builder = updateBuilder(context)
|
||||
val builder = updateBuilder(
|
||||
context
|
||||
)
|
||||
.setContentTitle(context.getString(R.string.manager_update_title))
|
||||
.setContentText(context.getString(R.string.manager_download_install))
|
||||
.setAutoCancel(true)
|
||||
@ -87,7 +91,9 @@ object Notifications {
|
||||
val pendingIntent = PendingIntent.getBroadcast(context,
|
||||
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
|
||||
val builder = updateBuilder(context)
|
||||
val builder = updateBuilder(
|
||||
context
|
||||
)
|
||||
.setContentTitle(context.getString(R.string.dtbo_patched_title))
|
||||
.setContentText(context.getString(R.string.dtbo_patched_reboot))
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.view
|
||||
package com.topjohnwu.magisk.core.view
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@ -10,17 +10,18 @@ import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.toAdaptiveIcon
|
||||
import androidx.core.graphics.drawable.toIcon
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.*
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.magisk.extensions.getBitmap
|
||||
import com.topjohnwu.magisk.ui.SplashActivity
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
|
||||
object Shortcuts {
|
||||
|
||||
fun setup(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= 25) {
|
||||
val manager = context.getSystemService<ShortcutManager>()
|
||||
manager?.dynamicShortcuts = getShortCuts(context)
|
||||
manager?.dynamicShortcuts =
|
||||
getShortCuts(context)
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ package com.topjohnwu.magisk.data.database
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
|
||||
interface RepoBase {
|
||||
|
||||
@ -64,4 +64,4 @@ interface RepoByNameDao : RepoBase {
|
||||
override fun searchRepos(query: String, offset: Int, limit: Int): List<Repo>
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.topjohnwu.magisk.data.database
|
||||
|
||||
import androidx.room.*
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
|
||||
@Database(version = 6, entities = [Repo::class, RepoEtag::class])
|
||||
abstract class RepoDatabase : RoomDatabase() {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.topjohnwu.magisk.data.network
|
||||
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.model.entity.UpdateInfo
|
||||
import com.topjohnwu.magisk.tasks.GithubRepoInfo
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.tasks.GithubRepoInfo
|
||||
import com.topjohnwu.magisk.core.model.UpdateInfo
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Single
|
||||
import okhttp3.ResponseBody
|
||||
@ -78,4 +78,4 @@ interface GithubApiServices {
|
||||
@Query("sort") sort: String = "pushed",
|
||||
@Query("per_page") count: Int = 100): Flowable<Result<List<GithubRepoInfo>>>
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.topjohnwu.magisk.data.repository
|
||||
|
||||
import com.topjohnwu.magisk.data.database.SettingsDao
|
||||
import com.topjohnwu.magisk.data.database.StringDao
|
||||
import com.topjohnwu.magisk.core.magiskdb.SettingsDao
|
||||
import com.topjohnwu.magisk.core.magiskdb.StringDao
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlin.properties.ReadWriteProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.data.repository
|
||||
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.data.database.SuLogDao
|
||||
import com.topjohnwu.magisk.model.entity.MagiskLog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.topjohnwu.magisk.data.repository
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.extensions.getLabel
|
||||
import com.topjohnwu.magisk.extensions.packageName
|
||||
@ -24,7 +24,8 @@ class MagiskRepository(
|
||||
Config.Value.BETA_CHANNEL -> apiRaw.fetchBetaUpdate()
|
||||
Config.Value.CANARY_CHANNEL -> apiRaw.fetchCanaryUpdate()
|
||||
Config.Value.CANARY_DEBUG_CHANNEL -> apiRaw.fetchCanaryDebugUpdate()
|
||||
Config.Value.CUSTOM_CHANNEL -> apiRaw.fetchCustomUpdate(Config.customChannelUrl)
|
||||
Config.Value.CUSTOM_CHANNEL -> apiRaw.fetchCustomUpdate(
|
||||
Config.customChannelUrl)
|
||||
else -> throw IllegalArgumentException()
|
||||
}.flatMap {
|
||||
// If remote version is lower than current installed, try switching to beta
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.topjohnwu.magisk.data.repository
|
||||
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
|
||||
class StringRepository(
|
||||
private val api: GithubRawServices
|
||||
@ -12,4 +12,4 @@ class StringRepository(
|
||||
fun getMetadata(repo: Repo) = api.fetchModuleInfo(repo.id, "module.prop")
|
||||
|
||||
fun getReadme(repo: Repo) = api.fetchModuleInfo(repo.id, "README.md")
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,12 @@ package com.topjohnwu.magisk.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import com.topjohnwu.magisk.data.database.*
|
||||
import com.topjohnwu.magisk.tasks.RepoUpdater
|
||||
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
|
||||
import com.topjohnwu.magisk.core.magiskdb.SettingsDao
|
||||
import com.topjohnwu.magisk.core.magiskdb.StringDao
|
||||
import com.topjohnwu.magisk.core.tasks.RepoUpdater
|
||||
import com.topjohnwu.magisk.data.database.RepoDatabase
|
||||
import com.topjohnwu.magisk.data.database.SuLogDatabase
|
||||
import org.koin.dsl.module
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@ import android.content.Context
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.data.network.GithubApiServices
|
||||
import com.topjohnwu.magisk.data.network.GithubRawServices
|
||||
import com.topjohnwu.magisk.net.Networking
|
||||
|
@ -28,11 +28,11 @@ import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.FileProvider
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import com.topjohnwu.magisk.utils.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.currentLocale
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
import java.io.File
|
||||
@ -317,7 +317,9 @@ fun Context.hasPermissions(vararg permissions: String) = permissions.all {
|
||||
ContextCompat.checkSelfPermission(this, it) == PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private val securityLevelFormatter get() = SimpleDateFormat("yyyy-MM-dd", currentLocale)
|
||||
private val securityLevelFormatter get() = SimpleDateFormat("yyyy-MM-dd",
|
||||
currentLocale
|
||||
)
|
||||
|
||||
/** Friendly reminder to seek newer roms or install oem updates. */
|
||||
val isDeviceSecure: Boolean
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.extensions
|
||||
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||
import com.topjohnwu.superuser.io.SuFileOutputStream
|
||||
@ -13,4 +13,4 @@ fun reboot(reason: String = if (Info.recovery) "recovery" else "") {
|
||||
fun File.suOutputStream() = SuFileOutputStream(this)
|
||||
fun File.suInputStream() = SuFileInputStream(this)
|
||||
|
||||
val hasRoot get() = Shell.rootAccess()
|
||||
val hasRoot get() = Shell.rootAccess()
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.extensions
|
||||
|
||||
import com.topjohnwu.magisk.utils.currentLocale
|
||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||
import java.text.DateFormat
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
@ -14,10 +14,18 @@ fun String.toTime(format: DateFormat) = try {
|
||||
-1L
|
||||
}
|
||||
|
||||
val timeFormatFull by lazy { SimpleDateFormat("yyyy/MM/dd_HH:mm:ss", currentLocale) }
|
||||
val timeFormatStandard by lazy { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", currentLocale) }
|
||||
val timeFormatMedium by lazy { DateFormat.getDateInstance(DateFormat.MEDIUM, currentLocale) }
|
||||
val timeFormatTime by lazy { SimpleDateFormat("h:mm a", currentLocale) }
|
||||
val timeFormatFull by lazy { SimpleDateFormat("yyyy/MM/dd_HH:mm:ss",
|
||||
currentLocale
|
||||
) }
|
||||
val timeFormatStandard by lazy { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
currentLocale
|
||||
) }
|
||||
val timeFormatMedium by lazy { DateFormat.getDateInstance(DateFormat.MEDIUM,
|
||||
currentLocale
|
||||
) }
|
||||
val timeFormatTime by lazy { SimpleDateFormat("h:mm a",
|
||||
currentLocale
|
||||
) }
|
||||
val timeDateFormat by lazy {
|
||||
DateFormat.getDateTimeInstance(
|
||||
DateFormat.DEFAULT,
|
||||
|
@ -6,22 +6,22 @@ import android.content.pm.ActivityInfo
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.databinding.ActivityFlashBinding
|
||||
import com.topjohnwu.magisk.extensions.snackbar
|
||||
import com.topjohnwu.magisk.intent
|
||||
import com.topjohnwu.magisk.model.events.BackPressEvent
|
||||
import com.topjohnwu.magisk.model.events.PermissionEvent
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||
import com.topjohnwu.magisk.core.view.Notifications
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import java.io.File
|
||||
|
||||
open class FlashActivity : BaseActivity<FlashViewModel, ActivityFlashBinding>() {
|
||||
open class FlashActivity : BaseUIActivity<FlashViewModel, ActivityFlashBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_flash
|
||||
override val themeRes: Int = R.style.MagiskTheme_Flashing
|
||||
|
@ -8,10 +8,9 @@ import android.os.Handler
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.databinding.ObservableArrayList
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.extensions.*
|
||||
import com.topjohnwu.magisk.model.entity.recycler.ConsoleRvItem
|
||||
@ -19,6 +18,7 @@ import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
import com.topjohnwu.magisk.model.flash.FlashResultListener
|
||||
import com.topjohnwu.magisk.model.flash.Flashing
|
||||
import com.topjohnwu.magisk.model.flash.Patching
|
||||
import com.topjohnwu.magisk.ui.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.utils.DiffObservableList
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
@ -6,16 +6,16 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.Window
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
|
||||
import com.topjohnwu.magisk.databinding.ActivityRequestBinding
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewActionEvent
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.utils.SuHandler
|
||||
import com.topjohnwu.magisk.utils.SuHandler.REQUEST
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestBinding>() {
|
||||
open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityRequestBinding>() {
|
||||
|
||||
override val layoutRes: Int = R.layout.activity_request
|
||||
override val themeRes: Int = R.style.MagiskTheme_SU
|
||||
@ -36,7 +36,11 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB
|
||||
}
|
||||
|
||||
fun runHandler(action: String?) {
|
||||
SuHandler(this, action, intent.extras)
|
||||
SuCallbackHandler(
|
||||
this,
|
||||
action,
|
||||
intent.extras
|
||||
)
|
||||
finish()
|
||||
}
|
||||
|
||||
|
@ -6,41 +6,36 @@ import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.CountDownTimer
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.data.database.PolicyDao
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.magiskdb.PolicyDao
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.DENY
|
||||
import com.topjohnwu.magisk.core.su.SuRequestHandler
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.extensions.now
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.entity.recycler.SpinnerRvItem
|
||||
import com.topjohnwu.magisk.model.entity.toPolicy
|
||||
import com.topjohnwu.magisk.model.events.DieEvent
|
||||
import com.topjohnwu.magisk.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.ui.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.utils.DiffObservableList
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
import com.topjohnwu.magisk.utils.SuConnector
|
||||
import me.tatarka.bindingcollectionadapter2.BindingListViewAdapter
|
||||
import me.tatarka.bindingcollectionadapter2.ItemBinding
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit.*
|
||||
import java.util.concurrent.TimeUnit.SECONDS
|
||||
|
||||
class SuRequestViewModel(
|
||||
private val packageManager: PackageManager,
|
||||
private val pm: PackageManager,
|
||||
private val policyDB: PolicyDao,
|
||||
private val timeoutPrefs: SharedPreferences,
|
||||
private val resources: Resources
|
||||
private val res: Resources
|
||||
) : BaseViewModel() {
|
||||
|
||||
val icon = KObservableField<Drawable?>(null)
|
||||
val title = KObservableField("")
|
||||
val packageName = KObservableField("")
|
||||
|
||||
val denyText = KObservableField(resources.getString(R.string.deny))
|
||||
val warningText = KObservableField<CharSequence>(resources.getString(R.string.su_warning))
|
||||
val denyText = KObservableField(res.getString(R.string.deny))
|
||||
val warningText = KObservableField<CharSequence>(res.getString(R.string.su_warning))
|
||||
|
||||
val selectedItemPosition = KObservableField(0)
|
||||
|
||||
@ -54,130 +49,74 @@ class SuRequestViewModel(
|
||||
setItems(items)
|
||||
}
|
||||
|
||||
private val cancelTasks = mutableListOf<() -> Unit>()
|
||||
|
||||
private lateinit var timer: CountDownTimer
|
||||
private lateinit var policy: MagiskPolicy
|
||||
private lateinit var connector: SuConnector
|
||||
|
||||
private fun cancelTimer() {
|
||||
timer.cancel()
|
||||
denyText.value = resources.getString(R.string.deny)
|
||||
}
|
||||
private val handler = Handler()
|
||||
|
||||
fun grantPressed() {
|
||||
cancelTimer()
|
||||
handler.cancelTimer()
|
||||
if (BiometricHelper.isEnabled) {
|
||||
withView {
|
||||
BiometricHelper.authenticate(this) {
|
||||
handleAction(MagiskPolicy.ALLOW)
|
||||
handler.respond(ALLOW)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handleAction(MagiskPolicy.ALLOW)
|
||||
handler.respond(ALLOW)
|
||||
}
|
||||
}
|
||||
|
||||
fun denyPressed() {
|
||||
handleAction(MagiskPolicy.DENY)
|
||||
timer.cancel()
|
||||
handler.respond(DENY)
|
||||
}
|
||||
|
||||
fun spinnerTouched(): Boolean {
|
||||
cancelTimer()
|
||||
handler.cancelTimer()
|
||||
return false
|
||||
}
|
||||
|
||||
fun handleRequest(intent: Intent): Boolean {
|
||||
val socketName = intent.getStringExtra("socket") ?: return false
|
||||
return handler.start(intent)
|
||||
}
|
||||
|
||||
try {
|
||||
connector = Connector(socketName)
|
||||
val map = connector.readRequest()
|
||||
val uid = map["uid"]?.toIntOrNull() ?: return false
|
||||
policy = uid.toPolicy(packageManager)
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
return false
|
||||
private inner class Handler : SuRequestHandler(pm, policyDB) {
|
||||
|
||||
fun respond(action: Int) {
|
||||
val pos = selectedItemPosition.value
|
||||
timeoutPrefs.edit().putInt(policy.packageName, pos).apply()
|
||||
respond(action, Config.Value.TIMEOUT_LIST[pos])
|
||||
}
|
||||
|
||||
// Never allow com.topjohnwu.magisk (could be malware)
|
||||
if (policy.packageName == BuildConfig.APPLICATION_ID)
|
||||
return false
|
||||
fun cancelTimer() {
|
||||
timer.cancel()
|
||||
denyText.value = res.getString(R.string.deny)
|
||||
}
|
||||
|
||||
when (Config.suAutoReponse) {
|
||||
Config.Value.SU_AUTO_DENY -> {
|
||||
handleAction(MagiskPolicy.DENY, 0)
|
||||
return true
|
||||
}
|
||||
Config.Value.SU_AUTO_ALLOW -> {
|
||||
handleAction(MagiskPolicy.ALLOW, 0)
|
||||
return true
|
||||
override fun onStart() {
|
||||
res.getStringArray(R.array.allow_timeout)
|
||||
.map { SpinnerRvItem(it) }
|
||||
.let { items.update(it) }
|
||||
|
||||
icon.value = policy.applicationInfo.loadIcon(pm)
|
||||
title.value = policy.appName
|
||||
packageName.value = policy.packageName
|
||||
selectedItemPosition.value = timeoutPrefs.getInt(policy.packageName, 0)
|
||||
|
||||
// Override timer
|
||||
val millis = SECONDS.toMillis(Config.suDefaultTimeout.toLong())
|
||||
timer = object : CountDownTimer(millis, 1000) {
|
||||
override fun onTick(remains: Long) {
|
||||
denyText.value = "${res.getString(R.string.deny)} (${remains / 1000})"
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
denyText.value = res.getString(R.string.deny)
|
||||
respond(DENY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showUI()
|
||||
return true
|
||||
}
|
||||
|
||||
private fun showUI() {
|
||||
resources.getStringArray(R.array.allow_timeout)
|
||||
.map { SpinnerRvItem(it) }
|
||||
.let { items.update(it) }
|
||||
|
||||
icon.value = policy.applicationInfo.loadIcon(packageManager)
|
||||
title.value = policy.appName
|
||||
packageName.value = policy.packageName
|
||||
selectedItemPosition.value = timeoutPrefs.getInt(policy.packageName, 0)
|
||||
|
||||
val millis = SECONDS.toMillis(Config.suDefaultTimeout.toLong())
|
||||
timer = object : CountDownTimer(millis, 1000) {
|
||||
override fun onTick(remains: Long) {
|
||||
denyText.value = "${resources.getString(R.string.deny)} (${remains / 1000})"
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
denyText.value = resources.getString(R.string.deny)
|
||||
handleAction(MagiskPolicy.DENY)
|
||||
}
|
||||
}
|
||||
timer.start()
|
||||
cancelTasks.add { cancelTimer() }
|
||||
}
|
||||
|
||||
private fun handleAction() {
|
||||
connector.response()
|
||||
cancelTasks.forEach { it() }
|
||||
DieEvent().publish()
|
||||
}
|
||||
|
||||
private fun handleAction(action: Int) {
|
||||
val pos = selectedItemPosition.value
|
||||
timeoutPrefs.edit().putInt(policy.packageName, pos).apply()
|
||||
handleAction(action, Config.Value.TIMEOUT_LIST[pos])
|
||||
}
|
||||
|
||||
private fun handleAction(action: Int, time: Int) {
|
||||
val until = if (time > 0)
|
||||
MILLISECONDS.toSeconds(now) + MINUTES.toSeconds(time.toLong())
|
||||
else
|
||||
time.toLong()
|
||||
|
||||
policy.policy = action
|
||||
policy.until = until
|
||||
policy.uid = policy.uid % 100000 + Const.USER_ID * 100000
|
||||
|
||||
if (until >= 0)
|
||||
policyDB.update(policy).blockingAwait()
|
||||
|
||||
handleAction()
|
||||
}
|
||||
|
||||
private inner class Connector @Throws(Exception::class)
|
||||
internal constructor(name: String) : SuConnector(name) {
|
||||
@Throws(IOException::class)
|
||||
override fun onResponse() {
|
||||
out.writeInt(policy.policy)
|
||||
override fun onRespond() {
|
||||
// Kill activity after response
|
||||
DieEvent().publish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,11 @@ package com.topjohnwu.magisk.model.entity
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.ALLOW
|
||||
import com.topjohnwu.magisk.extensions.now
|
||||
import com.topjohnwu.magisk.extensions.timeFormatTime
|
||||
import com.topjohnwu.magisk.extensions.toTime
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy.Companion.ALLOW
|
||||
|
||||
@Entity(tableName = "logs")
|
||||
data class MagiskLog(
|
||||
@ -23,11 +24,6 @@ data class MagiskLog(
|
||||
@Ignore val timeString = time.toTime(timeFormatTime)
|
||||
}
|
||||
|
||||
data class WrappedMagiskLog(
|
||||
val time: Long,
|
||||
val items: List<MagiskLog>
|
||||
)
|
||||
|
||||
fun MagiskPolicy.toLog(
|
||||
toUid: Int,
|
||||
fromPid: Int,
|
||||
|
@ -2,13 +2,13 @@ package com.topjohnwu.magisk.model.entity.internal
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.extensions.cachedFile
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.model.entity.MagiskJson
|
||||
import com.topjohnwu.magisk.model.entity.ManagerJson
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import com.topjohnwu.magisk.core.model.MagiskJson
|
||||
import com.topjohnwu.magisk.core.model.ManagerJson
|
||||
import kotlinx.android.parcel.IgnoredOnParcel
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.io.File
|
||||
@ -103,4 +103,4 @@ sealed class DownloadSubject : Parcelable {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.topjohnwu.magisk.model.entity.recycler
|
||||
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
|
||||
sealed class HomeItem : ComparableRvItem<HomeItem>() {
|
||||
|
@ -7,9 +7,9 @@ import androidx.databinding.ViewDataBinding
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.model.module.Module
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.model.entity.module.Module
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import com.topjohnwu.magisk.ui.module.ModuleViewModel
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
|
||||
|
@ -2,9 +2,9 @@ package com.topjohnwu.magisk.model.entity.recycler
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
||||
import com.topjohnwu.magisk.extensions.toggle
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.events.PolicyUpdateEvent
|
||||
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
|
||||
import com.topjohnwu.magisk.utils.KObservableField
|
||||
|
@ -2,7 +2,7 @@ package com.topjohnwu.magisk.model.events
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
|
||||
interface ContextExecutor {
|
||||
|
||||
@ -12,7 +12,7 @@ interface ContextExecutor {
|
||||
|
||||
interface ActivityExecutor {
|
||||
|
||||
operator fun invoke(activity: BaseActivity<*, *>)
|
||||
operator fun invoke(activity: BaseActivity)
|
||||
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,14 @@ package com.topjohnwu.magisk.model.events
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.intent
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.legacy.flash.FlashActivity
|
||||
|
||||
class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor {
|
||||
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
activity.withExternalRW {
|
||||
onSuccess {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.topjohnwu.magisk.model.events
|
||||
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.core.model.MagiskPolicy
|
||||
import com.topjohnwu.magisk.utils.RxBus
|
||||
|
||||
sealed class PolicyUpdateEvent(val item: MagiskPolicy) : RxBus.Event {
|
||||
|
@ -3,8 +3,9 @@ package com.topjohnwu.magisk.model.events
|
||||
import android.content.Context
|
||||
import androidx.annotation.StringRes
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.extensions.snackbar
|
||||
import com.topjohnwu.magisk.ui.base.BaseUIActivity
|
||||
|
||||
class SnackbarEvent private constructor(
|
||||
@StringRes private val messageRes: Int,
|
||||
@ -27,8 +28,8 @@ class SnackbarEvent private constructor(
|
||||
|
||||
fun message(context: Context): String = messageString ?: context.getString(messageRes)
|
||||
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
if (activity is BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
if (activity is BaseUIActivity<*, *>) {
|
||||
activity.snackbar(activity.snackbarView, message(activity), length, f)
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,16 @@ package com.topjohnwu.magisk.model.events
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.data.repository.MagiskRepository
|
||||
import com.topjohnwu.magisk.extensions.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.extensions.writeTo
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import com.topjohnwu.magisk.utils.RxBus
|
||||
import com.topjohnwu.magisk.utils.SafetyNetHelper
|
||||
import com.topjohnwu.magisk.core.utils.SafetyNetHelper
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import com.topjohnwu.superuser.Shell
|
||||
@ -118,8 +118,8 @@ class UpdateSafetyNetEvent : ViewEvent(), ContextExecutor, KoinComponent, Safety
|
||||
}
|
||||
}
|
||||
|
||||
class ViewActionEvent(val action: BaseActivity<*, *>.() -> Unit) : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity<*, *>) = activity.run(action)
|
||||
class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity) = activity.run(action)
|
||||
}
|
||||
|
||||
class OpenChangelogEvent(val item: Repo) : ViewEvent(), ContextExecutor {
|
||||
@ -133,7 +133,7 @@ class PermissionEvent(
|
||||
val callback: PublishSubject<Boolean>
|
||||
) : ViewEvent(), ActivityExecutor {
|
||||
|
||||
override fun invoke(activity: BaseActivity<*, *>) =
|
||||
override fun invoke(activity: BaseActivity) =
|
||||
activity.withPermissions(*permissions.toTypedArray()) {
|
||||
onSuccess {
|
||||
callback.onNext(true)
|
||||
@ -146,25 +146,25 @@ class PermissionEvent(
|
||||
}
|
||||
|
||||
class BackPressEvent : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
activity.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
class DieEvent : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
|
||||
class RecreateEvent : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
activity.recreate()
|
||||
}
|
||||
}
|
||||
|
||||
class RequestFileEvent : ViewEvent(), ActivityExecutor {
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
Intent(Intent.ACTION_GET_CONTENT)
|
||||
.setType("*/*")
|
||||
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
|
||||
class BiometricDialog(
|
||||
builder: Builder.() -> Unit
|
||||
@ -16,7 +16,7 @@ class BiometricDialog(
|
||||
builder(Builder())
|
||||
}
|
||||
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
BiometricHelper.authenticate(
|
||||
activity,
|
||||
onError = listenerOnFailure,
|
||||
|
@ -2,9 +2,9 @@ package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import java.lang.ref.WeakReference
|
||||
@ -13,7 +13,7 @@ class DarkThemeDialog : DialogEvent(), ActivityExecutor {
|
||||
|
||||
private var activity: WeakReference<Activity>? = null
|
||||
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
this.activity = WeakReference(activity)
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,14 @@
|
||||
package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.widget.Toast
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.extensions.cachedFile
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.extensions.reboot
|
||||
import com.topjohnwu.magisk.net.Networking
|
||||
import com.topjohnwu.magisk.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import org.koin.core.KoinComponent
|
||||
import org.koin.core.get
|
||||
import java.io.File
|
||||
|
||||
class EnvFixDialog : DialogEvent() {
|
||||
|
||||
@ -48,19 +38,7 @@ class EnvFixDialog : DialogEvent() {
|
||||
|
||||
private fun fixEnv(dialog: DialogInterface) {
|
||||
object : MagiskInstaller(), KoinComponent {
|
||||
override fun operations(): Boolean {
|
||||
val context = get<Context>()
|
||||
val zip: File = context.cachedFile("magisk.zip")
|
||||
|
||||
installDir = SuFile("/data/adb/magisk")
|
||||
Shell.su("rm -rf /data/adb/magisk/*").exec()
|
||||
|
||||
if (!ShellUtils.checkSum("MD5", zip, Info.remote.magisk.md5))
|
||||
Networking.get(Info.remote.magisk.link).execForFile(zip)
|
||||
|
||||
zipUri = zip.toUri()
|
||||
return extractZip() && Shell.su("fix_env").exec().isSuccess
|
||||
}
|
||||
override fun operations() = fixEnv()
|
||||
|
||||
override fun onResult(success: Boolean) {
|
||||
dialog.dismiss()
|
||||
@ -74,4 +52,4 @@ class EnvFixDialog : DialogEvent() {
|
||||
}.exec()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -4,16 +4,16 @@ import android.Manifest
|
||||
import android.net.Uri
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.databinding.IncludeInstallOptionsBinding
|
||||
import com.topjohnwu.magisk.extensions.hasPermissions
|
||||
import com.topjohnwu.magisk.extensions.res
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.model.events.OpenInappLinkEvent
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import com.topjohnwu.superuser.Shell
|
||||
@ -128,4 +128,4 @@ class MagiskInstallDialog : DialogEvent() {
|
||||
.fastCmd("grep_prop ro.build.ab_update")
|
||||
.let { it.isNotEmpty() && it.toBoolean() }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.extensions.res
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
@ -33,4 +33,4 @@ class ManagerInstallDialog : DialogEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
|
||||
class ModuleInstallDialog(private val item: Repo) : DialogEvent() {
|
||||
@ -34,4 +34,4 @@ class ModuleInstallDialog(private val item: Repo) : DialogEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.topjohnwu.magisk.model.events.dialog
|
||||
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.core.utils.Utils
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
@ -52,4 +52,4 @@ class UninstallDialog : DialogEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package com.topjohnwu.magisk.model.flash
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.core.os.postDelayed
|
||||
import com.topjohnwu.magisk.core.tasks.FlashZip
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.tasks.FlashZip
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
|
||||
@ -58,4 +58,4 @@ sealed class Flashing(
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.topjohnwu.magisk.model.flash
|
||||
|
||||
import android.net.Uri
|
||||
import com.topjohnwu.magisk.tasks.MagiskInstaller
|
||||
import com.topjohnwu.magisk.core.tasks.MagiskInstaller
|
||||
import com.topjohnwu.superuser.Shell
|
||||
|
||||
sealed class Patching(
|
||||
@ -28,8 +28,7 @@ sealed class Patching(
|
||||
logs: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : Patching(file, console, logs, resultListener) {
|
||||
override fun operations() =
|
||||
extractZip() && handleFile(uri) && patchBoot() && storeBoot()
|
||||
override fun operations() = doPatchFile(uri)
|
||||
}
|
||||
|
||||
class SecondSlot(
|
||||
@ -38,8 +37,7 @@ sealed class Patching(
|
||||
logs: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : Patching(file, console, logs, resultListener) {
|
||||
override fun operations() =
|
||||
findSecondaryImage() && extractZip() && patchBoot() && flashBoot() && postOTA()
|
||||
override fun operations() = secondSlot()
|
||||
}
|
||||
|
||||
class Direct(
|
||||
@ -48,8 +46,7 @@ sealed class Patching(
|
||||
logs: MutableList<String>,
|
||||
resultListener: FlashResultListener
|
||||
) : Patching(file, console, logs, resultListener) {
|
||||
override fun operations() =
|
||||
findImage() && extractZip() && patchBoot() && flashBoot()
|
||||
override fun operations() = direct()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,10 @@ import android.os.Bundle
|
||||
import androidx.annotation.AnimRes
|
||||
import androidx.annotation.AnimatorRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
import com.topjohnwu.magisk.ui.compat.CompatActivity
|
||||
import com.topjohnwu.magisk.ui.base.CompatActivity
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@DslMarker
|
||||
@ -23,7 +23,7 @@ class MagiskNavigationEvent(
|
||||
operator fun invoke(builder: Builder.() -> Unit) = Builder().apply(builder).build()
|
||||
}
|
||||
|
||||
override fun invoke(activity: BaseActivity<*, *>) {
|
||||
override fun invoke(activity: BaseActivity) {
|
||||
if (activity !is CompatActivity<*, *>) return
|
||||
activity.navigation?.navigateTo(this)
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package com.topjohnwu.magisk.model.navigation
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.intent
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
import com.topjohnwu.magisk.ui.hide.HideFragment
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragment
|
||||
@ -82,7 +82,9 @@ object Navigation {
|
||||
|
||||
fun start(launchIntent: Intent, context: Context) {
|
||||
context.intent<MainActivity>()
|
||||
.putExtra(Const.Key.OPEN_SECTION, launchIntent.getStringExtra(Const.Key.OPEN_SECTION))
|
||||
.putExtra(
|
||||
Const.Key.OPEN_SECTION, launchIntent.getStringExtra(
|
||||
Const.Key.OPEN_SECTION))
|
||||
.putExtra(
|
||||
Const.Key.OPEN_SETTINGS,
|
||||
launchIntent.action == ACTION_APPLICATION_PREFERENCES
|
||||
|
@ -1,75 +0,0 @@
|
||||
package com.topjohnwu.magisk.model.zip
|
||||
|
||||
import com.topjohnwu.magisk.extensions.forEach
|
||||
import com.topjohnwu.magisk.extensions.withStreams
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import java.io.File
|
||||
import java.util.zip.ZipInputStream
|
||||
|
||||
|
||||
class Zip private constructor(private val values: Builder) {
|
||||
|
||||
companion object {
|
||||
operator fun invoke(builder: Builder.() -> Unit): Zip {
|
||||
return Zip(Builder().apply(builder))
|
||||
}
|
||||
}
|
||||
|
||||
class Builder {
|
||||
lateinit var zip: File
|
||||
lateinit var destination: File
|
||||
var excludeDirs = true
|
||||
}
|
||||
|
||||
data class Path(val path: String, val pullFromDir: Boolean = true)
|
||||
|
||||
fun unzip(vararg paths: Pair<String, Boolean>) =
|
||||
unzip(*paths.map { Path(it.first, it.second) }.toTypedArray())
|
||||
|
||||
@Suppress("RedundantLambdaArrow")
|
||||
fun unzip(vararg paths: Path) {
|
||||
ensureRequiredParams()
|
||||
|
||||
values.zip.zipStream().use {
|
||||
it.forEach { e ->
|
||||
val currentPath = paths.firstOrNull { e.name.startsWith(it.path) }
|
||||
val isDirectory = values.excludeDirs && e.isDirectory
|
||||
if (currentPath == null || isDirectory) {
|
||||
// Ignore directories, only create files
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val name = if (currentPath.pullFromDir) {
|
||||
e.name.substring(e.name.lastIndexOf('/') + 1)
|
||||
} else {
|
||||
e.name
|
||||
}
|
||||
|
||||
val out = File(values.destination, name)
|
||||
.ensureExists()
|
||||
.outputStream()
|
||||
//.suOutputStream()
|
||||
|
||||
withStreams(it, out) { reader, writer ->
|
||||
reader.copyTo(writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ensureRequiredParams() {
|
||||
if (!values.zip.exists()) {
|
||||
throw RuntimeException("Zip file does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.ensureExists() =
|
||||
if ((!parentFile.exists() && !parentFile.mkdirs()) || parentFile is SuFile) {
|
||||
SuFile(parentFile, name).apply { parentFile.mkdirs() }
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
private fun File.zipStream() = ZipInputStream(inputStream())
|
||||
|
||||
}
|
@ -12,13 +12,13 @@ import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.ncapdevi.fragnav.FragNavController
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
|
||||
import com.topjohnwu.magisk.extensions.startAnimations
|
||||
import com.topjohnwu.magisk.model.navigation.Navigation
|
||||
import com.topjohnwu.magisk.ui.compat.CompatActivity
|
||||
import com.topjohnwu.magisk.ui.compat.CompatNavigationDelegate
|
||||
import com.topjohnwu.magisk.ui.base.CompatActivity
|
||||
import com.topjohnwu.magisk.ui.base.CompatNavigationDelegate
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragment
|
||||
import com.topjohnwu.magisk.ui.module.ModuleFragment
|
||||
import com.topjohnwu.magisk.ui.superuser.SuperuserFragment
|
||||
|
@ -1,5 +1,5 @@
|
||||
package com.topjohnwu.magisk.ui
|
||||
|
||||
import com.topjohnwu.magisk.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.ui.base.BaseViewModel
|
||||
|
||||
class MainViewModel : BaseViewModel()
|
||||
|
@ -0,0 +1,39 @@
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.EventHandler
|
||||
|
||||
abstract class BaseUIActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
BaseActivity(), EventHandler {
|
||||
|
||||
protected lateinit var binding: Binding
|
||||
protected abstract val layoutRes: Int
|
||||
protected abstract val viewModel: ViewModel
|
||||
protected open val themeRes: Int = R.style.MagiskTheme
|
||||
|
||||
open val snackbarView get() = binding.root
|
||||
|
||||
init {
|
||||
val theme = Config.darkThemeExtended
|
||||
AppCompatDelegate.setDefaultNightMode(theme)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTheme(themeRes)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
viewModel.viewEvents.observe(this, viewEventObserver)
|
||||
|
||||
binding = DataBindingUtil.setContentView<Binding>(this, layoutRes).apply {
|
||||
setVariable(BR.viewModel, viewModel)
|
||||
lifecycleOwner = this@BaseUIActivity
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.base
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
@ -11,10 +11,10 @@ import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.model.events.EventHandler
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
|
||||
abstract class BaseFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
Fragment(), EventHandler {
|
||||
|
||||
protected val activity get() = requireActivity() as BaseActivity<*, *>
|
||||
protected val activity get() = requireActivity() as BaseUIActivity<*, *>
|
||||
protected lateinit var binding: Binding
|
||||
protected abstract val layoutRes: Int
|
||||
protected abstract val viewModel: ViewModel
|
||||
@ -31,7 +31,7 @@ abstract class BaseFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding
|
||||
): View? {
|
||||
binding = DataBindingUtil.inflate<Binding>(inflater, layoutRes, container, false).apply {
|
||||
setVariable(BR.viewModel, viewModel)
|
||||
lifecycleOwner = this@BaseFragment
|
||||
lifecycleOwner = this@BaseUIFragment
|
||||
}
|
||||
|
||||
return binding.root
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.base
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.graphics.Insets
|
||||
@ -8,7 +8,8 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.Info
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.extensions.doOnSubscribeUi
|
||||
import com.topjohnwu.magisk.model.events.*
|
||||
import com.topjohnwu.magisk.model.observer.Observer
|
||||
@ -79,7 +80,7 @@ abstract class BaseViewModel(
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
fun withView(action: BaseActivity<*, *>.() -> Unit) {
|
||||
fun withView(action: BaseActivity.() -> Unit) {
|
||||
ViewActionEvent(action).publish()
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.ui.compat
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
@ -10,8 +10,6 @@ import androidx.core.content.getSystemService
|
||||
import androidx.databinding.OnRebindCallback
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.extensions.snackbar
|
||||
import com.topjohnwu.magisk.extensions.startAnimations
|
||||
import com.topjohnwu.magisk.model.events.SnackbarEvent
|
||||
@ -20,9 +18,10 @@ import com.topjohnwu.magisk.model.navigation.Navigator
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
// TODO (diareuse): Merge into BaseUIActivity after all legacy UI is migrated
|
||||
|
||||
abstract class CompatActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
|
||||
BaseActivity<ViewModel, Binding>(), CompatView<ViewModel>, Navigator {
|
||||
BaseUIActivity<ViewModel, Binding>(), CompatView<ViewModel>, Navigator {
|
||||
|
||||
override val themeRes = Theme.selected.themeRes
|
||||
override val viewRoot: View get() = binding.root
|
@ -1,11 +1,10 @@
|
||||
package com.topjohnwu.magisk.ui.compat
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
import com.topjohnwu.magisk.model.events.ActivityExecutor
|
||||
import com.topjohnwu.magisk.model.events.ContextExecutor
|
||||
import com.topjohnwu.magisk.model.events.FragmentExecutor
|
||||
@ -26,7 +25,7 @@ class CompatDelegate internal constructor(
|
||||
view.viewModel.requestRefresh()
|
||||
}
|
||||
|
||||
fun onEventExecute(event: ViewEvent, activity: BaseActivity<*, *>) {
|
||||
fun onEventExecute(event: ViewEvent, activity: BaseUIActivity<*, *>) {
|
||||
(event as? ContextExecutor)?.invoke(activity)
|
||||
(event as? ActivityExecutor)?.invoke(activity)
|
||||
(event as? FragmentExecutor)?.let {
|
||||
@ -37,7 +36,7 @@ class CompatDelegate internal constructor(
|
||||
fun onEventExecute(event: ViewEvent, fragment: Fragment) {
|
||||
(event as? ContextExecutor)?.invoke(fragment.requireContext())
|
||||
(event as? FragmentExecutor)?.invoke(fragment)
|
||||
(event as? ActivityExecutor)?.invoke(fragment.requireActivity() as BaseActivity<*, *>)
|
||||
(event as? ActivityExecutor)?.invoke(fragment.requireActivity() as BaseUIActivity<*, *>)
|
||||
}
|
||||
|
||||
private fun ensureInsets() {
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.ui.compat
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
@ -6,13 +6,13 @@ import android.view.ViewGroup
|
||||
import androidx.databinding.OnRebindCallback
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.topjohnwu.magisk.base.BaseFragment
|
||||
import com.topjohnwu.magisk.base.BaseViewModel
|
||||
import com.topjohnwu.magisk.extensions.startAnimations
|
||||
import com.topjohnwu.magisk.model.events.ViewEvent
|
||||
|
||||
// TODO (diareuse): Merge into BaseUIFragment after all legacy UI is migrated
|
||||
|
||||
abstract class CompatFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding>
|
||||
: BaseFragment<ViewModel, Binding>(), CompatView<ViewModel> {
|
||||
: BaseUIFragment<ViewModel, Binding>(), CompatView<ViewModel> {
|
||||
|
||||
override val viewRoot: View get() = binding.root
|
||||
override val navigation by lazy { compatActivity.navigation }
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.ui.compat
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import androidx.databinding.ViewDataBinding
|
||||
import com.topjohnwu.magisk.databinding.ComparableRvItem
|
@ -1,4 +1,4 @@
|
||||
package com.topjohnwu.magisk.ui.compat
|
||||
package com.topjohnwu.magisk.ui.base
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user