From 4b238a9cd069c91bb5db4d7c4da6edc8743a7774 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Fri, 21 Aug 2020 03:36:12 -0700 Subject: [PATCH] Add feature to create launch shortcuts --- app/src/main/AndroidManifest.xml | 1 + .../java/com/topjohnwu/magisk/core/Config.kt | 6 +- .../java/com/topjohnwu/magisk/core/Const.kt | 1 + .../topjohnwu/magisk/core/GeneralReceiver.kt | 2 +- .../topjohnwu/magisk/core/SplashActivity.kt | 2 +- .../com/topjohnwu/magisk/events/ViewEvents.kt | 7 ++ .../com/topjohnwu/magisk/ui/MainActivity.kt | 52 ++++++++++---- .../magisk/ui/settings/SettingsItems.kt | 7 +- .../magisk/ui/settings/SettingsViewModel.kt | 12 +++- .../com/topjohnwu/magisk/view/Shortcuts.kt | 67 ++++++++++--------- app/src/main/res/values/strings.xml | 3 + 11 files changed, 109 insertions(+), 51 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b84152fa8..bd2209947 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + (Protected) val xml = File( "${context.filesDir.parent}/shared_prefs", diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Const.kt b/app/src/main/java/com/topjohnwu/magisk/core/Const.kt index ea5df7f6c..d867738b3 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/Const.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/Const.kt @@ -83,6 +83,7 @@ object Const { } object Nav { + const val HOME = "home" const val SETTINGS = "settings" const val HIDE = "hide" const val MODULES = "modules" diff --git a/app/src/main/java/com/topjohnwu/magisk/core/GeneralReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/core/GeneralReceiver.kt index dd81b365c..1d370b8cd 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/GeneralReceiver.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/GeneralReceiver.kt @@ -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(Const.Key.INTENT_SET_APP)?.let { Info.remote = Info.remote.copy(app = it) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt b/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt index 606533c7c..bb48ddc85 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/SplashActivity.kt @@ -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() diff --git a/app/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt b/app/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt index 0751e1de4..69fbad00b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt +++ b/app/src/main/java/com/topjohnwu/magisk/events/ViewEvents.kt @@ -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) + } +} 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 e77464c4f..2f0de7b5d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt @@ -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( 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( } } + 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 diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt index f90be7083..70722047d 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt @@ -103,9 +103,10 @@ object Restore : BaseSettingsItem.Blank() { override val description = R.string.settings_restore_manager_summary.asTransitive() } -@Suppress("FunctionName") -fun HideOrRestore() = - if (get().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 diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt index 9d148ee10..d758ec764 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt @@ -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 { + val context = get() + 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() } diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt index 3d058907f..36aa2892b 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/Shortcuts.kt @@ -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() - manager?.dynamicShortcuts = - getShortCuts(context) + val manager = context.getSystemService() ?: 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 { - val shortCuts = mutableListOf() - val intent = context.intent() + 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() 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() ) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 449e5f309..66deedde5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -174,6 +174,7 @@ Use biometric authentication to allow superuser requests Unsupported device or no biometric settings are enabled Customization + Add a pretty shortcut in the home screen in case the name and icon are difficult to recognize after hiding the app Multiuser Mode Device Owner Only @@ -231,5 +232,7 @@ Unsupported Magisk Version 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. Grant storage permission to enable this functionality + Add shortcut to home screen + 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?