mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-07-28 15:33:36 +00:00
app: support config restrict policy
This commit is contained in:
parent
ff18cb8e70
commit
e5d36d1d24
@ -24,6 +24,7 @@ import androidx.core.widget.ImageViewCompat
|
||||
import androidx.databinding.BindingAdapter
|
||||
import androidx.databinding.InverseBindingAdapter
|
||||
import androidx.databinding.InverseBindingListener
|
||||
import androidx.databinding.InverseMethod
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
@ -33,9 +34,11 @@ import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.di.ServiceLocator
|
||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||
import com.topjohnwu.magisk.utils.TextHolder
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import com.topjohnwu.widget.IndeterminateCheckBox
|
||||
@ -306,3 +309,38 @@ fun TextView.setText(text: TextHolder) {
|
||||
fun Spinner.setAdapter(items: Array<Any>, layoutRes: Int) {
|
||||
adapter = ArrayAdapter(context, layoutRes, items)
|
||||
}
|
||||
|
||||
@BindingAdapter("labelFormatter")
|
||||
fun Slider.setLabelFormatter(formatter: (Float) -> Int) {
|
||||
setLabelFormatter { value -> resources.getString(formatter(value)) }
|
||||
}
|
||||
|
||||
@InverseBindingAdapter(attribute = "android:value")
|
||||
fun Slider.getValueBinding() = value
|
||||
|
||||
@BindingAdapter("android:valueAttrChanged")
|
||||
fun Slider.setListener(attrChange: InverseBindingListener) {
|
||||
addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
|
||||
override fun onStartTrackingTouch(slider: Slider) = Unit
|
||||
override fun onStopTrackingTouch(slider: Slider) = attrChange.onChange()
|
||||
})
|
||||
}
|
||||
|
||||
@InverseMethod("sliderValueToPolicy")
|
||||
fun policyToSliderValue(policy: Int): Float {
|
||||
return when (policy) {
|
||||
SuPolicy.DENY -> 1f
|
||||
SuPolicy.RESTRICT -> 2f
|
||||
SuPolicy.ALLOW -> 3f
|
||||
else -> 1f
|
||||
}
|
||||
}
|
||||
|
||||
fun sliderValueToPolicy(value: Float): Int {
|
||||
return when (value) {
|
||||
1f -> SuPolicy.DENY
|
||||
2f -> SuPolicy.RESTRICT
|
||||
3f -> SuPolicy.ALLOW
|
||||
else -> SuPolicy.DENY
|
||||
}
|
||||
}
|
||||
|
@ -322,6 +322,12 @@ object Reauthenticate : BaseSettingsItem.Toggle() {
|
||||
override var value by Config::suReAuth
|
||||
|
||||
override fun refresh() {
|
||||
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && Info.showSuperUser
|
||||
isEnabled = Build.VERSION.SDK_INT < Build.VERSION_CODES.O
|
||||
}
|
||||
}
|
||||
|
||||
object Restrict : BaseSettingsItem.Toggle() {
|
||||
override val title = CoreR.string.settings_su_restrict_title.asText()
|
||||
override val description = CoreR.string.settings_su_restrict_summary.asText()
|
||||
override var value by Config::suRestrict
|
||||
}
|
||||
|
@ -83,6 +83,9 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Handler {
|
||||
// Can hide overlay windows on 12.0+
|
||||
list.remove(Tapjack)
|
||||
}
|
||||
if (Const.Version.isCanary()) {
|
||||
list.add(Restrict)
|
||||
}
|
||||
}
|
||||
|
||||
return list
|
||||
|
@ -4,11 +4,13 @@ import android.graphics.drawable.Drawable
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.model.su.SuPolicy
|
||||
import com.topjohnwu.magisk.databinding.DiffItem
|
||||
import com.topjohnwu.magisk.databinding.ItemWrapper
|
||||
import com.topjohnwu.magisk.databinding.ObservableRvItem
|
||||
import com.topjohnwu.magisk.databinding.set
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class PolicyRvItem(
|
||||
private val viewModel: SuperuserViewModel,
|
||||
@ -33,14 +35,34 @@ class PolicyRvItem(
|
||||
var isExpanded = false
|
||||
set(value) = set(value, field, { field = it }, BR.expanded)
|
||||
|
||||
val showSlider = Config.suRestrict || item.policy == SuPolicy.RESTRICT
|
||||
|
||||
@get:Bindable
|
||||
var isEnabled
|
||||
get() = item.policy == SuPolicy.ALLOW
|
||||
get() = item.policy >= SuPolicy.ALLOW
|
||||
set(value) = setImpl(value, isEnabled) {
|
||||
notifyPropertyChanged(BR.enabled)
|
||||
viewModel.togglePolicy(this, value)
|
||||
viewModel.updatePolicy(this, if (it) SuPolicy.ALLOW else SuPolicy.DENY)
|
||||
}
|
||||
|
||||
@get:Bindable
|
||||
var sliderValue
|
||||
get() = item.policy
|
||||
set(value) = setImpl(value, sliderValue) {
|
||||
notifyPropertyChanged(BR.sliderValue)
|
||||
notifyPropertyChanged(BR.enabled)
|
||||
viewModel.updatePolicy(this, it)
|
||||
}
|
||||
|
||||
val sliderValueToPolicyString: (Float) -> Int = { value ->
|
||||
when (value.toInt()) {
|
||||
1 -> CoreR.string.deny
|
||||
2 -> CoreR.string.restrict
|
||||
3 -> CoreR.string.grant
|
||||
else -> CoreR.string.deny
|
||||
}
|
||||
}
|
||||
|
||||
@get:Bindable
|
||||
var shouldNotify
|
||||
get() = item.notification
|
||||
|
@ -156,15 +156,16 @@ class SuperuserViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun togglePolicy(item: PolicyRvItem, enable: Boolean) {
|
||||
fun updatePolicy(item: PolicyRvItem, policy: Int) {
|
||||
val items = itemsPolicies.filter { it.item.uid == item.item.uid }
|
||||
fun updateState() {
|
||||
viewModelScope.launch {
|
||||
val res = if (enable) R.string.su_snack_grant else R.string.su_snack_deny
|
||||
item.item.policy = if (enable) SuPolicy.ALLOW else SuPolicy.DENY
|
||||
val res = if (policy >= SuPolicy.ALLOW) R.string.su_snack_grant else R.string.su_snack_deny
|
||||
item.item.policy = policy
|
||||
db.update(item.item)
|
||||
items.forEach {
|
||||
it.notifyPropertyChanged(BR.enabled)
|
||||
it.notifyPropertyChanged(BR.sliderValue)
|
||||
}
|
||||
SnackbarEvent(res.asText(item.appName)).publish()
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
<include
|
||||
android:id="@+id/log_track_container"
|
||||
bullet="@{item.log.action == 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
|
||||
bullet="@{item.log.action >= 2 ? R.drawable.ic_check_md2 : R.drawable.ic_close_md2}"
|
||||
isBottom="@{item.isBottom}"
|
||||
isSelected="@{item.log.action != 2}"
|
||||
isTop="@{item.isTop}"
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
<data>
|
||||
|
||||
<import type="com.topjohnwu.magisk.databinding.DataBindingAdaptersKt" />
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="com.topjohnwu.magisk.ui.superuser.PolicyRvItem" />
|
||||
@ -85,16 +87,32 @@
|
||||
app:layout_constraintVertical_bias="0"
|
||||
tools:text="com.topjohnwu.magisk" />
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
<FrameLayout
|
||||
android:id="@+id/policy_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/l1"
|
||||
android:checked="@={item.enabled}"
|
||||
android:nextFocusLeft="@id/policy"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
gone="@{item.showSlider}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="@={item.enabled}" />
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
goneUnless="@{item.showSlider}"
|
||||
labelFormatter="@{item.sliderValueToPolicyString}"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:stepSize="1"
|
||||
android:value="@={DataBindingAdaptersKt.policyToSliderValue(item.sliderValue)}"
|
||||
android:valueFrom="1"
|
||||
android:valueTo="3" />
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
@ -32,6 +32,7 @@ object Config : PreferenceConfig, DBConfig {
|
||||
const val SU_NOTIFICATION = "su_notification"
|
||||
const val SU_REAUTH = "su_reauth"
|
||||
const val SU_TAPJACK = "su_tapjack"
|
||||
const val SU_RESTRICT = "su_restrict"
|
||||
const val CHECK_UPDATES = "check_update"
|
||||
const val RELEASE_CHANNEL = "release_channel"
|
||||
const val CUSTOM_CHANNEL = "custom_channel"
|
||||
@ -147,6 +148,7 @@ object Config : PreferenceConfig, DBConfig {
|
||||
}
|
||||
var suReAuth by preference(Key.SU_REAUTH, false)
|
||||
var suTapjack by preference(Key.SU_TAPJACK, true)
|
||||
var suRestrict by preference(Key.SU_RESTRICT, false)
|
||||
|
||||
private const val SU_FINGERPRINT = "su_fingerprint"
|
||||
private const val UPDATE_CHANNEL = "update_channel"
|
||||
|
@ -70,7 +70,7 @@ object SuCallbackHandler {
|
||||
}.getOrNull() ?: createSuLog(fromUid, toUid, pid, command, policy, target, seContext, gids)
|
||||
|
||||
if (notify)
|
||||
notify(context, log.action == SuPolicy.ALLOW, log.appName)
|
||||
notify(context, log.action >= SuPolicy.ALLOW, log.appName)
|
||||
|
||||
runBlocking { ServiceLocator.logRepo.insert(log) }
|
||||
}
|
||||
@ -86,7 +86,7 @@ object SuCallbackHandler {
|
||||
pm.getPackageInfo(uid, pid)?.applicationInfo?.getLabel(pm)
|
||||
}.getOrNull() ?: "[UID] $uid"
|
||||
|
||||
notify(context, policy == SuPolicy.ALLOW, appName)
|
||||
notify(context, policy >= SuPolicy.ALLOW, appName)
|
||||
}
|
||||
|
||||
private fun notify(context: Context, granted: Boolean, appName: String) {
|
||||
|
@ -82,7 +82,11 @@ class SuRequestHandler(
|
||||
}
|
||||
|
||||
suspend fun respond(action: Int, time: Long) {
|
||||
policy.policy = action
|
||||
if (action == SuPolicy.ALLOW && Config.suRestrict) {
|
||||
policy.policy = SuPolicy.RESTRICT
|
||||
} else {
|
||||
policy.policy = action
|
||||
}
|
||||
if (time >= 0) {
|
||||
policy.remain = TimeUnit.MINUTES.toSeconds(time)
|
||||
} else {
|
||||
|
@ -54,6 +54,7 @@
|
||||
<string name="touch_filtered_warning">由于某个应用遮挡了超级用户请求界面,因此 Magisk 无法验证您的回应</string>
|
||||
<string name="deny">拒绝</string>
|
||||
<string name="prompt">提示</string>
|
||||
<string name="restrict">受限</string>
|
||||
<string name="grant">允许</string>
|
||||
<string name="su_warning">将授予对该设备的最高权限。\n如果不确定,请拒绝!</string>
|
||||
<string name="forever">永久</string>
|
||||
@ -173,6 +174,8 @@
|
||||
<string name="settings_su_auth_title">身份验证</string>
|
||||
<string name="settings_su_auth_summary">对超级用户请求验证身份</string>
|
||||
<string name="settings_su_auth_insecure">设备未配置验证方式</string>
|
||||
<string name="settings_su_restrict_title">限制超级用户权能</string>
|
||||
<string name="settings_su_restrict_summary">默认限制新的超级用户应用。警告,这会破坏大多数应用,不建议启用。</string>
|
||||
<string name="settings_customization">个性化</string>
|
||||
<string name="setting_add_shortcut_summary">在隐藏后难以识别名称和图标的情况下,添加快捷方式到桌面</string>
|
||||
<string name="settings_doh_title">安全 DNS(DoH)</string>
|
||||
|
@ -53,6 +53,7 @@
|
||||
<string name="touch_filtered_warning">Because an app is obscuring a Superuser request, Magisk can\'t verify your response.</string>
|
||||
<string name="deny">Deny</string>
|
||||
<string name="prompt">Prompt</string>
|
||||
<string name="restrict">Restrict</string>
|
||||
<string name="grant">Grant</string>
|
||||
<string name="su_warning">Grants full access to your device.\nDeny if you\'re not sure!</string>
|
||||
<string name="forever">Forever</string>
|
||||
@ -170,6 +171,8 @@
|
||||
<string name="settings_su_auth_title">User authentication</string>
|
||||
<string name="settings_su_auth_summary">Ask for user authentication during Superuser requests</string>
|
||||
<string name="settings_su_auth_insecure">No authentication method is configured on the device</string>
|
||||
<string name="settings_su_restrict_title">Restrict root capabilities</string>
|
||||
<string name="settings_su_restrict_summary">Will restrict new superuser apps by default. Warning, this will break most apps, do not enable it.</string>
|
||||
<string name="settings_customization">Customization</string>
|
||||
<string name="setting_add_shortcut_summary">Add a pretty shortcut to the home screen in case the name and icon are difficult to recognize after hiding the app</string>
|
||||
<string name="settings_doh_title">DNS over HTTPS</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user