Separate core components

This commit is contained in:
topjohnwu 2020-01-13 22:01:46 +08:00
parent ba1a2fbce4
commit 707d7b3342
134 changed files with 742 additions and 693 deletions

View File

@ -17,9 +17,9 @@
#} #}
# Snet # Snet
-keepclassmembers class com.topjohnwu.magisk.utils.SafetyNetHelper { *; } -keepclassmembers class com.topjohnwu.magisk.core.utils.SafetyNetHelper { *; }
-keep,allowobfuscation interface com.topjohnwu.magisk.utils.SafetyNetHelper$Callback -keep,allowobfuscation interface com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback
-keepclassmembers class * implements com.topjohnwu.magisk.utils.SafetyNetHelper$Callback { -keepclassmembers class * implements com.topjohnwu.magisk.core.utils.SafetyNetHelper$Callback {
void onResponse(int); void onResponse(int);
} }
@ -29,13 +29,13 @@
} }
# DelegateWorker # DelegateWorker
-keep,allowobfuscation class * extends com.topjohnwu.magisk.base.DelegateWorker -keep,allowobfuscation class * extends com.topjohnwu.magisk.core.base.BaseWorkerWrapper
# BootSigner # BootSigner
-keep class a.a { *; } -keep class a.a { *; }
# Workaround R8 bug # Workaround R8 bug
-keep,allowobfuscation class com.topjohnwu.magisk.model.receiver.GeneralReceiver -keep,allowobfuscation class com.topjohnwu.magisk.core.GeneralReceiver
-keepclassmembers class a.e { *; } -keepclassmembers class a.e { *; }
# Strip logging # Strip logging

View File

