mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-12-31 10:07:17 +00:00
Added safetynet implementation
This commit is contained in:
@@ -1,9 +1,19 @@
|
||||
package com.topjohnwu.magisk.redesign.safetynet
|
||||
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.ViewAnimationUtils
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.databinding.BindingAdapter
|
||||
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.databinding.FragmentSafetynetMd2Binding
|
||||
import com.topjohnwu.magisk.redesign.compat.CompatFragment
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import kotlin.math.hypot
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class SafetynetFragment : CompatFragment<SafetynetViewModel, FragmentSafetynetMd2Binding>() {
|
||||
|
||||
@@ -15,4 +25,34 @@ class SafetynetFragment : CompatFragment<SafetynetViewModel, FragmentSafetynetMd
|
||||
activity.setTitle(R.string.safetyNet)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@BindingAdapter("revealSafetyNet")
|
||||
fun View.revealOnCenter(expand: Boolean) {
|
||||
val anim = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
isInvisible = expand
|
||||
return
|
||||
} else {
|
||||
val x = measuredWidth.toDouble()
|
||||
val y = measuredHeight.toDouble()
|
||||
val maxRadius = hypot(x, y).toFloat()
|
||||
val start = if (expand) 0f else maxRadius
|
||||
val end = if (expand) maxRadius else 0f
|
||||
|
||||
ViewAnimationUtils.createCircularReveal(
|
||||
this,
|
||||
(x / 2).roundToInt(),
|
||||
(y / 2).roundToInt(),
|
||||
start,
|
||||
end
|
||||
).apply {
|
||||
interpolator = FastOutSlowInInterpolator()
|
||||
doOnEnd { if (!expand) isVisible = false }
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
isVisible = true
|
||||
anim.start()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.topjohnwu.magisk.redesign.safetynet
|
||||
|
||||
import androidx.databinding.Bindable
|
||||
import com.topjohnwu.magisk.BR
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.extensions.subscribeK
|
||||
import com.topjohnwu.magisk.model.events.SafetyNetResult
|
||||
@@ -14,44 +16,63 @@ class SafetynetViewModel(
|
||||
rxBus: RxBus
|
||||
) : CompatViewModel() {
|
||||
|
||||
private var currentState = IDLE
|
||||
set(value) {
|
||||
field = value
|
||||
notifyStateChanged()
|
||||
}
|
||||
val safetyNetTitle = KObservableField(R.string.empty)
|
||||
val ctsState = KObservableField(IDLE)
|
||||
val basicIntegrityState = KObservableField(IDLE)
|
||||
val ctsState = KObservableField(false)
|
||||
val basicIntegrityState = KObservableField(false)
|
||||
|
||||
val isChecking @Bindable get() = currentState == LOADING
|
||||
val isFailed @Bindable get() = currentState == FAILED
|
||||
val isSuccess @Bindable get() = currentState == PASS
|
||||
|
||||
init {
|
||||
rxBus.register<SafetyNetResult>()
|
||||
.subscribeK { resolveResponse(it.responseCode) }
|
||||
.add()
|
||||
|
||||
attest()
|
||||
}
|
||||
|
||||
fun attest() = UpdateSafetyNetEvent().publish()
|
||||
override fun notifyStateChanged() {
|
||||
super.notifyStateChanged()
|
||||
notifyPropertyChanged(BR.loading)
|
||||
notifyPropertyChanged(BR.failed)
|
||||
notifyPropertyChanged(BR.success)
|
||||
}
|
||||
|
||||
private fun attest() {
|
||||
currentState = LOADING
|
||||
UpdateSafetyNetEvent().publish()
|
||||
}
|
||||
|
||||
fun reset() = attest()
|
||||
|
||||
private fun resolveResponse(response: Int) = when {
|
||||
//todo animate (reveal) to result (green/error)
|
||||
response and 0x0F == 0 -> {
|
||||
val hasCtsPassed = response and SafetyNetHelper.CTS_PASS != 0
|
||||
val hasBasicIntegrityPassed = response and SafetyNetHelper.BASIC_PASS != 0
|
||||
safetyNetTitle.value = R.string.safetyNet_check_success
|
||||
ctsState.value = if (hasCtsPassed) {
|
||||
PASS
|
||||
} else {
|
||||
FAILED
|
||||
}
|
||||
basicIntegrityState.value = if (hasBasicIntegrityPassed) {
|
||||
PASS
|
||||
} else {
|
||||
FAILED
|
||||
}
|
||||
val result = hasCtsPassed && hasBasicIntegrityPassed
|
||||
ctsState.value = hasCtsPassed
|
||||
basicIntegrityState.value = hasBasicIntegrityPassed
|
||||
currentState = if (result) PASS else FAILED
|
||||
safetyNetTitle.value =
|
||||
if (result) R.string.safetynet_attest_success
|
||||
else R.string.safetynet_attest_failure
|
||||
}
|
||||
//todo animate (collapse) back to initial (fade error)
|
||||
response == -2 -> {
|
||||
ctsState.value = IDLE
|
||||
basicIntegrityState.value = IDLE
|
||||
currentState = FAILED
|
||||
ctsState.value = false
|
||||
basicIntegrityState.value = false
|
||||
back()
|
||||
}
|
||||
//todo animate (collapse) back to initial (surface)
|
||||
else -> {
|
||||
ctsState.value = IDLE
|
||||
basicIntegrityState.value = IDLE
|
||||
currentState = FAILED
|
||||
ctsState.value = false
|
||||
basicIntegrityState.value = false
|
||||
safetyNetTitle.value = when (response) {
|
||||
SafetyNetHelper.RESPONSE_ERR -> R.string.safetyNet_res_invalid
|
||||
else -> R.string.safetyNet_api_error
|
||||
|
||||
Reference in New Issue
Block a user