Commit 707d7b33 authored by topjohnwu's avatar topjohnwu

Separate core components

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