@ -1,6 +1,6 @@
package a; package a;
import com.topjohnwu.magisk.utils.PatchAPK; import com.topjohnwu.magisk.core.utils.PatchAPK;
import com.topjohnwu.signing.BootSigner; import com.topjohnwu.signing.BootSigner;
public class a { public class a {

View File

@ -1,6 +1,6 @@
package a; package a;
import com.topjohnwu.magisk.ui.SplashActivity; import com.topjohnwu.magisk.core.SplashActivity;
public class c extends SplashActivity { public class c extends SplashActivity {
/* stub */ /* stub */

View File

@ -1,6 +1,6 @@
package a; package a;
import com.topjohnwu.magisk.App; import com.topjohnwu.magisk.core.App;
public class e extends App { public class e extends App {
public e() { public e() {

View File

@ -5,7 +5,7 @@ import android.content.Context;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import com.topjohnwu.magisk.model.update.UpdateCheckService; import com.topjohnwu.magisk.core.UpdateCheckService;
public class g extends w<UpdateCheckService> { public class g extends w<UpdateCheckService> {
/* Stub */ /* Stub */

View File

@ -1,6 +1,6 @@
package a; package a;
import com.topjohnwu.magisk.model.receiver.GeneralReceiver; import com.topjohnwu.magisk.core.GeneralReceiver;
public class h extends GeneralReceiver { public class h extends GeneralReceiver {
/* stub */ /* stub */

View File

@ -1,6 +1,6 @@
package a; package a;
import com.topjohnwu.magisk.model.download.DownloadService; import com.topjohnwu.magisk.core.download.DownloadService;
public class j extends DownloadService { public class j extends DownloadService {
/* stub */ /* stub */

View File

@ -6,11 +6,11 @@ import androidx.annotation.NonNull;
import androidx.work.Worker; import androidx.work.Worker;
import androidx.work.WorkerParameters; import androidx.work.WorkerParameters;
import com.topjohnwu.magisk.base.DelegateWorker; import com.topjohnwu.magisk.core.base.BaseWorkerWrapper;
import java.lang.reflect.ParameterizedType; 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 */ /* Wrapper class to workaround Proguard -keep class * extends Worker */

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk package com.topjohnwu.magisk.core
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
@ -9,6 +9,12 @@ import androidx.room.Room
import androidx.work.WorkManager import androidx.work.WorkManager
import androidx.work.impl.WorkDatabase import androidx.work.impl.WorkDatabase
import androidx.work.impl.WorkDatabase_Impl 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
import com.topjohnwu.magisk.data.database.RepoDatabase_Impl import com.topjohnwu.magisk.data.database.RepoDatabase_Impl
import com.topjohnwu.magisk.data.database.SuLogDatabase 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.di.koinModules
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.unwrap 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 com.topjohnwu.superuser.Shell
import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin import org.koin.core.context.startKoin
@ -37,7 +40,7 @@ open class App() : Application() {
Shell.Config.verboseLogging(BuildConfig.DEBUG) Shell.Config.verboseLogging(BuildConfig.DEBUG)
Shell.Config.addInitializers(RootInit::class.java) Shell.Config.addInitializers(RootInit::class.java)
Shell.Config.setTimeout(2) Shell.Config.setTimeout(2)
FileProvider.callHandler = SuHandler FileProvider.callHandler = SuCallbackHandler
Room.setFactory { Room.setFactory {
when (it) { when (it) {
WorkDatabase::class.java -> WorkDatabase_Impl() WorkDatabase::class.java -> WorkDatabase_Impl()

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk package com.topjohnwu.magisk.core
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
@ -6,16 +6,17 @@ import android.os.Environment
import android.util.Xml import android.util.Xml
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit import androidx.core.content.edit
import com.topjohnwu.magisk.data.database.SettingsDao import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.data.database.StringDao 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.data.repository.DBConfig
import com.topjohnwu.magisk.di.Protected import com.topjohnwu.magisk.di.Protected
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.model.preference.PreferenceModel import com.topjohnwu.magisk.model.preference.PreferenceModel
import com.topjohnwu.magisk.ui.theme.Theme import com.topjohnwu.magisk.ui.theme.Theme
import com.topjohnwu.magisk.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.BiometricHelper
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile
import com.topjohnwu.superuser.io.SuFileInputStream import com.topjohnwu.superuser.io.SuFileInputStream
@ -115,12 +116,24 @@ object Config : PreferenceModel, DBConfig {
var bootId by preference(Key.BOOT_ID, "") var bootId by preference(Key.BOOT_ID, "")
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS) 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 suDefaultTimeout by preferenceStrInt(Key.SU_REQUEST_TIMEOUT, 10)
var suAutoReponse by preferenceStrInt(Key.SU_AUTO_RESPONSE, Value.SU_PROMPT) var suAutoReponse by preferenceStrInt(
var suNotification by preferenceStrInt(Key.SU_NOTIFICATION, Value.NOTIFICATION_TOAST) Key.SU_AUTO_RESPONSE,
var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel) 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 safetyNotice by preference(Key.SAFETY, true)
var darkThemeExtended by preference( var darkThemeExtended by preference(
@ -139,9 +152,18 @@ object Config : PreferenceModel, DBConfig {
var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "") var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "")
var locale by preference(Key.LOCALE, "") var locale by preference(Key.LOCALE, "")
var rootMode by dbSettings(Key.ROOT_ACCESS, Value.ROOT_ACCESS_APPS_AND_ADB) var rootMode by dbSettings(
var suMntNamespaceMode by dbSettings(Key.SU_MNT_NS, Value.NAMESPACE_MODE_REQUESTER) Key.ROOT_ACCESS,
var suMultiuserMode by dbSettings(Key.SU_MULTIUSER_MODE, Value.MULTIUSER_MODE_OWNER_ONLY) 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 suBiometric by dbSettings(Key.SU_BIOMETRIC, false)
var suManager by dbStrings(Key.SU_MANAGER, "", true) var suManager by dbStrings(Key.SU_MANAGER, "", true)
var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true) var keyStoreRaw by dbStrings(Key.KEYSTORE, "", true)
@ -177,7 +199,9 @@ object Config : PreferenceModel, DBConfig {
} }
private fun parsePrefs(editor: SharedPreferences.Editor) = editor.apply { 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 { if (config.exists()) runCatching {
val input = SuFileInputStream(config) val input = SuFileInputStream(config)
val parser = Xml.newPullParser() val parser = Xml.newPullParser()

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk package com.topjohnwu.magisk.core
import android.os.Process import android.os.Process
import java.io.File import java.io.File

View File

@ -1,19 +1,16 @@
package com.topjohnwu.magisk.model.receiver package com.topjohnwu.magisk.core
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.core.base.BaseReceiver
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.base.BaseReceiver import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.data.database.PolicyDao
import com.topjohnwu.magisk.extensions.reboot import com.topjohnwu.magisk.extensions.reboot
import com.topjohnwu.magisk.model.download.DownloadService import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.model.entity.ManagerJson
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.utils.SuHandler import com.topjohnwu.magisk.core.view.Shortcuts
import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import org.koin.core.inject import org.koin.core.inject
@ -30,7 +27,11 @@ open class GeneralReceiver : BaseReceiver() {
when (intent.action ?: return) { when (intent.action ?: return) {
Intent.ACTION_REBOOT -> { Intent.ACTION_REBOOT -> {
SuHandler(context, intent.getStringExtra("action"), intent.extras) SuCallbackHandler(
context,
intent.getStringExtra("action"),
intent.extras
)
} }
Intent.ACTION_PACKAGE_REPLACED -> { Intent.ACTION_PACKAGE_REPLACED -> {
// This will only work pre-O // This will only work pre-O

View File

@ -1,6 +1,6 @@
@file:Suppress("DEPRECATION") @file:Suppress("DEPRECATION")
package com.topjohnwu.magisk package com.topjohnwu.magisk.core
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.job.JobInfo import android.app.job.JobInfo
@ -14,16 +14,15 @@ import android.content.res.AssetManager
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import androidx.annotation.RequiresApi 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.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.flash.FlashActivity
import com.topjohnwu.magisk.legacy.surequest.SuRequestActivity import com.topjohnwu.magisk.legacy.surequest.SuRequestActivity
import com.topjohnwu.magisk.utils.refreshLocale import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.utils.updateConfig
fun AssetManager.addAssetPath(path: String) { fun AssetManager.addAssetPath(path: String) {
DynAPK.addAssetPath(this, path) DynAPK.addAssetPath(this, path)

View File

@ -1,9 +1,10 @@
package com.topjohnwu.magisk package com.topjohnwu.magisk.core
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork 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.get
import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.UpdateInfo
import com.topjohnwu.magisk.utils.CachedValue import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell

View File

@ -1,16 +1,13 @@
package com.topjohnwu.magisk.ui package com.topjohnwu.magisk.core
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import com.topjohnwu.magisk.BuildConfig 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.model.navigation.Navigation
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.core.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.core.view.Shortcuts
import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils

View File

@ -1,15 +1,14 @@
package com.topjohnwu.magisk.model.update package com.topjohnwu.magisk.core
import androidx.work.ListenableWorker import androidx.work.ListenableWorker
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.core.base.BaseWorkerWrapper
import com.topjohnwu.magisk.base.DelegateWorker import com.topjohnwu.magisk.core.view.Notifications
import com.topjohnwu.magisk.data.repository.MagiskRepository import com.topjohnwu.magisk.data.repository.MagiskRepository
import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
class UpdateCheckService : DelegateWorker() { class UpdateCheckService : BaseWorkerWrapper() {
private val magiskRepo: MagiskRepository by inject() private val magiskRepo: MagiskRepository by inject()

View File

@ -1,47 +1,26 @@
package com.topjohnwu.magisk.base package com.topjohnwu.magisk.core.base
import android.Manifest import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.SparseArrayCompat import androidx.collection.SparseArrayCompat
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.databinding.DataBindingUtil import com.topjohnwu.magisk.core.utils.currentLocale
import androidx.databinding.ViewDataBinding import com.topjohnwu.magisk.core.wrap
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.extensions.set import com.topjohnwu.magisk.extensions.set
import com.topjohnwu.magisk.model.events.EventHandler
import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder import com.topjohnwu.magisk.model.permissions.PermissionRequestBuilder
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.magisk.wrap
import kotlin.random.Random import kotlin.random.Random
typealias RequestCallback = BaseActivity<*, *>.(Int, Intent?) -> Unit typealias RequestCallback = BaseActivity.(Int, Intent?) -> Unit
abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> : abstract class BaseActivity : AppCompatActivity() {
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
private val resultCallbacks by lazy { SparseArrayCompat<RequestCallback>() } private val resultCallbacks by lazy { SparseArrayCompat<RequestCallback>() }
init {
val theme = Config.darkThemeExtended
AppCompatDelegate.setDefaultNightMode(theme)
}
override fun applyOverrideConfiguration(config: Configuration?) { override fun applyOverrideConfiguration(config: Configuration?) {
// Force applying our preferred local // Force applying our preferred local
config?.setLocale(currentLocale) config?.setLocale(currentLocale)
@ -52,18 +31,6 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
super.attachBaseContext(base.wrap(false)) 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) { fun withPermissions(vararg permissions: String, builder: PermissionRequestBuilder.() -> Unit) {
val request = PermissionRequestBuilder().apply(builder).build() val request = PermissionRequestBuilder().apply(builder).build()
val ungranted = permissions.filter { val ungranted = permissions.filter {
@ -89,7 +56,7 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
} }
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
var success = true var success = true
for (res in grantResults) { for (res in grantResults) {
if (res != PackageManager.PERMISSION_GRANTED) { if (res != PackageManager.PERMISSION_GRANTED) {
@ -97,18 +64,18 @@ abstract class BaseActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding
break break
} }
} }
resultCallbacks[requestCode]?.apply { resultCallbacks[requestCode]?.also {
resultCallbacks.remove(requestCode) 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?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
resultCallbacks[requestCode]?.apply { resultCallbacks[requestCode]?.also {
resultCallbacks.remove(requestCode) resultCallbacks.remove(requestCode)
invoke(this@BaseActivity, resultCode, data) it(this@BaseActivity, resultCode, data)
} }
} }

View File

@ -1,10 +1,10 @@
package com.topjohnwu.magisk.base package com.topjohnwu.magisk.core.base
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.wrap import com.topjohnwu.magisk.core.wrap
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
abstract class BaseReceiver : BroadcastReceiver(), KoinComponent { abstract class BaseReceiver : BroadcastReceiver(), KoinComponent {

View File

@ -1,8 +1,8 @@
package com.topjohnwu.magisk.base package com.topjohnwu.magisk.core.base
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import com.topjohnwu.magisk.wrap import com.topjohnwu.magisk.core.wrap
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
abstract class BaseService : Service(), KoinComponent { abstract class BaseService : Service(), KoinComponent {

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.base package com.topjohnwu.magisk.core.base
import android.content.Context import android.content.Context
import android.net.Network import android.net.Network
@ -10,7 +10,7 @@ import androidx.work.ListenableWorker
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import java.util.* import java.util.*
abstract class DelegateWorker { abstract class BaseWorkerWrapper {
private lateinit var worker: ListenableWorker private lateinit var worker: ListenableWorker

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.download package com.topjohnwu.magisk.core.download
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Notification import android.app.Notification
@ -8,15 +8,15 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.extensions.chooser import com.topjohnwu.magisk.extensions.chooser
import com.topjohnwu.magisk.extensions.exists import com.topjohnwu.magisk.extensions.exists
import com.topjohnwu.magisk.extensions.provide 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.*
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary 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.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 com.topjohnwu.magisk.utils.APKInstall
import org.koin.core.get import org.koin.core.get
import java.io.File import java.io.File

View 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.extensions.writeTo
import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore 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.Configuration.APK.Upgrade
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.utils.PatchAPK
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import java.io.File import java.io.File

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.download package com.topjohnwu.magisk.core.download
import com.topjohnwu.magisk.extensions.withStreams import com.topjohnwu.magisk.extensions.withStreams
import java.io.File import java.io.File
@ -41,4 +41,4 @@ fun InputStream.toModule(file: File, installer: InputStream) {
entry = zin.nextEntry entry = zin.nextEntry
} }
} }
} }

View File

@ -1,10 +1,10 @@
package com.topjohnwu.magisk.model.download package com.topjohnwu.magisk.core.download
import android.app.Notification import android.app.Notification
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
import com.topjohnwu.magisk.base.BaseService import com.topjohnwu.magisk.core.base.BaseService
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.core.view.Notifications
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import java.util.* import java.util.*
import kotlin.random.Random.Default.nextInt import kotlin.random.Random.Default.nextInt

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.download package com.topjohnwu.magisk.core.download
import android.app.Activity import android.app.Activity
import android.app.Notification import android.app.Notification
@ -13,8 +13,8 @@ import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.writeTo 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.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
import com.topjohnwu.magisk.utils.ProgressInputStream import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.core.view.Notifications
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import io.reactivex.Completable import io.reactivex.Completable
import okhttp3.ResponseBody import okhttp3.ResponseBody

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.data.database.magiskdb package com.topjohnwu.magisk.core.magiskdb
import androidx.annotation.StringDef import androidx.annotation.StringDef
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell

View File

@ -1,16 +1,12 @@
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.core.magiskdb
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.data.database.magiskdb.BaseDao import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.data.database.magiskdb.Delete import com.topjohnwu.magisk.core.model.toMap
import com.topjohnwu.magisk.data.database.magiskdb.Replace import com.topjohnwu.magisk.core.model.toPolicy
import com.topjohnwu.magisk.data.database.magiskdb.Select
import com.topjohnwu.magisk.extensions.now 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 timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.data.database.magiskdb package com.topjohnwu.magisk.core.magiskdb
import androidx.annotation.StringDef import androidx.annotation.StringDef

View File

@ -1,9 +1,4 @@
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.core.magiskdb
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
class SettingsDao : BaseDao() { class SettingsDao : BaseDao() {

View File

@ -1,9 +1,4 @@
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.core.magiskdb
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
class StringDao : BaseDao() { class StringDao : BaseDao() {

View File

@ -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.ApplicationInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import com.topjohnwu.magisk.core.model.MagiskPolicy.Companion.INTERACTIVE
import com.topjohnwu.magisk.extensions.getLabel import com.topjohnwu.magisk.extensions.getLabel
import com.topjohnwu.magisk.model.entity.MagiskPolicy.Companion.INTERACTIVE
data class MagiskPolicy( data class MagiskPolicy(

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity package com.topjohnwu.magisk.core.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.model.entity.module package com.topjohnwu.magisk.core.model.module
abstract class BaseModule : Comparable<BaseModule> { abstract class BaseModule : Comparable<BaseModule> {
abstract var id: String abstract var id: String

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.model.entity.module package com.topjohnwu.magisk.core.model.module
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile

View File

@ -1,9 +1,9 @@
package com.topjohnwu.magisk.model.entity.module package com.topjohnwu.magisk.core.model.module
import android.os.Parcelable import android.os.Parcelable
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey 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.data.repository.StringRepository
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.legalFilename import com.topjohnwu.magisk.extensions.legalFilename

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.su
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -6,20 +6,26 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Process import android.os.Process
import android.widget.Toast 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.data.repository.LogRepository
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.startActivity import com.topjohnwu.magisk.extensions.startActivity
import com.topjohnwu.magisk.extensions.startActivityWithRoot import com.topjohnwu.magisk.extensions.startActivityWithRoot
import com.topjohnwu.magisk.extensions.subscribeK 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.legacy.surequest.SuRequestActivity
import com.topjohnwu.magisk.model.entity.toLog
import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import timber.log.Timber import timber.log.Timber
object SuHandler : ProviderCallHandler { object SuCallbackHandler : ProviderCallHandler {
const val REQUEST = "request" const val REQUEST = "request"
const val LOG = "log" const val LOG = "log"

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.su
import android.net.LocalSocket import android.net.LocalSocket
import android.net.LocalSocketAddress import android.net.LocalSocketAddress

View File

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

View File

@ -1,13 +1,13 @@
package com.topjohnwu.magisk.tasks package com.topjohnwu.magisk.core.tasks
import android.content.Context import android.content.Context
import android.net.Uri 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.fileName
import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.extensions.readUri import com.topjohnwu.magisk.extensions.readUri
import com.topjohnwu.magisk.extensions.subscribeK 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 com.topjohnwu.superuser.Shell
import io.reactivex.Single import io.reactivex.Single
import java.io.File import java.io.File

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.tasks package com.topjohnwu.magisk.core.tasks
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
@ -6,11 +6,13 @@ import android.os.Build
import android.text.TextUtils import android.text.TextUtils
import androidx.annotation.MainThread import androidx.annotation.MainThread
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import com.topjohnwu.magisk.Config import androidx.core.net.toUri
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.data.network.GithubRawServices
import com.topjohnwu.magisk.di.Protected import com.topjohnwu.magisk.di.Protected
import com.topjohnwu.magisk.extensions.* import com.topjohnwu.magisk.extensions.*
import com.topjohnwu.magisk.net.Networking
import com.topjohnwu.signing.SignBoot import com.topjohnwu.signing.SignBoot
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
@ -34,10 +36,10 @@ import java.util.zip.ZipInputStream
abstract class MagiskInstaller { abstract class MagiskInstaller {
protected lateinit var srcBoot: String
protected lateinit var destFile: File
protected lateinit var installDir: 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 console: MutableList<String>
private val logs: MutableList<String> private val logs: MutableList<String>
@ -60,7 +62,7 @@ abstract class MagiskInstaller {
installDir.mkdirs() installDir.mkdirs()
} }
protected fun findImage(): Boolean { private fun findImage(): Boolean {
srcBoot = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh() srcBoot = "find_boot_image; echo \"\$BOOTIMAGE\"".fsh()
if (srcBoot.isEmpty()) { if (srcBoot.isEmpty()) {
console.add("! Unable to detect target image") console.add("! Unable to detect target image")
@ -70,7 +72,7 @@ abstract class MagiskInstaller {
return true return true
} }
protected fun findSecondaryImage(): Boolean { private fun findSecondaryImage(): Boolean {
val slot = "echo \$SLOT".fsh() val slot = "echo \$SLOT".fsh()
val target = if (slot == "_a") "_b" else "_a" val target = if (slot == "_a") "_b" else "_a"
console.add("- Target slot: $target") console.add("- Target slot: $target")
@ -87,7 +89,7 @@ abstract class MagiskInstaller {
return true return true
} }
protected fun extractZip(): Boolean { private fun extractZip(): Boolean {
val arch: String val arch: String
arch = if (Build.VERSION.SDK_INT >= 21) { arch = if (Build.VERSION.SDK_INT >= 21) {
val abis = listOf(*Build.SUPPORTED_ABIS) 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 { try {
context.readUri(uri).buffered().use { context.readUri(uri).buffered().use {
it.mark(500) it.mark(500)
@ -238,7 +240,7 @@ abstract class MagiskInstaller {
return true return true
} }
protected fun patchBoot(): Boolean { private fun patchBoot(): Boolean {
var isSigned = false var isSigned = false
try { try {
SuFileInputStream(srcBoot).use { SuFileInputStream(srcBoot).use {
@ -284,7 +286,7 @@ abstract class MagiskInstaller {
return true return true
} }
protected fun flashBoot(): Boolean { private fun flashBoot(): Boolean {
if (!"direct_install $installDir $srcBoot".sh().isSuccess) if (!"direct_install $installDir $srcBoot".sh().isSuccess)
return false return false
arrayOf( arrayOf(
@ -294,7 +296,7 @@ abstract class MagiskInstaller {
return true return true
} }
protected fun storeBoot(): Boolean { private fun storeBoot(): Boolean {
val patched = SuFile.open(installDir, "new-boot.img") val patched = SuFile.open(installDir, "new-boot.img")
try { try {
val os = tarOut?.let { val os = tarOut?.let {
@ -320,7 +322,7 @@ abstract class MagiskInstaller {
return true return true
} }
protected fun postOTA(): Boolean { private fun postOTA(): Boolean {
val bootctl = SuFile("/data/adb/bootctl") val bootctl = SuFile("/data/adb/bootctl")
try { try {
withStreams(service.fetchBootctl().blockingGet().byteStream(), bootctl.suOutputStream()) { withStreams(service.fetchBootctl().blockingGet().byteStream(), bootctl.suOutputStream()) {
@ -345,6 +347,28 @@ abstract class MagiskInstaller {
private fun String.fsh() = ShellUtils.fastCmd(this) private fun String.fsh() = ShellUtils.fastCmd(this)
private fun Array<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 @WorkerThread
protected abstract fun operations(): Boolean protected abstract fun operations(): Boolean

View File

@ -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.database.RepoDao
import com.topjohnwu.magisk.data.network.GithubApiServices 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.Flowable
import io.reactivex.Single
import io.reactivex.rxkotlin.toFlowable import io.reactivex.rxkotlin.toFlowable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import se.ansman.kotshi.JsonSerializable import se.ansman.kotshi.JsonSerializable
@ -19,18 +19,17 @@ class RepoUpdater(
private val api: GithubApiServices, private val api: GithubApiServices,
private val repoDB: RepoDao private val repoDB: RepoDao
) { ) {
private fun loadRepos(repos: List<GithubRepoInfo>, cached: MutableSet<String>) = private fun loadRepos(repos: List<GithubRepoInfo>, cached: MutableSet<String>) =
repos.toFlowable().parallel().runOn(Schedulers.io()).map { repos.toFlowable().parallel().runOn(Schedulers.io()).map {
// Skip submission // Skip submission
if (it.id == "submission") if (it.id == "submission")
return@map return@map
(repoDB.getRepo(it.id)?.apply { cached.remove(it.id) } ?: (repoDB.getRepo(it.id)?.apply { cached.remove(it.id) } ?:
Repo(it.id)).runCatching { Repo(it.id)).runCatching {
update(it.pushDate) update(it.pushDate)
repoDB.addRepo(this) repoDB.addRepo(this)
}.getOrElse { Timber.e(it) } }.getOrElse { Timber.e(it) }
}.sequential() }.sequential()
private fun loadPage( private fun loadPage(
cached: MutableSet<String>, cached: MutableSet<String>,
@ -55,16 +54,16 @@ class RepoUpdater(
} }
private fun forcedReload(cached: MutableSet<String>) = private fun forcedReload(cached: MutableSet<String>) =
cached.toFlowable().parallel().runOn(Schedulers.io()).map { cached.toFlowable().parallel().runOn(Schedulers.io()).map {
runCatching { runCatching {
Repo(it).update() Repo(it).update()
}.getOrElse { Timber.e(it) } }.getOrElse { Timber.e(it) }
}.sequential() }.sequential()
private fun String.trimEtag() = substring(indexOf('\"'), lastIndexOf('\"') + 1) private fun String.trimEtag() = substring(indexOf('\"'), lastIndexOf('\"') + 1)
@Suppress("RedundantLambdaArrow") @Suppress("RedundantLambdaArrow")
operator fun invoke(forced: Boolean = false) : Single<Unit> { operator fun invoke(forced: Boolean = false) : Completable {
val cached = Collections.synchronizedSet(HashSet(repoDB.repoIDList)) val cached = Collections.synchronizedSet(HashSet(repoDB.repoIDList))
return loadPage(cached, etag = repoDB.etagKey).doOnComplete { return loadPage(cached, etag = repoDB.etagKey).doOnComplete {
repoDB.removeRepos(cached) repoDB.removeRepos(cached)
@ -76,16 +75,16 @@ class RepoUpdater(
Timber.e(it) Timber.e(it)
} }
Flowable.empty() Flowable.empty()
}.ignoreElements().toSingleDefault(Unit) }.ignoreElements()
} }
object CachedException : Exception() object CachedException : Exception()
} }
private val dateFormat: SimpleDateFormat = private val dateFormat: SimpleDateFormat =
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).apply { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).apply {
timeZone = TimeZone.getTimeZone("UTC") timeZone = TimeZone.getTimeZone("UTC")
} }
@JsonSerializable @JsonSerializable
data class GithubRepoInfo( data class GithubRepoInfo(

View File

@ -1,11 +1,11 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Config
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.get import org.koin.core.get

View File

@ -1,11 +1,11 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.util.Base64 import android.util.Base64
import android.util.Base64OutputStream 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.di.koinModules
import com.topjohnwu.magisk.utils.PatchAPK.ALPHANUM
import com.topjohnwu.signing.CryptoUtils.readCertificate import com.topjohnwu.signing.CryptoUtils.readCertificate
import com.topjohnwu.signing.CryptoUtils.readPrivateKey import com.topjohnwu.signing.CryptoUtils.readPrivateKey
import com.topjohnwu.superuser.internal.InternalUtils import com.topjohnwu.superuser.internal.InternalUtils
@ -50,10 +50,14 @@ class Keygen: CertKeyProvider {
private val provider: CertKeyProvider private val provider: CertKeyProvider
inner class KeyStoreProvider : CertKeyProvider { inner class KeyStoreProvider :
CertKeyProvider {
private val ks by lazy { init() } private val ks by lazy { init() }
override val cert by lazy { ks.getCertificate(ALIAS) as X509Certificate } 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 { class TestProvider : CertKeyProvider {
@ -113,8 +117,12 @@ class Keygen: CertKeyProvider {
if (raw.isEmpty()) { if (raw.isEmpty()) {
ks.load(null) ks.load(null)
} else { } else {
GZIPInputStream(Base64.decode(raw, BASE64_FLAG).inputStream()).use { GZIPInputStream(Base64.decode(raw,
ks.load(it, PASSWORD) BASE64_FLAG
).inputStream()).use {
ks.load(it,
PASSWORD
)
} }
} }
@ -131,10 +139,16 @@ class Keygen: CertKeyProvider {
val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer)) val cert = JcaX509CertificateConverter().getCertificate(builder.build(signer))
// Store them into keystore // Store them into keystore
ks.setKeyEntry(ALIAS, kp.private, PASSWORD, arrayOf(cert)) ks.setKeyEntry(
ALIAS, kp.private,
PASSWORD, arrayOf(cert))
val bytes = ByteArrayOutputStream() val bytes = ByteArrayOutputStream()
GZIPOutputStream(Base64OutputStream(bytes, BASE64_FLAG)).use { GZIPOutputStream(Base64OutputStream(bytes,
ks.store(it, PASSWORD) BASE64_FLAG
)).use {
ks.store(it,
PASSWORD
)
} }
Config.keyStoreRaw = bytes.toString("UTF-8") Config.keyStoreRaw = bytes.toString("UTF-8")

View File

@ -1,13 +1,13 @@
@file:Suppress("DEPRECATION") @file:Suppress("DEPRECATION")
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R 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.langTagToLocale
import com.topjohnwu.magisk.extensions.toLangTag import com.topjohnwu.magisk.extensions.toLangTag
import io.reactivex.Single import io.reactivex.Single

View File

@ -1,15 +1,20 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import android.content.Context import android.content.Context
import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION.SDK_INT
import android.widget.Toast 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.data.network.GithubRawServices
import com.topjohnwu.magisk.extensions.DynamicClassLoader import com.topjohnwu.magisk.extensions.DynamicClassLoader
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.writeTo 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.JarMap
import com.topjohnwu.signing.SignAPK import com.topjohnwu.signing.SignAPK
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
import java.io.FilterInputStream import java.io.FilterInputStream
@ -41,4 +41,4 @@ class ProgressInputStream(
} }
return sz return sz
} }
} }

View File

@ -1,10 +1,10 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import android.content.Context import android.content.Context
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R 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.extensions.rawResource
import com.topjohnwu.magisk.wrap
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.io.SuFile import com.topjohnwu.superuser.io.SuFile

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
interface SafetyNetHelper { interface SafetyNetHelper {

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.utils package com.topjohnwu.magisk.core.utils
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -7,10 +7,10 @@ import android.net.Uri
import android.os.Environment import android.os.Environment
import android.widget.Toast import android.widget.Toast
import androidx.work.* import androidx.work.*
import com.topjohnwu.magisk.* import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.model.update.UpdateCheckService
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
import java.io.File import java.io.File
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -62,7 +62,10 @@ object Utils {
if (intent.resolveActivity(context.packageManager) != null) { if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent) context.startActivity(intent)
} else { } else {
toast(R.string.open_link_failed_toast, Toast.LENGTH_SHORT) toast(
R.string.open_link_failed_toast,
Toast.LENGTH_SHORT
)
} }
} }

View File

@ -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.SuFile
import com.topjohnwu.superuser.io.SuFileOutputStream import com.topjohnwu.superuser.io.SuFileOutputStream

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.view package com.topjohnwu.magisk.core.view
import android.app.Notification import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
@ -9,13 +9,12 @@ import android.os.Build.VERSION.SDK_INT
import androidx.core.app.TaskStackBuilder import androidx.core.app.TaskStackBuilder
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toIcon import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.* import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.Const.ID.PROGRESS_NOTIFICATION_CHANNEL import com.topjohnwu.magisk.core.*
import com.topjohnwu.magisk.Const.ID.UPDATE_NOTIFICATION_CHANNEL 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.get
import com.topjohnwu.magisk.extensions.getBitmap import com.topjohnwu.magisk.extensions.getBitmap
import com.topjohnwu.magisk.model.receiver.GeneralReceiver
import com.topjohnwu.magisk.ui.SplashActivity
object Notifications { object Notifications {
@ -52,10 +51,13 @@ object Notifications {
val stackBuilder = TaskStackBuilder.create(context) val stackBuilder = TaskStackBuilder.create(context)
stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName)) stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName))
stackBuilder.addNextIntent(intent) 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) PendingIntent.FLAG_UPDATE_CURRENT)
val builder = updateBuilder(context) val builder = updateBuilder(
context
)
.setContentTitle(context.getString(R.string.magisk_update_title)) .setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install)) .setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true) .setAutoCancel(true)
@ -72,7 +74,9 @@ object Notifications {
val pendingIntent = PendingIntent.getBroadcast(context, val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) 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)) .setContentTitle(context.getString(R.string.manager_update_title))
.setContentText(context.getString(R.string.manager_download_install)) .setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true) .setAutoCancel(true)
@ -87,7 +91,9 @@ object Notifications {
val pendingIntent = PendingIntent.getBroadcast(context, val pendingIntent = PendingIntent.getBroadcast(context,
Const.ID.DTBO_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT) 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)) .setContentTitle(context.getString(R.string.dtbo_patched_title))
.setContentText(context.getString(R.string.dtbo_patched_reboot)) .setContentText(context.getString(R.string.dtbo_patched_reboot))

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.view package com.topjohnwu.magisk.core.view
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -10,17 +10,18 @@ import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toAdaptiveIcon import androidx.core.graphics.drawable.toAdaptiveIcon
import androidx.core.graphics.drawable.toIcon 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.extensions.getBitmap
import com.topjohnwu.magisk.ui.SplashActivity
import com.topjohnwu.magisk.utils.Utils
object Shortcuts { object Shortcuts {
fun setup(context: Context) { fun setup(context: Context) {
if (Build.VERSION.SDK_INT >= 25) { if (Build.VERSION.SDK_INT >= 25) {
val manager = context.getSystemService<ShortcutManager>() val manager = context.getSystemService<ShortcutManager>()
manager?.dynamicShortcuts = getShortCuts(context) manager?.dynamicShortcuts =
getShortCuts(context)
} }
} }

View File

@ -4,7 +4,7 @@ package com.topjohnwu.magisk.data.database
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import com.topjohnwu.magisk.model.entity.module.Repo import com.topjohnwu.magisk.core.model.module.Repo
interface RepoBase { interface RepoBase {
@ -64,4 +64,4 @@ interface RepoByNameDao : RepoBase {
override fun searchRepos(query: String, offset: Int, limit: Int): List<Repo> override fun searchRepos(query: String, offset: Int, limit: Int): List<Repo>
} }

View File

@ -1,8 +1,8 @@
package com.topjohnwu.magisk.data.database package com.topjohnwu.magisk.data.database
import androidx.room.* import androidx.room.*
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.model.entity.module.Repo import com.topjohnwu.magisk.core.model.module.Repo
@Database(version = 6, entities = [Repo::class, RepoEtag::class]) @Database(version = 6, entities = [Repo::class, RepoEtag::class])
abstract class RepoDatabase : RoomDatabase() { abstract class RepoDatabase : RoomDatabase() {

View File

@ -1,8 +1,8 @@
package com.topjohnwu.magisk.data.network package com.topjohnwu.magisk.data.network
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.model.entity.UpdateInfo import com.topjohnwu.magisk.core.tasks.GithubRepoInfo
import com.topjohnwu.magisk.tasks.GithubRepoInfo import com.topjohnwu.magisk.core.model.UpdateInfo
import io.reactivex.Flowable import io.reactivex.Flowable
import io.reactivex.Single import io.reactivex.Single
import okhttp3.ResponseBody import okhttp3.ResponseBody
@ -78,4 +78,4 @@ interface GithubApiServices {
@Query("sort") sort: String = "pushed", @Query("sort") sort: String = "pushed",
@Query("per_page") count: Int = 100): Flowable<Result<List<GithubRepoInfo>>> @Query("per_page") count: Int = 100): Flowable<Result<List<GithubRepoInfo>>>
} }

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.data.repository package com.topjohnwu.magisk.data.repository
import com.topjohnwu.magisk.data.database.SettingsDao import com.topjohnwu.magisk.core.magiskdb.SettingsDao
import com.topjohnwu.magisk.data.database.StringDao import com.topjohnwu.magisk.core.magiskdb.StringDao
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty

View File

@ -1,6 +1,6 @@
package com.topjohnwu.magisk.data.repository 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.data.database.SuLogDao
import com.topjohnwu.magisk.model.entity.MagiskLog import com.topjohnwu.magisk.model.entity.MagiskLog
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell

View File

@ -1,8 +1,8 @@
package com.topjohnwu.magisk.data.repository package com.topjohnwu.magisk.data.repository
import android.content.pm.PackageManager import android.content.pm.PackageManager
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.data.network.GithubRawServices import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.extensions.getLabel import com.topjohnwu.magisk.extensions.getLabel
import com.topjohnwu.magisk.extensions.packageName import com.topjohnwu.magisk.extensions.packageName
@ -24,7 +24,8 @@ class MagiskRepository(
Config.Value.BETA_CHANNEL -> apiRaw.fetchBetaUpdate() Config.Value.BETA_CHANNEL -> apiRaw.fetchBetaUpdate()
Config.Value.CANARY_CHANNEL -> apiRaw.fetchCanaryUpdate() Config.Value.CANARY_CHANNEL -> apiRaw.fetchCanaryUpdate()
Config.Value.CANARY_DEBUG_CHANNEL -> apiRaw.fetchCanaryDebugUpdate() 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() else -> throw IllegalArgumentException()
}.flatMap { }.flatMap {
// If remote version is lower than current installed, try switching to beta // If remote version is lower than current installed, try switching to beta

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.data.repository 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.data.network.GithubRawServices
import com.topjohnwu.magisk.model.entity.module.Repo
class StringRepository( class StringRepository(
private val api: GithubRawServices private val api: GithubRawServices
@ -12,4 +12,4 @@ class StringRepository(
fun getMetadata(repo: Repo) = api.fetchModuleInfo(repo.id, "module.prop") fun getMetadata(repo: Repo) = api.fetchModuleInfo(repo.id, "module.prop")
fun getReadme(repo: Repo) = api.fetchModuleInfo(repo.id, "README.md") fun getReadme(repo: Repo) = api.fetchModuleInfo(repo.id, "README.md")
} }

View File

@ -2,8 +2,12 @@ package com.topjohnwu.magisk.di
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
import com.topjohnwu.magisk.data.database.* import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.tasks.RepoUpdater 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 import org.koin.dsl.module

View File

@ -4,7 +4,7 @@ import android.content.Context
import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.topjohnwu.magisk.BuildConfig 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.GithubApiServices
import com.topjohnwu.magisk.data.network.GithubRawServices import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.net.Networking import com.topjohnwu.magisk.net.Networking

View File

@ -28,11 +28,11 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.net.toFile import androidx.core.net.toFile
import androidx.core.net.toUri import androidx.core.net.toUri
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.FileProvider 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.DynamicClassLoader
import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.magisk.utils.currentLocale
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
import java.io.File import java.io.File
@ -317,7 +317,9 @@ fun Context.hasPermissions(vararg permissions: String) = permissions.all {
ContextCompat.checkSelfPermission(this, it) == PERMISSION_GRANTED 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. */ /** Friendly reminder to seek newer roms or install oem updates. */
val isDeviceSecure: Boolean val isDeviceSecure: Boolean

View File

@ -1,6 +1,6 @@
package com.topjohnwu.magisk.extensions 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.Shell
import com.topjohnwu.superuser.io.SuFileInputStream import com.topjohnwu.superuser.io.SuFileInputStream
import com.topjohnwu.superuser.io.SuFileOutputStream 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.suOutputStream() = SuFileOutputStream(this)
fun File.suInputStream() = SuFileInputStream(this) fun File.suInputStream() = SuFileInputStream(this)
val hasRoot get() = Shell.rootAccess() val hasRoot get() = Shell.rootAccess()

View File

@ -1,6 +1,6 @@
package com.topjohnwu.magisk.extensions 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.DateFormat
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -14,10 +14,18 @@ fun String.toTime(format: DateFormat) = try {
-1L -1L
} }
val timeFormatFull by lazy { SimpleDateFormat("yyyy/MM/dd_HH:mm:ss", currentLocale) } val timeFormatFull by lazy { SimpleDateFormat("yyyy/MM/dd_HH:mm:ss",
val timeFormatStandard by lazy { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", currentLocale) } currentLocale
val timeFormatMedium by lazy { DateFormat.getDateInstance(DateFormat.MEDIUM, currentLocale) } ) }
val timeFormatTime by lazy { SimpleDateFormat("h:mm a", 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 { val timeDateFormat by lazy {
DateFormat.getDateTimeInstance( DateFormat.getDateTimeInstance(
DateFormat.DEFAULT, DateFormat.DEFAULT,

View File

@ -6,22 +6,22 @@ import android.content.pm.ActivityInfo
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.core.net.toUri import androidx.core.net.toUri
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R 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.databinding.ActivityFlashBinding
import com.topjohnwu.magisk.extensions.snackbar import com.topjohnwu.magisk.extensions.snackbar
import com.topjohnwu.magisk.intent
import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.SnackbarEvent import com.topjohnwu.magisk.model.events.SnackbarEvent
import com.topjohnwu.magisk.model.events.ViewEvent 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.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
import java.io.File 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 layoutRes: Int = R.layout.activity_flash
override val themeRes: Int = R.style.MagiskTheme_Flashing override val themeRes: Int = R.style.MagiskTheme_Flashing

View File

@ -8,10 +8,9 @@ import android.os.Handler
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import androidx.databinding.ObservableArrayList import androidx.databinding.ObservableArrayList
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R 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.databinding.ComparableRvItem
import com.topjohnwu.magisk.extensions.* import com.topjohnwu.magisk.extensions.*
import com.topjohnwu.magisk.model.entity.recycler.ConsoleRvItem 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.FlashResultListener
import com.topjohnwu.magisk.model.flash.Flashing import com.topjohnwu.magisk.model.flash.Flashing
import com.topjohnwu.magisk.model.flash.Patching 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.DiffObservableList
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell

View File

@ -6,16 +6,16 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.Window import android.view.Window
import com.topjohnwu.magisk.R 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.databinding.ActivityRequestBinding
import com.topjohnwu.magisk.model.events.DieEvent import com.topjohnwu.magisk.model.events.DieEvent
import com.topjohnwu.magisk.model.events.ViewActionEvent import com.topjohnwu.magisk.model.events.ViewActionEvent
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
import com.topjohnwu.magisk.utils.SuHandler import com.topjohnwu.magisk.ui.base.BaseUIActivity
import com.topjohnwu.magisk.utils.SuHandler.REQUEST
import org.koin.androidx.viewmodel.ext.android.viewModel 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 layoutRes: Int = R.layout.activity_request
override val themeRes: Int = R.style.MagiskTheme_SU override val themeRes: Int = R.style.MagiskTheme_SU
@ -36,7 +36,11 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB
} }
fun runHandler(action: String?) { fun runHandler(action: String?) {
SuHandler(this, action, intent.extras) SuCallbackHandler(
this,
action,
intent.extras
)
finish() finish()
} }

View File

@ -6,41 +6,36 @@ import android.content.pm.PackageManager
import android.content.res.Resources import android.content.res.Resources
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.CountDownTimer 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.R
import com.topjohnwu.magisk.base.BaseViewModel import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.data.database.PolicyDao 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.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.recycler.SpinnerRvItem
import com.topjohnwu.magisk.model.entity.toPolicy
import com.topjohnwu.magisk.model.events.DieEvent 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.DiffObservableList
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.magisk.utils.SuConnector
import me.tatarka.bindingcollectionadapter2.BindingListViewAdapter import me.tatarka.bindingcollectionadapter2.BindingListViewAdapter
import me.tatarka.bindingcollectionadapter2.ItemBinding import me.tatarka.bindingcollectionadapter2.ItemBinding
import timber.log.Timber import java.util.concurrent.TimeUnit.SECONDS
import java.io.IOException
import java.util.concurrent.TimeUnit.*
class SuRequestViewModel( class SuRequestViewModel(
private val packageManager: PackageManager, private val pm: PackageManager,
private val policyDB: PolicyDao, private val policyDB: PolicyDao,
private val timeoutPrefs: SharedPreferences, private val timeoutPrefs: SharedPreferences,
private val resources: Resources private val res: Resources
) : BaseViewModel() { ) : BaseViewModel() {
val icon = KObservableField<Drawable?>(null) val icon = KObservableField<Drawable?>(null)
val title = KObservableField("") val title = KObservableField("")
val packageName = KObservableField("") val packageName = KObservableField("")
val denyText = KObservableField(resources.getString(R.string.deny)) val denyText = KObservableField(res.getString(R.string.deny))
val warningText = KObservableField<CharSequence>(resources.getString(R.string.su_warning)) val warningText = KObservableField<CharSequence>(res.getString(R.string.su_warning))
val selectedItemPosition = KObservableField(0) val selectedItemPosition = KObservableField(0)
@ -54,130 +49,74 @@ class SuRequestViewModel(
setItems(items) setItems(items)
} }
private val cancelTasks = mutableListOf<() -> Unit>() private val handler = Handler()
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)
}
fun grantPressed() { fun grantPressed() {
cancelTimer() handler.cancelTimer()
if (BiometricHelper.isEnabled) { if (BiometricHelper.isEnabled) {
withView { withView {
BiometricHelper.authenticate(this) { BiometricHelper.authenticate(this) {
handleAction(MagiskPolicy.ALLOW) handler.respond(ALLOW)
} }
} }
} else { } else {
handleAction(MagiskPolicy.ALLOW) handler.respond(ALLOW)
} }
} }
fun denyPressed() { fun denyPressed() {
handleAction(MagiskPolicy.DENY) handler.respond(DENY)
timer.cancel()
} }
fun spinnerTouched(): Boolean { fun spinnerTouched(): Boolean {
cancelTimer() handler.cancelTimer()
return false return false
} }
fun handleRequest(intent: Intent): Boolean { fun handleRequest(intent: Intent): Boolean {
val socketName = intent.getStringExtra("socket") ?: return false return handler.start(intent)
}
try { private inner class Handler : SuRequestHandler(pm, policyDB) {
connector = Connector(socketName)
val map = connector.readRequest() fun respond(action: Int) {
val uid = map["uid"]?.toIntOrNull() ?: return false val pos = selectedItemPosition.value
policy = uid.toPolicy(packageManager) timeoutPrefs.edit().putInt(policy.packageName, pos).apply()
} catch (e: Exception) { respond(action, Config.Value.TIMEOUT_LIST[pos])
Timber.e(e)
return false
} }
// Never allow com.topjohnwu.magisk (could be malware) fun cancelTimer() {
if (policy.packageName == BuildConfig.APPLICATION_ID) timer.cancel()
return false denyText.value = res.getString(R.string.deny)
}
when (Config.suAutoReponse) { override fun onStart() {
Config.Value.SU_AUTO_DENY -> { res.getStringArray(R.array.allow_timeout)
handleAction(MagiskPolicy.DENY, 0) .map { SpinnerRvItem(it) }
return true .let { items.update(it) }
}
Config.Value.SU_AUTO_ALLOW -> { icon.value = policy.applicationInfo.loadIcon(pm)
handleAction(MagiskPolicy.ALLOW, 0) title.value = policy.appName
return true 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() override fun onRespond() {
return true // Kill activity after response
} DieEvent().publish()
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)
} }
} }

View File

@ -3,10 +3,11 @@ package com.topjohnwu.magisk.model.entity
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Ignore import androidx.room.Ignore
import androidx.room.PrimaryKey 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.now
import com.topjohnwu.magisk.extensions.timeFormatTime import com.topjohnwu.magisk.extensions.timeFormatTime
import com.topjohnwu.magisk.extensions.toTime import com.topjohnwu.magisk.extensions.toTime
import com.topjohnwu.magisk.model.entity.MagiskPolicy.Companion.ALLOW
@Entity(tableName = "logs") @Entity(tableName = "logs")
data class MagiskLog( data class MagiskLog(
@ -23,11 +24,6 @@ data class MagiskLog(
@Ignore val timeString = time.toTime(timeFormatTime) @Ignore val timeString = time.toTime(timeFormatTime)
} }
data class WrappedMagiskLog(
val time: Long,
val items: List<MagiskLog>
)
fun MagiskPolicy.toLog( fun MagiskPolicy.toLog(
toUid: Int, toUid: Int,
fromPid: Int, fromPid: Int,

View File

@ -2,13 +2,13 @@ package com.topjohnwu.magisk.model.entity.internal
import android.content.Context import android.content.Context
import android.os.Parcelable import android.os.Parcelable
import com.topjohnwu.magisk.Config import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.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.cachedFile
import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.model.entity.MagiskJson import com.topjohnwu.magisk.core.model.MagiskJson
import com.topjohnwu.magisk.model.entity.ManagerJson import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.model.entity.module.Repo
import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import java.io.File import java.io.File
@ -103,4 +103,4 @@ sealed class DownloadSubject : Parcelable {
} }
} }

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.model.entity.recycler package com.topjohnwu.magisk.model.entity.recycler
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem
sealed class HomeItem : ComparableRvItem<HomeItem>() { sealed class HomeItem : ComparableRvItem<HomeItem>() {

View File

@ -7,9 +7,9 @@ import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.StaggeredGridLayoutManager import androidx.recyclerview.widget.StaggeredGridLayoutManager
import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R 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.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.ui.module.ModuleViewModel
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField

View File

@ -2,9 +2,9 @@ package com.topjohnwu.magisk.model.entity.recycler
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.model.MagiskPolicy
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem
import com.topjohnwu.magisk.extensions.toggle import com.topjohnwu.magisk.extensions.toggle
import com.topjohnwu.magisk.model.entity.MagiskPolicy
import com.topjohnwu.magisk.model.events.PolicyUpdateEvent import com.topjohnwu.magisk.model.events.PolicyUpdateEvent
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import com.topjohnwu.magisk.utils.KObservableField import com.topjohnwu.magisk.utils.KObservableField

View File

@ -2,7 +2,7 @@ package com.topjohnwu.magisk.model.events
import android.content.Context import android.content.Context
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.core.base.BaseActivity
interface ContextExecutor { interface ContextExecutor {
@ -12,7 +12,7 @@ interface ContextExecutor {
interface ActivityExecutor { interface ActivityExecutor {
operator fun invoke(activity: BaseActivity<*, *>) operator fun invoke(activity: BaseActivity)
} }

View File

@ -3,14 +3,14 @@ package com.topjohnwu.magisk.model.events
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.base.BaseActivity import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.legacy.flash.FlashActivity import com.topjohnwu.magisk.legacy.flash.FlashActivity
class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor { class InstallExternalModuleEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
activity.withExternalRW { activity.withExternalRW {
onSuccess { onSuccess {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)

View File

@ -1,6 +1,6 @@
package com.topjohnwu.magisk.model.events 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 import com.topjohnwu.magisk.utils.RxBus
sealed class PolicyUpdateEvent(val item: MagiskPolicy) : RxBus.Event { sealed class PolicyUpdateEvent(val item: MagiskPolicy) : RxBus.Event {

View File

@ -3,8 +3,9 @@ package com.topjohnwu.magisk.model.events
import android.content.Context import android.content.Context
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar 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.extensions.snackbar
import com.topjohnwu.magisk.ui.base.BaseUIActivity
class SnackbarEvent private constructor( class SnackbarEvent private constructor(
@StringRes private val messageRes: Int, @StringRes private val messageRes: Int,
@ -27,8 +28,8 @@ class SnackbarEvent private constructor(
fun message(context: Context): String = messageString ?: context.getString(messageRes) fun message(context: Context): String = messageString ?: context.getString(messageRes)
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
if (activity is BaseActivity<*, *>) { if (activity is BaseUIActivity<*, *>) {
activity.snackbar(activity.snackbarView, message(activity), length, f) activity.snackbar(activity.snackbarView, message(activity), length, f)
} }
} }

View File

@ -3,16 +3,16 @@ package com.topjohnwu.magisk.model.events
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R 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.data.repository.MagiskRepository
import com.topjohnwu.magisk.extensions.DynamicClassLoader import com.topjohnwu.magisk.extensions.DynamicClassLoader
import com.topjohnwu.magisk.extensions.subscribeK import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.extensions.writeTo 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.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.MagiskDialog
import com.topjohnwu.magisk.view.MarkDownWindow import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -118,8 +118,8 @@ class UpdateSafetyNetEvent : ViewEvent(), ContextExecutor, KoinComponent, Safety
} }
} }
class ViewActionEvent(val action: BaseActivity<*, *>.() -> Unit) : ViewEvent(), ActivityExecutor { class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) = activity.run(action) override fun invoke(activity: BaseActivity) = activity.run(action)
} }
class OpenChangelogEvent(val item: Repo) : ViewEvent(), ContextExecutor { class OpenChangelogEvent(val item: Repo) : ViewEvent(), ContextExecutor {
@ -133,7 +133,7 @@ class PermissionEvent(
val callback: PublishSubject<Boolean> val callback: PublishSubject<Boolean>
) : ViewEvent(), ActivityExecutor { ) : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) = override fun invoke(activity: BaseActivity) =
activity.withPermissions(*permissions.toTypedArray()) { activity.withPermissions(*permissions.toTypedArray()) {
onSuccess { onSuccess {
callback.onNext(true) callback.onNext(true)
@ -146,25 +146,25 @@ class PermissionEvent(
} }
class BackPressEvent : ViewEvent(), ActivityExecutor { class BackPressEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
activity.onBackPressed() activity.onBackPressed()
} }
} }
class DieEvent : ViewEvent(), ActivityExecutor { class DieEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
activity.finish() activity.finish()
} }
} }
class RecreateEvent : ViewEvent(), ActivityExecutor { class RecreateEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
activity.recreate() activity.recreate()
} }
} }
class RequestFileEvent : ViewEvent(), ActivityExecutor { class RequestFileEvent : ViewEvent(), ActivityExecutor {
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
Intent(Intent.ACTION_GET_CONTENT) Intent(Intent.ACTION_GET_CONTENT)
.setType("*/*") .setType("*/*")
.addCategory(Intent.CATEGORY_OPENABLE) .addCategory(Intent.CATEGORY_OPENABLE)

View File

@ -1,9 +1,9 @@
package com.topjohnwu.magisk.model.events.dialog 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.ActivityExecutor
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
import com.topjohnwu.magisk.utils.BiometricHelper import com.topjohnwu.magisk.core.utils.BiometricHelper
class BiometricDialog( class BiometricDialog(
builder: Builder.() -> Unit builder: Builder.() -> Unit
@ -16,7 +16,7 @@ class BiometricDialog(
builder(Builder()) builder(Builder())
} }
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
BiometricHelper.authenticate( BiometricHelper.authenticate(
activity, activity,
onError = listenerOnFailure, onError = listenerOnFailure,

View File

@ -2,9 +2,9 @@ package com.topjohnwu.magisk.model.events.dialog
import android.app.Activity import android.app.Activity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.topjohnwu.magisk.Config
import com.topjohnwu.magisk.R 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.model.events.ActivityExecutor
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@ -13,7 +13,7 @@ class DarkThemeDialog : DialogEvent(), ActivityExecutor {
private var activity: WeakReference<Activity>? = null private var activity: WeakReference<Activity>? = null
override fun invoke(activity: BaseActivity<*, *>) { override fun invoke(activity: BaseActivity) {
this.activity = WeakReference(activity) this.activity = WeakReference(activity)
} }

View File

@ -1,24 +1,14 @@
package com.topjohnwu.magisk.model.events.dialog package com.topjohnwu.magisk.model.events.dialog
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.widget.Toast import android.widget.Toast
import androidx.core.net.toUri
import com.topjohnwu.magisk.Info
import com.topjohnwu.magisk.R 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.extensions.reboot
import com.topjohnwu.magisk.net.Networking import com.topjohnwu.magisk.core.utils.Utils
import com.topjohnwu.magisk.tasks.MagiskInstaller
import com.topjohnwu.magisk.utils.Utils
import com.topjohnwu.magisk.view.MagiskDialog 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.internal.UiThreadHandler
import com.topjohnwu.superuser.io.SuFile
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.get
import java.io.File
class EnvFixDialog : DialogEvent() { class EnvFixDialog : DialogEvent() {
@ -48,19 +38,7 @@ class EnvFixDialog : DialogEvent() {
private fun fixEnv(dialog: DialogInterface) { private fun fixEnv(dialog: DialogInterface) {
object : MagiskInstaller(), KoinComponent { object : MagiskInstaller(), KoinComponent {
override fun operations(): Boolean { override fun operations() = fixEnv()
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 onResult(success: Boolean) { override fun onResult(success: Boolean) {
dialog.dismiss() dialog.dismiss()
@ -74,4 +52,4 @@ class EnvFixDialog : DialogEvent() {
}.exec() }.exec()
} }
} }

View File

@ -4,16 +4,16 @@ import android.Manifest
import android.net.Uri import android.net.Uri
import android.view.LayoutInflater import android.view.LayoutInflater
import android.widget.Toast import android.widget.Toast
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.databinding.IncludeInstallOptionsBinding import com.topjohnwu.magisk.databinding.IncludeInstallOptionsBinding
import com.topjohnwu.magisk.extensions.hasPermissions import com.topjohnwu.magisk.extensions.hasPermissions
import com.topjohnwu.magisk.extensions.res 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.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.events.OpenInappLinkEvent 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.MagiskDialog
import com.topjohnwu.magisk.view.MarkDownWindow import com.topjohnwu.magisk.view.MarkDownWindow
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -128,4 +128,4 @@ class MagiskInstallDialog : DialogEvent() {
.fastCmd("grep_prop ro.build.ab_update") .fastCmd("grep_prop ro.build.ab_update")
.let { it.isNotEmpty() && it.toBoolean() } .let { it.isNotEmpty() && it.toBoolean() }
} }

View File

@ -1,9 +1,9 @@
package com.topjohnwu.magisk.model.events.dialog 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.R
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.extensions.res 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.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
@ -33,4 +33,4 @@ class ManagerInstallDialog : DialogEvent() {
} }
} }
} }

View File

@ -1,10 +1,10 @@
package com.topjohnwu.magisk.model.events.dialog package com.topjohnwu.magisk.model.events.dialog
import com.topjohnwu.magisk.R 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.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
import com.topjohnwu.magisk.model.entity.module.Repo
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
class ModuleInstallDialog(private val item: Repo) : DialogEvent() { class ModuleInstallDialog(private val item: Repo) : DialogEvent() {
@ -34,4 +34,4 @@ class ModuleInstallDialog(private val item: Repo) : DialogEvent() {
} }
} }
} }

View File

@ -1,12 +1,12 @@
package com.topjohnwu.magisk.model.events.dialog package com.topjohnwu.magisk.model.events.dialog
import android.widget.Toast import android.widget.Toast
import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.R 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.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject 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.magisk.view.MagiskDialog
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -52,4 +52,4 @@ class UninstallDialog : DialogEvent() {
} }
} }
} }

View File

@ -3,8 +3,8 @@ package com.topjohnwu.magisk.model.flash
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import com.topjohnwu.magisk.core.tasks.FlashZip
import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.inject
import com.topjohnwu.magisk.tasks.FlashZip
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.internal.UiThreadHandler import com.topjohnwu.superuser.internal.UiThreadHandler
@ -58,4 +58,4 @@ sealed class Flashing(
} }
} }
} }

View File

@ -1,7 +1,7 @@
package com.topjohnwu.magisk.model.flash package com.topjohnwu.magisk.model.flash
import android.net.Uri import android.net.Uri
import com.topjohnwu.magisk.tasks.MagiskInstaller import com.topjohnwu.magisk.core.tasks.MagiskInstaller
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
sealed class Patching( sealed class Patching(
@ -28,8 +28,7 @@ sealed class Patching(
logs: MutableList<String>, logs: MutableList<String>,
resultListener: FlashResultListener resultListener: FlashResultListener
) : Patching(file, console, logs, resultListener) { ) : Patching(file, console, logs, resultListener) {
override fun operations() = override fun operations() = doPatchFile(uri)
extractZip() && handleFile(uri) && patchBoot() && storeBoot()
} }
class SecondSlot( class SecondSlot(
@ -38,8 +37,7 @@ sealed class Patching(
logs: MutableList<String>, logs: MutableList<String>,
resultListener: FlashResultListener resultListener: FlashResultListener
) : Patching(file, console, logs, resultListener) { ) : Patching(file, console, logs, resultListener) {
override fun operations() = override fun operations() = secondSlot()
findSecondaryImage() && extractZip() && patchBoot() && flashBoot() && postOTA()
} }
class Direct( class Direct(
@ -48,8 +46,7 @@ sealed class Patching(
logs: MutableList<String>, logs: MutableList<String>,
resultListener: FlashResultListener resultListener: FlashResultListener
) : Patching(file, console, logs, resultListener) { ) : Patching(file, console, logs, resultListener) {
override fun operations() = override fun operations() = direct()
findImage() && extractZip() && patchBoot() && flashBoot()
} }
} }

View File

@ -4,10 +4,10 @@ import android.os.Bundle
import androidx.annotation.AnimRes import androidx.annotation.AnimRes
import androidx.annotation.AnimatorRes import androidx.annotation.AnimatorRes
import androidx.fragment.app.Fragment 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.ActivityExecutor
import com.topjohnwu.magisk.model.events.ViewEvent 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 import kotlin.reflect.KClass
@DslMarker @DslMarker
@ -23,7 +23,7 @@ class MagiskNavigationEvent(
operator fun invoke(builder: Builder.() -> Unit) = Builder().apply(builder).build() 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 if (activity !is CompatActivity<*, *>) return
activity.navigation?.navigateTo(this) activity.navigation?.navigateTo(this)
} }

View File

@ -3,8 +3,8 @@ package com.topjohnwu.magisk.model.navigation
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.intent import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.MainActivity
import com.topjohnwu.magisk.ui.hide.HideFragment import com.topjohnwu.magisk.ui.hide.HideFragment
import com.topjohnwu.magisk.ui.home.HomeFragment import com.topjohnwu.magisk.ui.home.HomeFragment
@ -82,7 +82,9 @@ object Navigation {
fun start(launchIntent: Intent, context: Context) { fun start(launchIntent: Intent, context: Context) {
context.intent<MainActivity>() 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( .putExtra(
Const.Key.OPEN_SETTINGS, Const.Key.OPEN_SETTINGS,
launchIntent.action == ACTION_APPLICATION_PREFERENCES launchIntent.action == ACTION_APPLICATION_PREFERENCES

View File

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

View File

@ -12,13 +12,13 @@ import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
import com.ncapdevi.fragnav.FragNavController import com.ncapdevi.fragnav.FragNavController
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import com.topjohnwu.magisk.extensions.startAnimations import com.topjohnwu.magisk.extensions.startAnimations
import com.topjohnwu.magisk.model.navigation.Navigation import com.topjohnwu.magisk.model.navigation.Navigation
import com.topjohnwu.magisk.ui.compat.CompatActivity import com.topjohnwu.magisk.ui.base.CompatActivity
import com.topjohnwu.magisk.ui.compat.CompatNavigationDelegate import com.topjohnwu.magisk.ui.base.CompatNavigationDelegate
import com.topjohnwu.magisk.ui.home.HomeFragment import com.topjohnwu.magisk.ui.home.HomeFragment
import com.topjohnwu.magisk.ui.module.ModuleFragment import com.topjohnwu.magisk.ui.module.ModuleFragment
import com.topjohnwu.magisk.ui.superuser.SuperuserFragment import com.topjohnwu.magisk.ui.superuser.SuperuserFragment

View File

@ -1,5 +1,5 @@
package com.topjohnwu.magisk.ui package com.topjohnwu.magisk.ui
import com.topjohnwu.magisk.base.BaseViewModel import com.topjohnwu.magisk.ui.base.BaseViewModel
class MainViewModel : BaseViewModel() class MainViewModel : BaseViewModel()

View File

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

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.base package com.topjohnwu.magisk.ui.base
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater 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.EventHandler
import com.topjohnwu.magisk.model.events.ViewEvent import com.topjohnwu.magisk.model.events.ViewEvent
abstract class BaseFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding> : abstract class BaseUIFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding> :
Fragment(), EventHandler { Fragment(), EventHandler {
protected val activity get() = requireActivity() as BaseActivity<*, *> protected val activity get() = requireActivity() as BaseUIActivity<*, *>
protected lateinit var binding: Binding protected lateinit var binding: Binding
protected abstract val layoutRes: Int protected abstract val layoutRes: Int
protected abstract val viewModel: ViewModel protected abstract val viewModel: ViewModel
@ -31,7 +31,7 @@ abstract class BaseFragment<ViewModel : BaseViewModel, Binding : ViewDataBinding
): View? { ): View? {
binding = DataBindingUtil.inflate<Binding>(inflater, layoutRes, container, false).apply { binding = DataBindingUtil.inflate<Binding>(inflater, layoutRes, container, false).apply {
setVariable(BR.viewModel, viewModel) setVariable(BR.viewModel, viewModel)
lifecycleOwner = this@BaseFragment lifecycleOwner = this@BaseUIFragment
} }
return binding.root return binding.root

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.base package com.topjohnwu.magisk.ui.base
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
@ -8,7 +8,8 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.topjohnwu.magisk.BR 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.extensions.doOnSubscribeUi
import com.topjohnwu.magisk.model.events.* import com.topjohnwu.magisk.model.events.*
import com.topjohnwu.magisk.model.observer.Observer import com.topjohnwu.magisk.model.observer.Observer
@ -79,7 +80,7 @@ abstract class BaseViewModel(
super.onCleared() super.onCleared()
} }
fun withView(action: BaseActivity<*, *>.() -> Unit) { fun withView(action: BaseActivity.() -> Unit) {
ViewActionEvent(action).publish() ViewActionEvent(action).publish()
} }

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.ui.compat package com.topjohnwu.magisk.ui.base
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
@ -10,8 +10,6 @@ import androidx.core.content.getSystemService
import androidx.databinding.OnRebindCallback import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment 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.snackbar
import com.topjohnwu.magisk.extensions.startAnimations import com.topjohnwu.magisk.extensions.startAnimations
import com.topjohnwu.magisk.model.events.SnackbarEvent 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 com.topjohnwu.magisk.ui.theme.Theme
import kotlin.reflect.KClass import kotlin.reflect.KClass
// TODO (diareuse): Merge into BaseUIActivity after all legacy UI is migrated
abstract class CompatActivity<ViewModel : BaseViewModel, Binding : ViewDataBinding> : 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 themeRes = Theme.selected.themeRes
override val viewRoot: View get() = binding.root override val viewRoot: View get() = binding.root

View File

@ -1,11 +1,10 @@
package com.topjohnwu.magisk.ui.compat package com.topjohnwu.magisk.ui.base
import android.view.View import android.view.View
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.topjohnwu.magisk.base.BaseActivity
import com.topjohnwu.magisk.model.events.ActivityExecutor import com.topjohnwu.magisk.model.events.ActivityExecutor
import com.topjohnwu.magisk.model.events.ContextExecutor import com.topjohnwu.magisk.model.events.ContextExecutor
import com.topjohnwu.magisk.model.events.FragmentExecutor import com.topjohnwu.magisk.model.events.FragmentExecutor
@ -26,7 +25,7 @@ class CompatDelegate internal constructor(
view.viewModel.requestRefresh() view.viewModel.requestRefresh()
} }
fun onEventExecute(event: ViewEvent, activity: BaseActivity<*, *>) { fun onEventExecute(event: ViewEvent, activity: BaseUIActivity<*, *>) {
(event as? ContextExecutor)?.invoke(activity) (event as? ContextExecutor)?.invoke(activity)
(event as? ActivityExecutor)?.invoke(activity) (event as? ActivityExecutor)?.invoke(activity)
(event as? FragmentExecutor)?.let { (event as? FragmentExecutor)?.let {
@ -37,7 +36,7 @@ class CompatDelegate internal constructor(
fun onEventExecute(event: ViewEvent, fragment: Fragment) { fun onEventExecute(event: ViewEvent, fragment: Fragment) {
(event as? ContextExecutor)?.invoke(fragment.requireContext()) (event as? ContextExecutor)?.invoke(fragment.requireContext())
(event as? FragmentExecutor)?.invoke(fragment) (event as? FragmentExecutor)?.invoke(fragment)
(event as? ActivityExecutor)?.invoke(fragment.requireActivity() as BaseActivity<*, *>) (event as? ActivityExecutor)?.invoke(fragment.requireActivity() as BaseUIActivity<*, *>)
} }
private fun ensureInsets() { private fun ensureInsets() {

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.ui.compat package com.topjohnwu.magisk.ui.base
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
@ -6,13 +6,13 @@ import android.view.ViewGroup
import androidx.databinding.OnRebindCallback import androidx.databinding.OnRebindCallback
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment 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.extensions.startAnimations
import com.topjohnwu.magisk.model.events.ViewEvent 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> 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 viewRoot: View get() = binding.root
override val navigation by lazy { compatActivity.navigation } override val navigation by lazy { compatActivity.navigation }

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.ui.compat package com.topjohnwu.magisk.ui.base
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import com.topjohnwu.magisk.databinding.ComparableRvItem import com.topjohnwu.magisk.databinding.ComparableRvItem

View File

@ -1,4 +1,4 @@
package com.topjohnwu.magisk.ui.compat package com.topjohnwu.magisk.ui.base
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle

Some files were not shown because too many files have changed in this diff Show More