Add feature to create launch shortcuts

This commit is contained in:
topjohnwu
2020-08-21 03:36:12 -07:00
parent f200d472ef
commit 4b238a9cd0
11 changed files with 109 additions and 51 deletions

View File

@@ -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",

View File

@@ -83,6 +83,7 @@ object Const {
}
object Nav {
const val HOME = "home"
const val SETTINGS = "settings"
const val HIDE = "hide"
const val MODULES = "modules"

View File

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

View File

@@ -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>()

View File

@@ -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)
}
}

View File

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

View File

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

View File

@@ -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()
}

View File

@@ -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()
)