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