diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5af4ef80b..5ec133f02 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -129,5 +129,6 @@ dependencies {
implementation("androidx.fragment:fragment-ktx:1.3.6")
implementation("androidx.transition:transition:1.4.1")
implementation("androidx.core:core-ktx:1.7.0")
+ implementation("androidx.core:core-splashscreen:1.0.0-alpha02")
implementation("com.google.android.material:material:1.4.0")
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 70e733f99..df41a7b74 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -13,7 +13,7 @@
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
@@ -26,10 +26,6 @@
-
-
+ : BaseUIActivity() {
+
+ private val latch = CountDownLatch(1)
+
+ companion object {
+ private var doPreload = true
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ setTheme(Theme.selected.themeRes)
+
+ if (isRunningAsStub && doPreload) {
+ // Manually apply splash theme for stub
+ if (SDK_INT >= 31) {
+ theme.applyStyle(R.style.StubSplashTheme, true)
+ } else {
+ theme.applyStyle(R.style.SplashTheme, true)
+ }
+ }
+
+ super.onCreate(savedInstanceState)
+
+ if (!isRunningAsStub) {
+ val splashScreen = installSplashScreen()
+ splashScreen.setKeepVisibleCondition { doPreload }
+ }
+
+ if (doPreload) {
+ // Pre-initialize root shell
+ Shell.getShell(null) {
+ if (isRunningAsStub && !Shell.rootAccess()) {
+ showInvalidStateMessage()
+ return@getShell
+ }
+ preLoad()
+ runOnUiThread {
+ doPreload = false
+ if (isRunningAsStub) {
+ // Re-launch main activity without splash theme
+ recreate()
+ } else {
+ showMainUI(savedInstanceState)
+ }
+ }
+ }
+ } else {
+ showMainUI(savedInstanceState)
+ }
+ }
+
+ abstract fun showMainUI(savedInstanceState: Bundle?)
+
+ private fun showInvalidStateMessage() {
+ runOnUiThread {
+ MagiskDialog(this)
+ .applyTitle(R.string.unsupport_nonroot_stub_title)
+ .applyMessage(R.string.unsupport_nonroot_stub_msg)
+ .applyButton(MagiskDialog.ButtonType.POSITIVE) {
+ titleRes = R.string.install
+ onClick { HideAPK.restore(this@BaseMainActivity) }
+ }
+ .cancellable(false)
+ .reveal()
+ }
+ }
+
+ private fun preLoad() {
+ val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)
+
+ Config.load(prevPkg)
+ handleRepackage(prevPkg)
+ Notifications.setup(this)
+ JobService.schedule(this)
+ Shortcuts.setupDynamic(this)
+
+ // Pre-fetch network services
+ ServiceLocator.networkService
+ }
+
+ private fun handleRepackage(pkg: String?) {
+ if (packageName != APPLICATION_ID) {
+ runCatching {
+ // Hidden, remove com.topjohnwu.magisk if exist as it could be malware
+ packageManager.getApplicationInfo(APPLICATION_ID, 0)
+ Shell.su("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
+ }
+ } else {
+ if (Config.suManager.isNotEmpty())
+ Config.suManager = ""
+ pkg ?: return
+ if (!Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec().isSuccess)
+ uninstallApp(pkg)
+ }
+ }
+
+ @Suppress("DEPRECATION")
+ private fun uninstallApp(pkg: String) {
+ val uri = Uri.Builder().scheme("package").opaquePart(pkg).build()
+ val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, uri)
+ intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
+ startActivityForResult(intent) { _, _ ->
+ latch.countDown()
+ }
+ latch.await()
+ }
+}
diff --git a/app/src/main/java/com/topjohnwu/magisk/arch/BaseUIActivity.kt b/app/src/main/java/com/topjohnwu/magisk/arch/BaseUIActivity.kt
index a3ef51efc..e6dd45824 100644
--- a/app/src/main/java/com/topjohnwu/magisk/arch/BaseUIActivity.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/arch/BaseUIActivity.kt
@@ -17,14 +17,12 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.inflater.LayoutInflaterFactory
import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.base.BaseActivity
-import com.topjohnwu.magisk.ui.theme.Theme
abstract class BaseUIActivity :
BaseActivity(), BaseUIComponent {
protected lateinit var binding: Binding
protected abstract val layoutRes: Int
- protected open val themeRes: Int = Theme.selected.themeRes
private val navHostFragment by lazy {
supportFragmentManager.findFragmentById(navHostId) as? NavHostFragment
@@ -46,7 +44,6 @@ abstract class BaseUIActivity :
override fun onCreate(savedInstanceState: Bundle?) {
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
- setTheme(themeRes)
super.onCreate(savedInstanceState)
startObserveEvents()
diff --git a/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt
deleted file mode 100644
index 666044b24..000000000
--- a/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.topjohnwu.magisk.core
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
-import com.topjohnwu.magisk.R
-import com.topjohnwu.magisk.core.base.BaseActivity
-import com.topjohnwu.magisk.core.tasks.HideAPK
-import com.topjohnwu.magisk.di.ServiceLocator
-import com.topjohnwu.magisk.ui.MainActivity
-import com.topjohnwu.magisk.view.MagiskDialog
-import com.topjohnwu.magisk.view.Notifications
-import com.topjohnwu.magisk.view.Shortcuts
-import com.topjohnwu.superuser.Shell
-import java.util.concurrent.CountDownLatch
-
-class SplashActivity : BaseActivity() {
-
- private val latch = CountDownLatch(1)
-
- override fun onCreate(savedInstanceState: Bundle?) {
- setTheme(R.style.SplashTheme)
- super.onCreate(savedInstanceState)
- // Pre-initialize root shell
- Shell.getShell(null) { initAndStart() }
- }
-
- private fun handleRepackage(pkg: String?) {
- if (packageName != APPLICATION_ID) {
- runCatching {
- // Hidden, remove com.topjohnwu.magisk if exist as it could be malware
- packageManager.getApplicationInfo(APPLICATION_ID, 0)
- Shell.su("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
- }
- } else {
- if (Config.suManager.isNotEmpty())
- Config.suManager = ""
- pkg ?: return
- if (!Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec().isSuccess)
- uninstallApp(pkg)
- }
- }
-
- private fun initAndStart() {
- if (isRunningAsStub && !Shell.rootAccess()) {
- runOnUiThread {
- MagiskDialog(this)
- .applyTitle(R.string.unsupport_nonroot_stub_title)
- .applyMessage(R.string.unsupport_nonroot_stub_msg)
- .applyButton(MagiskDialog.ButtonType.POSITIVE) {
- titleRes = R.string.install
- onClick { HideAPK.restore(this@SplashActivity) }
- }
- .cancellable(false)
- .reveal()
- }
- return
- }
-
- val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)
-
- Config.load(prevPkg)
- handleRepackage(prevPkg)
- Notifications.setup(this)
- JobService.schedule(this)
- Shortcuts.setupDynamic(this)
-
- // Pre-fetch network services
- ServiceLocator.networkService
-
- DONE = true
- startActivity(redirect())
- finish()
- }
-
- @Suppress("DEPRECATION")
- private fun uninstallApp(pkg: String) {
- val uri = Uri.Builder().scheme("package").opaquePart(pkg).build()
- val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, uri)
- intent.putExtra(Intent.EXTRA_RETURN_RESULT, true)
- startActivityForResult(intent) { _, _ ->
- latch.countDown()
- }
- latch.await()
- }
-
- companion object {
- var DONE = false
- }
-}
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
index 582d1ea08..9e30a044c 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
@@ -16,7 +16,7 @@ import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R
-import com.topjohnwu.magisk.arch.BaseUIActivity
+import com.topjohnwu.magisk.arch.BaseMainActivity
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.core.*
@@ -31,7 +31,7 @@ import java.io.File
class MainViewModel : BaseViewModel()
-open class MainActivity : BaseUIActivity() {
+class MainActivity : BaseMainActivity() {
override val layoutRes = R.layout.activity_main_md2
override val viewModel by viewModel()
@@ -39,16 +39,7 @@ open class MainActivity : BaseUIActivity(
private var isRootFragment = true
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- // Make sure Splash is always ran before us
- if (!SplashActivity.DONE) {
- redirect().also { startActivity(it) }
- finish()
- return
- }
-
+ override fun showMainUI(savedInstanceState: Bundle?) {
setContentView()
showUnsupportedMessage()
askForHomeShortcut()
@@ -83,9 +74,16 @@ open class MainActivity : BaseUIActivity(
binding.mainNavigation.setOnItemReselectedListener {
(currentFragment as? ReselectionTarget)?.onReselected()
}
+ binding.mainNavigation.menu.apply {
+ findItem(R.id.superuserFragment)?.isEnabled = Utils.showSuperUser()
+ }
+
+ val section =
+ if (intent.action == Intent.ACTION_APPLICATION_PREFERENCES)
+ Const.Nav.SETTINGS
+ else
+ intent.getStringExtra(Const.Key.OPEN_SECTION)
- val section = if (intent.action == Intent.ACTION_APPLICATION_PREFERENCES) Const.Nav.SETTINGS
- else intent.getStringExtra(Const.Key.OPEN_SECTION)
getScreen(section)?.navigate()
if (savedInstanceState != null) {
@@ -95,13 +93,6 @@ open class MainActivity : BaseUIActivity(
}
}
- override fun onResume() {
- super.onResume()
- binding.mainNavigation.menu.apply {
- findItem(R.id.superuserFragment)?.isEnabled = Utils.showSuperUser()
- }
- }
-
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> onBackPressed()
diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt
index db018c390..b80999531 100644
--- a/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt
+++ b/app/src/main/java/com/topjohnwu/magisk/ui/surequest/SuRequestActivity.kt
@@ -14,6 +14,7 @@ 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.di.viewModel
+import com.topjohnwu.magisk.ui.theme.Theme
open class SuRequestActivity : BaseUIActivity() {
@@ -33,6 +34,7 @@ open class SuRequestActivity : BaseUIActivity= Build.VERSION_CODES.S) {
window.setHideOverlayWindows(true)
}
+ setTheme(Theme.selected.themeRes)
super.onCreate(savedInstanceState)
fun showRequest() {
diff --git a/app/src/main/res/values-night/styles_md2.xml b/app/src/main/res/values-night/styles_md2.xml
index 2c8a3c5c3..691508104 100644
--- a/app/src/main/res/values-night/styles_md2.xml
+++ b/app/src/main/res/values-night/styles_md2.xml
@@ -1,8 +1,6 @@
-
-
diff --git a/app/src/main/res/values-v23/themes.xml b/app/src/main/res/values-v23/themes.xml
index fdd613c98..27b30bfe5 100644
--- a/app/src/main/res/values-v23/themes.xml
+++ b/app/src/main/res/values-v23/themes.xml
@@ -8,10 +8,9 @@
-
-
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-v27/themes.xml b/app/src/main/res/values-v27/themes.xml
index 7a1956c4c..299b28c29 100644
--- a/app/src/main/res/values-v27/themes.xml
+++ b/app/src/main/res/values-v27/themes.xml
@@ -15,10 +15,4 @@
-
-
-
-
-
\ No newline at end of file
+
diff --git a/app/src/main/res/values-v31/themes.xml b/app/src/main/res/values-v31/themes.xml
new file mode 100644
index 000000000..7f70a2f72
--- /dev/null
+++ b/app/src/main/res/values-v31/themes.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
diff --git a/app/src/main/res/values/styles_md2.xml b/app/src/main/res/values/styles_md2.xml
index 95dd8bee8..418879c0f 100644
--- a/app/src/main/res/values/styles_md2.xml
+++ b/app/src/main/res/values/styles_md2.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 29d57a7df..508c5d197 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -21,30 +21,10 @@
-
-
-
-
-
-
-