Commit 022c217c authored by topjohnwu's avatar topjohnwu

Migrate to SplashScreen API

parent 81f57949
...@@ -129,5 +129,6 @@ dependencies { ...@@ -129,5 +129,6 @@ dependencies {
implementation("androidx.fragment:fragment-ktx:1.3.6") implementation("androidx.fragment:fragment-ktx:1.3.6")
implementation("androidx.transition:transition:1.4.1") implementation("androidx.transition:transition:1.4.1")
implementation("androidx.core:core-ktx:1.7.0") 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") implementation("com.google.android.material:material:1.4.0")
} }
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning"> tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
<activity <activity
android:name=".core.SplashActivity" android:name=".ui.MainActivity"
android:exported="true" android:exported="true"
android:theme="@style/SplashTheme"> android:theme="@style/SplashTheme">
<intent-filter> <intent-filter>
...@@ -26,10 +26,6 @@ ...@@ -26,10 +26,6 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.MainActivity"
android:exported="false" />
<activity <activity
android:name=".ui.surequest.SuRequestActivity" android:name=".ui.surequest.SuRequestActivity"
android:directBootAware="true" android:directBootAware="true"
......
package com.topjohnwu.magisk.core package com.topjohnwu.magisk.arch
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle import android.os.Bundle
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.databinding.ViewDataBinding
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.base.BaseActivity import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.JobService
import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.tasks.HideAPK import com.topjohnwu.magisk.core.tasks.HideAPK
import com.topjohnwu.magisk.di.ServiceLocator import com.topjohnwu.magisk.di.ServiceLocator
import com.topjohnwu.magisk.ui.MainActivity import com.topjohnwu.magisk.ui.theme.Theme
import com.topjohnwu.magisk.view.MagiskDialog import com.topjohnwu.magisk.view.MagiskDialog
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
class SplashActivity : BaseActivity() { abstract class BaseMainActivity<VM : BaseViewModel, Binding : ViewDataBinding>
: BaseUIActivity<VM, Binding>() {
private val latch = CountDownLatch(1) private val latch = CountDownLatch(1)
companion object {
private var doPreload = true
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setTheme(R.style.SplashTheme) 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) super.onCreate(savedInstanceState)
// Pre-initialize root shell
Shell.getShell(null) { initAndStart() }
}
private fun handleRepackage(pkg: String?) { if (!isRunningAsStub) {
if (packageName != APPLICATION_ID) { val splashScreen = installSplashScreen()
runCatching { splashScreen.setKeepVisibleCondition { doPreload }
// 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() 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 { } else {
if (Config.suManager.isNotEmpty()) showMainUI(savedInstanceState)
Config.suManager = ""
pkg ?: return
if (!Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec().isSuccess)
uninstallApp(pkg)
} }
} }
private fun initAndStart() { abstract fun showMainUI(savedInstanceState: Bundle?)
if (isRunningAsStub && !Shell.rootAccess()) {
runOnUiThread { private fun showInvalidStateMessage() {
MagiskDialog(this) runOnUiThread {
.applyTitle(R.string.unsupport_nonroot_stub_title) MagiskDialog(this)
.applyMessage(R.string.unsupport_nonroot_stub_msg) .applyTitle(R.string.unsupport_nonroot_stub_title)
.applyButton(MagiskDialog.ButtonType.POSITIVE) { .applyMessage(R.string.unsupport_nonroot_stub_msg)
titleRes = R.string.install .applyButton(MagiskDialog.ButtonType.POSITIVE) {
onClick { HideAPK.restore(this@SplashActivity) } titleRes = R.string.install
} onClick { HideAPK.restore(this@BaseMainActivity) }
.cancellable(false) }
.reveal() .cancellable(false)
} .reveal()
return
} }
}
private fun preLoad() {
val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG) val prevPkg = intent.getStringExtra(Const.Key.PREV_PKG)
Config.load(prevPkg) Config.load(prevPkg)
...@@ -68,10 +99,22 @@ class SplashActivity : BaseActivity() { ...@@ -68,10 +99,22 @@ class SplashActivity : BaseActivity() {
// Pre-fetch network services // Pre-fetch network services
ServiceLocator.networkService ServiceLocator.networkService
}
DONE = true private fun handleRepackage(pkg: String?) {
startActivity(redirect<MainActivity>()) if (packageName != APPLICATION_ID) {
finish() 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") @Suppress("DEPRECATION")
...@@ -84,8 +127,4 @@ class SplashActivity : BaseActivity() { ...@@ -84,8 +127,4 @@ class SplashActivity : BaseActivity() {
} }
latch.await() latch.await()
} }
companion object {
var DONE = false
}
} }
...@@ -17,14 +17,12 @@ import com.topjohnwu.magisk.BR ...@@ -17,14 +17,12 @@ import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.arch.inflater.LayoutInflaterFactory import com.topjohnwu.magisk.arch.inflater.LayoutInflaterFactory
import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config
import com.topjohnwu.magisk.core.base.BaseActivity import com.topjohnwu.magisk.core.base.BaseActivity
import com.topjohnwu.magisk.ui.theme.Theme
abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> : abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
BaseActivity(), BaseUIComponent<VM> { BaseActivity(), BaseUIComponent<VM> {
protected lateinit var binding: Binding protected lateinit var binding: Binding
protected abstract val layoutRes: Int protected abstract val layoutRes: Int
protected open val themeRes: Int = Theme.selected.themeRes
private val navHostFragment by lazy { private val navHostFragment by lazy {
supportFragmentManager.findFragmentById(navHostId) as? NavHostFragment supportFragmentManager.findFragmentById(navHostId) as? NavHostFragment
...@@ -46,7 +44,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> : ...@@ -46,7 +44,6 @@ abstract class BaseUIActivity<VM : BaseViewModel, Binding : ViewDataBinding> :
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
layoutInflater.factory2 = LayoutInflaterFactory(delegate) layoutInflater.factory2 = LayoutInflaterFactory(delegate)
setTheme(themeRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
startObserveEvents() startObserveEvents()
......
...@@ -16,7 +16,7 @@ import androidx.interpolator.view.animation.LinearOutSlowInInterpolator ...@@ -16,7 +16,7 @@ import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import com.topjohnwu.magisk.MainDirections import com.topjohnwu.magisk.MainDirections
import com.topjohnwu.magisk.R 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.BaseViewModel
import com.topjohnwu.magisk.arch.ReselectionTarget import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.core.* import com.topjohnwu.magisk.core.*
...@@ -31,7 +31,7 @@ import java.io.File ...@@ -31,7 +31,7 @@ import java.io.File
class MainViewModel : BaseViewModel() class MainViewModel : BaseViewModel()
open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>() { class MainActivity : BaseMainActivity<MainViewModel, ActivityMainMd2Binding>() {
override val layoutRes = R.layout.activity_main_md2 override val layoutRes = R.layout.activity_main_md2
override val viewModel by viewModel<MainViewModel>() override val viewModel by viewModel<MainViewModel>()
...@@ -39,16 +39,7 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>( ...@@ -39,16 +39,7 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
private var isRootFragment = true private var isRootFragment = true
override fun onCreate(savedInstanceState: Bundle?) { override fun showMainUI(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Make sure Splash is always ran before us
if (!SplashActivity.DONE) {
redirect<SplashActivity>().also { startActivity(it) }
finish()
return
}
setContentView() setContentView()
showUnsupportedMessage() showUnsupportedMessage()
askForHomeShortcut() askForHomeShortcut()
...@@ -83,9 +74,16 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>( ...@@ -83,9 +74,16 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
binding.mainNavigation.setOnItemReselectedListener { binding.mainNavigation.setOnItemReselectedListener {
(currentFragment as? ReselectionTarget)?.onReselected() (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() getScreen(section)?.navigate()
if (savedInstanceState != null) { if (savedInstanceState != null) {
...@@ -95,13 +93,6 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>( ...@@ -95,13 +93,6 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
} }
} }
override fun onResume() {
super.onResume()
binding.mainNavigation.menu.apply {
findItem(R.id.superuserFragment)?.isEnabled = Utils.showSuperUser()
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
android.R.id.home -> onBackPressed() android.R.id.home -> onBackPressed()
......
...@@ -14,6 +14,7 @@ import com.topjohnwu.magisk.core.su.SuCallbackHandler ...@@ -14,6 +14,7 @@ import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST import com.topjohnwu.magisk.core.su.SuCallbackHandler.REQUEST
import com.topjohnwu.magisk.databinding.ActivityRequestBinding import com.topjohnwu.magisk.databinding.ActivityRequestBinding
import com.topjohnwu.magisk.di.viewModel import com.topjohnwu.magisk.di.viewModel
import com.topjohnwu.magisk.ui.theme.Theme
open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityRequestBinding>() { open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityRequestBinding>() {
...@@ -33,6 +34,7 @@ open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityReques ...@@ -33,6 +34,7 @@ open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityReques
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
window.setHideOverlayWindows(true) window.setHideOverlayWindows(true)
} }
setTheme(Theme.selected.themeRes)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
fun showRequest() { fun showRequest() {
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="SplashTheme" parent="Theme.Splash" />
<style name="Foundation" parent="Theme.Foundation" /> <style name="Foundation" parent="Theme.Foundation" />
</resources> </resources>
...@@ -8,10 +8,9 @@ ...@@ -8,10 +8,9 @@
<style name="Theme.Foundation.Light" parent="Base.V23.Theme.Foundation.Light" /> <style name="Theme.Foundation.Light" parent="Base.V23.Theme.Foundation.Light" />
<style name="Base.V23.Theme.Splash.Light" parent="Base.V21.Theme.Splash.Light"> <style name="Theme.Splash" parent="Theme.SplashScreen">
<item name="android:windowLightStatusBar">false</item> <item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_magisk_padded</item>
</style> </style>
<style name="Theme.Splash.Light" parent="Base.V23.Theme.Splash.Light" /> </resources>
</resources>
\ No newline at end of file
...@@ -15,10 +15,4 @@ ...@@ -15,10 +15,4 @@
<style name="Theme.Foundation" parent="Base.V27.Theme.Foundation" /> <style name="Theme.Foundation" parent="Base.V27.Theme.Foundation" />
<style name="Base.V27.Theme.Splash.Light" parent="Base.V23.Theme.Splash.Light"> </resources>
<item name="android:windowLightNavigationBar">false</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V27.Theme.Splash.Light" />
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- For stub APK, we need to manually handle the SplashScreen -->
<style name="StubSplashTheme" parent="Theme.SplashScreenBase">
<item name="android:enforceStatusBarContrast">false</item>
<item name="android:enforceNavigationBarContrast">false</item>
<item name="windowSplashScreenBackground">@color/splash_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_magisk_padded</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="SplashTheme" parent="Theme.Splash.Light" /> <style name="SplashTheme" parent="Theme.Splash" />
<style name="Foundation" parent="Theme.Foundation.Light" /> <style name="Foundation" parent="Theme.Foundation.Light" />
......
...@@ -21,30 +21,10 @@ ...@@ -21,30 +21,10 @@
<style name="Theme.Foundation" parent="Base.V21.Theme.Foundation" /> <style name="Theme.Foundation" parent="Base.V21.Theme.Foundation" />
<style name="Base.V21.Theme.Splash.Light" parent="Theme.MaterialComponents.Light.NoActionBar"> <style name="Theme.Splash" parent="Theme.SplashScreen">
<item name="android:windowBackground">@drawable/ic_splash_activity</item> <item name="android:windowBackground">@drawable/ic_splash_activity</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style> </style>
<style name="Base.V21.Theme.Splash" parent="Theme.MaterialComponents.NoActionBar">
<item name="android:windowBackground">@drawable/ic_splash_activity</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
<style name="Theme.Splash.Light" parent="Base.V21.Theme.Splash.Light" />
<style name="Theme.Splash" parent="Base.V21.Theme.Splash" />
<style name="Base.V21.ThemeOverlay.Foundation.Dialog" parent="ThemeOverlay.MaterialComponents.Dialog"> <style name="Base.V21.ThemeOverlay.Foundation.Dialog" parent="ThemeOverlay.MaterialComponents.Dialog">
<item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item> <item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item> <item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
......
...@@ -137,7 +137,7 @@ fun genStubManifest(srcDir: File, outDir: File): String { ...@@ -137,7 +137,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
)) ))
cmpList.add(Component( cmpList.add(Component(
"com.topjohnwu.magisk.core.SplashActivity", "com.topjohnwu.magisk.ui.MainActivity",
"DownloadActivity", "DownloadActivity",
""" """
|<activity |<activity
...@@ -150,15 +150,6 @@ fun genStubManifest(srcDir: File, outDir: File): String { ...@@ -150,15 +150,6 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|</activity>""".ind(2) |</activity>""".ind(2)
)) ))
cmpList.add(Component(
"com.topjohnwu.magisk.ui.MainActivity",
"",
"""
|<activity
| android:name="%s"
| android:exported="false" />""".ind(2)
))
cmpList.add(Component( cmpList.add(Component(
"com.topjohnwu.magisk.ui.surequest.SuRequestActivity", "com.topjohnwu.magisk.ui.surequest.SuRequestActivity",
"", "",
......
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