Proper SafetyNet UI databinding

This commit is contained in:
topjohnwu 2020-09-13 00:23:23 -07:00
parent e51a3dacb9
commit 60e1e07e87
5 changed files with 51 additions and 22 deletions

View File

@ -1,19 +1,23 @@
package com.topjohnwu.magisk.databinding
import android.animation.ValueAnimator
import android.content.res.ColorStateList
import android.graphics.Paint
import android.graphics.drawable.Drawable
import android.util.TypedValue
import android.view.ContextThemeWrapper
import android.view.View
import android.view.ViewGroup
import android.widget.*
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.Toolbar
import androidx.cardview.widget.CardView
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.updateLayoutParams
import androidx.core.widget.ImageViewCompat
import androidx.databinding.BindingAdapter
import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener
@ -288,3 +292,8 @@ fun CardView.setCardBackgroundColorAttr(attr: Int) {
context.theme.resolveAttribute(attr, tv, true)
setCardBackgroundColor(tv.data)
}
@BindingAdapter("tint")
fun ImageView.setTint(color: Int) {
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color))
}

View File

@ -1,5 +1,6 @@
package com.topjohnwu.magisk.di
import android.view.ContextThemeWrapper
import com.topjohnwu.magisk.ui.MainViewModel
import com.topjohnwu.magisk.ui.flash.FlashFragmentArgs
import com.topjohnwu.magisk.ui.flash.FlashViewModel
@ -21,7 +22,7 @@ val viewModelModules = module {
viewModel { HomeViewModel(get()) }
viewModel { LogViewModel(get()) }
viewModel { ModuleViewModel(get(), get(), get()) }
viewModel { SafetynetViewModel() }
viewModel { (context: ContextThemeWrapper) -> SafetynetViewModel(context) }
viewModel { SettingsViewModel(get()) }
viewModel { SuperuserViewModel(get(), get()) }
viewModel { ThemeViewModel() }

View File

@ -8,11 +8,14 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.databinding.FragmentSafetynetMd2Binding
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
class SafetynetFragment : BaseUIFragment<SafetynetViewModel, FragmentSafetynetMd2Binding>() {
override val layoutRes = R.layout.fragment_safetynet_md2
override val viewModel by viewModel<SafetynetViewModel>()
override val viewModel by viewModel<SafetynetViewModel>() {
parametersOf(activity)
}
override fun onStart() {
super.onStart()

View File

@ -1,23 +1,20 @@
package com.topjohnwu.magisk.ui.safetynet
import android.util.TypedValue
import android.view.ContextThemeWrapper
import androidx.databinding.Bindable
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseViewModel
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
import com.topjohnwu.magisk.utils.set
import org.json.JSONObject
enum class SafetyNetState {
LOADING, PASS, FAILED
}
data class SafetyNetResult(
val response: JSONObject? = null,
val dismiss: Boolean = false
)
class SafetynetViewModel : BaseViewModel() {
class SafetynetViewModel(context: ContextThemeWrapper) : BaseViewModel() {
@get:Bindable
var safetyNetTitle = R.string.empty
@ -36,23 +33,33 @@ class SafetynetViewModel : BaseViewModel() {
set(value) = set(value, field, { field = it }, BR.evalType)
@get:Bindable
val isChecking get() = currentState == LOADING
@get:Bindable
val isFailed get() = currentState == FAILED
@get:Bindable
val isSuccess get() = currentState == PASS
var isChecking = false
set(value) = set(value, field, { field = it }, BR.checking)
private var currentState = LOADING
set(value) = set(value, field, { field = it }, BR.checking, BR.failed, BR.success)
@get:Bindable
var isSuccess = false
set(value) = set(value, field, { field = it }, BR.success, BR.textColor)
@get:Bindable
val textColor get() = if (isSuccess) colorOnPrimary else colorOnError
private val colorOnPrimary: Int
private val colorOnError: Int
init {
val tv = TypedValue()
context.theme.resolveAttribute(R.attr.colorOnPrimary, tv, true)
colorOnPrimary = tv.data
context.theme.resolveAttribute(R.attr.colorOnError, tv, true)
colorOnError = tv.data
cachedResult?.also {
resolveResponse(SafetyNetResult(it))
} ?: attest()
}
private fun attest() {
currentState = LOADING
isChecking = true
CheckSafetyNetEvent {
resolveResponse(it)
}.publish()
@ -61,6 +68,8 @@ class SafetynetViewModel : BaseViewModel() {
fun reset() = attest()
private fun resolveResponse(response: SafetyNetResult) {
isChecking = false
if (response.dismiss) {
back()
return
@ -76,19 +85,19 @@ class SafetynetViewModel : BaseViewModel() {
ctsState = cts
basicIntegrityState = basic
evalType = if (eval.contains("HARDWARE")) "HARDWARE" else "BASIC"
currentState = if (result) PASS else FAILED
isSuccess = result
safetyNetTitle =
if (result) R.string.safetynet_attest_success
else R.string.safetynet_attest_failure
}.onFailure {
currentState = FAILED
isSuccess = false
ctsState = false
basicIntegrityState = false
evalType = "N/A"
safetyNetTitle = R.string.safetynet_res_invalid
}
} ?: {
currentState = FAILED
isSuccess = false
ctsState = false
basicIntegrityState = false
evalType = "N/A"

View File

@ -80,6 +80,7 @@
android:gravity="center"
android:text="@{viewModel.safetyNetTitle}"
android:textAppearance="@style/AppearanceFoundation.Display.OnPrimary"
android:textColor="@{viewModel.textColor}"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
@ -93,7 +94,7 @@
android:layout_height="4dp"
android:layout_marginTop="@dimen/l2"
app:srcCompat="@drawable/bg_divider_rounded_on_primary"
app:tint="?colorOnPrimary"
app:tint="@{viewModel.textColor}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/safetynet_title" />
@ -116,6 +117,7 @@
android:text="basicIntegrity"
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
android:textStyle="bold"
android:textColor="@{viewModel.textColor}"
android:layout_marginTop="@dimen/l2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="@id/snet_barrier"
@ -131,6 +133,7 @@
android:text="ctsProfile"
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
android:textStyle="bold"
android:textColor="@{viewModel.textColor}"
android:layout_marginTop="@dimen/l2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="@id/snet_barrier"
@ -149,6 +152,7 @@
isSelected="@{viewModel.basicIntegrityState}"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_check_circle_md2"
app:tint="@{viewModel.textColor}"
app:layout_constraintStart_toEndOf="@id/snet_barrier"
app:layout_constraintTop_toTopOf="@id/basic_text"
app:layout_constraintBottom_toBottomOf="@id/basic_text"/>
@ -158,6 +162,7 @@
isSelected="@{viewModel.ctsState}"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_check_circle_md2"
app:tint="@{viewModel.textColor}"
app:layout_constraintStart_toEndOf="@id/snet_barrier"
app:layout_constraintTop_toTopOf="@id/cts_text"
app:layout_constraintBottom_toBottomOf="@id/cts_text"/>
@ -181,6 +186,7 @@
android:text="evalType"
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
android:textStyle="bold"
android:textColor="@{viewModel.textColor}"
tools:ignore="HardcodedText" />
<TextView
@ -189,6 +195,7 @@
android:layout_gravity="center_vertical"
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
android:textStyle="bold"
android:textColor="@{viewModel.textColor}"
android:layout_marginStart="@dimen/l1"
android:text="@{viewModel.evalType}"
tools:text="HARDWARE"/>