mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-23 18:15:30 +00:00
Migrate to SplashScreen API
This commit is contained in:
parent
81f57949ed
commit
022c217cfe
@ -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")
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
tools:ignore="UnusedAttribute,GoogleAppIndexingWarning">
|
||||
|
||||
<activity
|
||||
android:name=".core.SplashActivity"
|
||||
android:name=".ui.MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
@ -26,10 +26,6 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.MainActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.surequest.SuRequestActivity"
|
||||
android:directBootAware="true"
|
||||
|
130
app/src/main/java/com/topjohnwu/magisk/arch/BaseMainActivity.kt
Normal file
130
app/src/main/java/com/topjohnwu/magisk/arch/BaseMainActivity.kt
Normal file
@ -0,0 +1,130 @@
|
||||
package com.topjohnwu.magisk.arch
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
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.R
|
||||
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.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
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
|
||||
|
||||
abstract class BaseMainActivity<VM : BaseViewModel, Binding : ViewDataBinding>
|
||||
: BaseUIActivity<VM, Binding>() {
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
@ -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<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
BaseActivity(), BaseUIComponent<VM> {
|
||||
|
||||
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<VM : BaseViewModel, Binding : ViewDataBinding> :
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
layoutInflater.factory2 = LayoutInflaterFactory(delegate)
|
||||
|
||||
setTheme(themeRes)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
startObserveEvents()
|
||||
|
@ -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<MainActivity>())
|
||||
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
|
||||
}
|
||||
}
|
@ -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<MainViewModel, ActivityMainMd2Binding>() {
|
||||
class MainActivity : BaseMainActivity<MainViewModel, ActivityMainMd2Binding>() {
|
||||
|
||||
override val layoutRes = R.layout.activity_main_md2
|
||||
override val viewModel by viewModel<MainViewModel>()
|
||||
@ -39,16 +39,7 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
|
||||
private var isRootFragment = true
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// Make sure Splash is always ran before us
|
||||
if (!SplashActivity.DONE) {
|
||||
redirect<SplashActivity>().also { startActivity(it) }
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
override fun showMainUI(savedInstanceState: Bundle?) {
|
||||
setContentView()
|
||||
showUnsupportedMessage()
|
||||
askForHomeShortcut()
|
||||
@ -83,9 +74,16 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
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<MainViewModel, ActivityMainMd2Binding>(
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -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<SuRequestViewModel, ActivityRequestBinding>() {
|
||||
|
||||
@ -33,6 +34,7 @@ open class SuRequestActivity : BaseUIActivity<SuRequestViewModel, ActivityReques
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
window.setHideOverlayWindows(true)
|
||||
}
|
||||
setTheme(Theme.selected.themeRes)
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
fun showRequest() {
|
||||
|
@ -1,8 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="SplashTheme" parent="Theme.Splash" />
|
||||
|
||||
<style name="Foundation" parent="Theme.Foundation" />
|
||||
|
||||
</resources>
|
||||
|
@ -8,10 +8,9 @@
|
||||
|
||||
<style name="Theme.Foundation.Light" parent="Base.V23.Theme.Foundation.Light" />
|
||||
|
||||
<style name="Base.V23.Theme.Splash.Light" parent="Base.V21.Theme.Splash.Light">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<style name="Theme.Splash" parent="Theme.SplashScreen">
|
||||
<item name="windowSplashScreenBackground">@color/splash_background</item>
|
||||
<item name="windowSplashScreenAnimatedIcon">@drawable/ic_magisk_padded</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Splash.Light" parent="Base.V23.Theme.Splash.Light" />
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
@ -15,10 +15,4 @@
|
||||
|
||||
<style name="Theme.Foundation" parent="Base.V27.Theme.Foundation" />
|
||||
|
||||
<style name="Base.V27.Theme.Splash.Light" parent="Base.V23.Theme.Splash.Light">
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Splash.Light" parent="Base.V27.Theme.Splash.Light" />
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
10
app/src/main/res/values-v31/themes.xml
Normal file
10
app/src/main/res/values-v31/themes.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?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>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="SplashTheme" parent="Theme.Splash.Light" />
|
||||
<style name="SplashTheme" parent="Theme.Splash" />
|
||||
|
||||
<style name="Foundation" parent="Theme.Foundation.Light" />
|
||||
|
||||
|
@ -21,30 +21,10 @@
|
||||
|
||||
<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: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="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">
|
||||
<item name="android:windowMinWidthMajor">@dimen/abc_dialog_min_width_major</item>
|
||||
<item name="android:windowMinWidthMinor">@dimen/abc_dialog_min_width_minor</item>
|
||||
|
@ -137,7 +137,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|
||||
))
|
||||
|
||||
cmpList.add(Component(
|
||||
"com.topjohnwu.magisk.core.SplashActivity",
|
||||
"com.topjohnwu.magisk.ui.MainActivity",
|
||||
"DownloadActivity",
|
||||
"""
|
||||
|<activity
|
||||
@ -150,15 +150,6 @@ fun genStubManifest(srcDir: File, outDir: File): String {
|
||||
|</activity>""".ind(2)
|
||||
))
|
||||
|
||||
cmpList.add(Component(
|
||||
"com.topjohnwu.magisk.ui.MainActivity",
|
||||
"",
|
||||
"""
|
||||
|<activity
|
||||
| android:name="%s"
|
||||
| android:exported="false" />""".ind(2)
|
||||
))
|
||||
|
||||
cmpList.add(Component(
|
||||
"com.topjohnwu.magisk.ui.surequest.SuRequestActivity",
|
||||
"",
|
||||
|
Loading…
Reference in New Issue
Block a user