mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 02:25:28 +00:00
Add feature to create launch shortcuts
This commit is contained in:
parent
f200d472ef
commit
4b238a9cd0
@ -6,6 +6,7 @@
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/ic_launcher"
|
||||
|
@ -55,6 +55,7 @@ object Config : PreferenceModel, DBConfig {
|
||||
const val SAFETY = "safety_notice"
|
||||
const val THEME_ORDINAL = "theme_ordinal"
|
||||
const val BOOT_ID = "boot_id"
|
||||
const val ASKED_HOME = "asked_home"
|
||||
|
||||
// system state
|
||||
const val MAGISKHIDE = "magiskhide"
|
||||
@ -108,6 +109,7 @@ object Config : PreferenceModel, DBConfig {
|
||||
Value.DEFAULT_CHANNEL
|
||||
|
||||
var bootId by preference(Key.BOOT_ID, "")
|
||||
var askedHome by preference(Key.ASKED_HOME, false)
|
||||
|
||||
var downloadPath by preference(Key.DOWNLOAD_PATH, Environment.DIRECTORY_DOWNLOADS)
|
||||
var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE)
|
||||
@ -223,7 +225,9 @@ object Config : PreferenceModel, DBConfig {
|
||||
|
||||
fun export() {
|
||||
// Flush prefs to disk
|
||||
prefs.edit().commit()
|
||||
prefs.edit().apply {
|
||||
remove(Key.ASKED_HOME)
|
||||
}.commit()
|
||||
val context = get<Context>(Protected)
|
||||
val xml = File(
|
||||
"${context.filesDir.parent}/shared_prefs",
|
||||
|
@ -83,6 +83,7 @@ object Const {
|
||||
}
|
||||
|
||||
object Nav {
|
||||
const val HOME = "home"
|
||||
const val SETTINGS = "settings"
|
||||
const val HIDE = "hide"
|
||||
const val MODULES = "modules"
|
||||
|
@ -45,7 +45,7 @@ open class GeneralReceiver : BaseReceiver() {
|
||||
rmPolicy(pkg)
|
||||
Shell.su("magiskhide --rm $pkg").submit()
|
||||
}
|
||||
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context)
|
||||
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context)
|
||||
Const.Key.BROADCAST_MANAGER_UPDATE -> {
|
||||
intent.getParcelableExtra<ManagerJson>(Const.Key.INTENT_SET_APP)?.let {
|
||||
Info.remote = Info.remote.copy(app = it)
|
||||
|
@ -52,7 +52,7 @@ open class SplashActivity : Activity() {
|
||||
handleRepackage()
|
||||
Notifications.setup(this)
|
||||
UpdateCheckService.schedule(this)
|
||||
Shortcuts.setup(this)
|
||||
Shortcuts.setupDynamic(this)
|
||||
|
||||
// Pre-fetch network stuffs
|
||||
get<GithubRawServices>()
|
||||
|
@ -8,6 +8,7 @@ import com.topjohnwu.magisk.arch.*
|
||||
import com.topjohnwu.magisk.core.base.BaseActivity
|
||||
import com.topjohnwu.magisk.core.model.module.Repo
|
||||
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ViewActionEvent(val action: BaseActivity.() -> Unit) : ViewEvent(), ActivityExecutor {
|
||||
@ -82,3 +83,9 @@ class NavigationEvent(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AddHomeIconEvent : ViewEvent(), ContextExecutor {
|
||||
override fun invoke(context: Context) {
|
||||
Shortcuts.addHomeIcon(context)
|
||||
}
|
||||
}
|
||||
|
@ -8,20 +8,19 @@ import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.view.WindowManager
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.navigation.NavDirections
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.MainDirections
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseUIActivity
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.arch.ReselectionTarget
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.SplashActivity
|
||||
import com.topjohnwu.magisk.core.redirect
|
||||
import com.topjohnwu.magisk.core.*
|
||||
import com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
|
||||
import com.topjohnwu.magisk.ktx.startAnimations
|
||||
import com.topjohnwu.magisk.ui.home.HomeFragmentDirections
|
||||
@ -29,6 +28,7 @@ import com.topjohnwu.magisk.utils.HideBottomViewOnScrollBehavior
|
||||
import com.topjohnwu.magisk.utils.HideTopViewOnScrollBehavior
|
||||
import com.topjohnwu.magisk.utils.HideableBehavior
|
||||
import com.topjohnwu.magisk.view.MagiskDialog
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
|
||||
@ -60,14 +60,8 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
return
|
||||
}
|
||||
|
||||
if (Info.env.isUnsupported) {
|
||||
MagiskDialog(this)
|
||||
.applyTitle(R.string.unsupport_magisk_title)
|
||||
.applyMessage(R.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
|
||||
.applyButton(MagiskDialog.ButtonType.POSITIVE) { titleRes = android.R.string.ok }
|
||||
.cancellable(true)
|
||||
.reveal()
|
||||
}
|
||||
showUnsupportedMessage()
|
||||
askForHomeShortcut()
|
||||
|
||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
|
||||
@ -189,6 +183,40 @@ open class MainActivity : BaseUIActivity<MainViewModel, ActivityMainMd2Binding>(
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUnsupportedMessage() {
|
||||
if (Info.env.isUnsupported) {
|
||||
MagiskDialog(this)
|
||||
.applyTitle(R.string.unsupport_magisk_title)
|
||||
.applyMessage(R.string.unsupport_magisk_msg, Const.Version.MIN_VERSION)
|
||||
.applyButton(MagiskDialog.ButtonType.POSITIVE) { titleRes = android.R.string.ok }
|
||||
.cancellable(true)
|
||||
.reveal()
|
||||
}
|
||||
}
|
||||
|
||||
private fun askForHomeShortcut() {
|
||||
// Don't bother if we are not hidden
|
||||
if (packageName == BuildConfig.APPLICATION_ID)
|
||||
return
|
||||
|
||||
if (!Config.askedHome && ShortcutManagerCompat.isRequestPinShortcutSupported(this)) {
|
||||
// Ask and show dialog
|
||||
Config.askedHome = true
|
||||
MagiskDialog(this)
|
||||
.applyTitle(R.string.add_shortcut_title)
|
||||
.applyMessage(R.string.add_shortcut_msg)
|
||||
.applyButton(MagiskDialog.ButtonType.NEGATIVE) {
|
||||
titleRes = R.string.no
|
||||
}.applyButton(MagiskDialog.ButtonType.POSITIVE) {
|
||||
titleRes = R.string.yes
|
||||
onClick {
|
||||
Shortcuts.addHomeIcon(this@MainActivity)
|
||||
}
|
||||
}.cancellable(true)
|
||||
.reveal()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val ACTION_APPLICATION_PREFERENCES get() =
|
||||
if (Build.VERSION.SDK_INT >= 24) Intent.ACTION_APPLICATION_PREFERENCES
|
||||
|
@ -103,9 +103,10 @@ object Restore : BaseSettingsItem.Blank() {
|
||||
override val description = R.string.settings_restore_manager_summary.asTransitive()
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun HideOrRestore() =
|
||||
if (get<Context>().packageName == BuildConfig.APPLICATION_ID) Hide else Restore
|
||||
object AddShortcut : BaseSettingsItem.Blank() {
|
||||
override val title = R.string.add_shortcut_title.asTransitive()
|
||||
override val description = R.string.setting_add_shortcut_summary.asTransitive()
|
||||
}
|
||||
|
||||
object DownloadPath : BaseSettingsItem.Input() {
|
||||
override var value = Config.downloadPath
|
||||
|
@ -1,10 +1,13 @@
|
||||
package com.topjohnwu.magisk.ui.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||
import com.topjohnwu.magisk.arch.adapterOf
|
||||
@ -17,6 +20,7 @@ import com.topjohnwu.magisk.core.download.DownloadService
|
||||
import com.topjohnwu.magisk.core.download.DownloadSubject
|
||||
import com.topjohnwu.magisk.core.utils.PatchAPK
|
||||
import com.topjohnwu.magisk.data.database.RepoDao
|
||||
import com.topjohnwu.magisk.events.AddHomeIconEvent
|
||||
import com.topjohnwu.magisk.events.RecreateEvent
|
||||
import com.topjohnwu.magisk.events.dialog.BiometricDialog
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
@ -39,6 +43,9 @@ class SettingsViewModel(
|
||||
}
|
||||
|
||||
private fun createItems(): List<BaseSettingsItem> {
|
||||
val context = get<Context>()
|
||||
val hidden = context.packageName != BuildConfig.APPLICATION_ID
|
||||
|
||||
// Customization
|
||||
val list = mutableListOf(
|
||||
Customization,
|
||||
@ -49,6 +56,8 @@ class SettingsViewModel(
|
||||
// making theming a pain in the ass. Just forget about it
|
||||
list.remove(Theme)
|
||||
}
|
||||
if (hidden && ShortcutManagerCompat.isRequestPinShortcutSupported(context))
|
||||
list.add(AddShortcut)
|
||||
|
||||
// Manager
|
||||
list.addAll(listOf(
|
||||
@ -58,7 +67,7 @@ class SettingsViewModel(
|
||||
if (Info.env.isActive) {
|
||||
list.add(ClearRepoCache)
|
||||
if (Const.USER_ID == 0 && Info.isConnected.get())
|
||||
list.add(HideOrRestore())
|
||||
list.add(if (hidden) Restore else Hide)
|
||||
}
|
||||
|
||||
// Magisk
|
||||
@ -96,6 +105,7 @@ class SettingsViewModel(
|
||||
is ClearRepoCache -> clearRepoCache()
|
||||
is SystemlessHosts -> createHosts()
|
||||
is Restore -> restoreManager()
|
||||
is AddShortcut -> AddHomeIconEvent().publish()
|
||||
else -> callback()
|
||||
}
|
||||
|
||||
|
@ -4,53 +4,62 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.ShortcutManager
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.graphics.drawable.toAdaptiveIcon
|
||||
import androidx.core.graphics.drawable.toIcon
|
||||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.SplashActivity
|
||||
import com.topjohnwu.magisk.core.intent
|
||||
import com.topjohnwu.magisk.ktx.getBitmap
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
|
||||
object Shortcuts {
|
||||
|
||||
fun setup(context: Context) {
|
||||
fun setupDynamic(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= 25) {
|
||||
val manager = context.getSystemService<ShortcutManager>()
|
||||
manager?.dynamicShortcuts =
|
||||
getShortCuts(context)
|
||||
val manager = context.getSystemService<ShortcutManager>() ?: return
|
||||
manager.dynamicShortcuts = getShortCuts(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun addHomeIcon(context: Context) {
|
||||
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName) ?: return
|
||||
val info = ShortcutInfoCompat.Builder(context, Const.Nav.HOME)
|
||||
.setShortLabel(context.getString(R.string.app_name))
|
||||
.setIntent(intent)
|
||||
.setIcon(context.getIconCompat(R.drawable.ic_launcher))
|
||||
.build()
|
||||
ShortcutManagerCompat.requestPinShortcut(context, info, null)
|
||||
}
|
||||
|
||||
private fun Context.getIconCompat(id: Int): IconCompat {
|
||||
return if (Build.VERSION.SDK_INT >= 26)
|
||||
IconCompat.createWithAdaptiveBitmap(getBitmap(id))
|
||||
else
|
||||
IconCompat.createWithBitmap(getBitmap(id))
|
||||
}
|
||||
|
||||
@RequiresApi(api = 23)
|
||||
private fun Context.getIcon(id: Int) = getIconCompat(id).toIcon(this)
|
||||
|
||||
@RequiresApi(api = 25)
|
||||
private fun getShortCuts(context: Context): List<ShortcutInfo> {
|
||||
val shortCuts = mutableListOf<ShortcutInfo>()
|
||||
val intent = context.intent<SplashActivity>()
|
||||
val intent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
||||
?: return emptyList()
|
||||
|
||||
fun getIcon(id: Int): Icon {
|
||||
return if (Build.VERSION.SDK_INT >= 26)
|
||||
context.getBitmap(id).toAdaptiveIcon()
|
||||
else
|
||||
context.getBitmap(id).toIcon()
|
||||
}
|
||||
val shortCuts = mutableListOf<ShortcutInfo>()
|
||||
|
||||
if (Utils.showSuperUser()) {
|
||||
shortCuts.add(
|
||||
ShortcutInfo.Builder(context, Const.Nav.SUPERUSER)
|
||||
.setShortLabel(context.getString(R.string.superuser))
|
||||
.setIntent(
|
||||
Intent(intent)
|
||||
.putExtra(Const.Key.OPEN_SECTION, Const.Nav.SUPERUSER)
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
Intent(intent).putExtra(Const.Key.OPEN_SECTION, Const.Nav.SUPERUSER)
|
||||
)
|
||||
.setIcon(getIcon(R.drawable.sc_superuser))
|
||||
.setIcon(context.getIcon(R.drawable.sc_superuser))
|
||||
.setRank(0)
|
||||
.build()
|
||||
)
|
||||
@ -60,12 +69,9 @@ object Shortcuts {
|
||||
ShortcutInfo.Builder(context, Const.Nav.HIDE)
|
||||
.setShortLabel(context.getString(R.string.magiskhide))
|
||||
.setIntent(
|
||||
Intent(intent)
|
||||
.putExtra(Const.Key.OPEN_SECTION, Const.Nav.HIDE)
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
Intent(intent).putExtra(Const.Key.OPEN_SECTION, Const.Nav.HIDE)
|
||||
)
|
||||
.setIcon(getIcon(R.drawable.sc_magiskhide))
|
||||
.setIcon(context.getIcon(R.drawable.sc_magiskhide))
|
||||
.setRank(1)
|
||||
.build()
|
||||
)
|
||||
@ -75,12 +81,9 @@ object Shortcuts {
|
||||
ShortcutInfo.Builder(context, Const.Nav.MODULES)
|
||||
.setShortLabel(context.getString(R.string.modules))
|
||||
.setIntent(
|
||||
Intent(intent)
|
||||
.putExtra(Const.Key.OPEN_SECTION, Const.Nav.MODULES)
|
||||
.setAction(Intent.ACTION_VIEW)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
Intent(intent).putExtra(Const.Key.OPEN_SECTION, Const.Nav.MODULES)
|
||||
)
|
||||
.setIcon(getIcon(R.drawable.sc_extension))
|
||||
.setIcon(context.getIcon(R.drawable.sc_extension))
|
||||
.setRank(2)
|
||||
.build()
|
||||
)
|
||||
|
@ -174,6 +174,7 @@
|
||||
<string name="settings_su_biometric_summary">Use biometric authentication to allow superuser requests</string>
|
||||
<string name="no_biometric">Unsupported device or no biometric settings are enabled</string>
|
||||
<string name="settings_customization">Customization</string>
|
||||
<string name="setting_add_shortcut_summary">Add a pretty shortcut in the home screen in case the name and icon are difficult to recognize after hiding the app</string>
|
||||
|
||||
<string name="multiuser_mode">Multiuser Mode</string>
|
||||
<string name="settings_owner_only">Device Owner Only</string>
|
||||
@ -231,5 +232,7 @@
|
||||
<string name="unsupport_magisk_title">Unsupported Magisk Version</string>
|
||||
<string name="unsupport_magisk_msg">This version of Magisk Manager does not support Magisk version lower than %1$s.\n\nThe app will behave as if no Magisk is installed, please upgrade Magisk as soon as possible.</string>
|
||||
<string name="external_rw_permission_denied">Grant storage permission to enable this functionality</string>
|
||||
<string name="add_shortcut_title">Add shortcut to home screen</string>
|
||||
<string name="add_shortcut_msg">After hiding Magisk Manager, its name and icon might become difficult to recognize. Do you want to add a pretty shortcut to the home screen?</string>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user