Proper SafetyNet UI databinding
This commit is contained in:
parent
e51a3dacb9
commit
60e1e07e87
@ -1,19 +1,23 @@
|
|||||||
package com.topjohnwu.magisk.databinding
|
package com.topjohnwu.magisk.databinding
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.Paint
|
import android.graphics.Paint
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.ContextThemeWrapper
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.annotation.DrawableRes
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.cardview.widget.CardView
|
import androidx.cardview.widget.CardView
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.core.widget.ImageViewCompat
|
||||||
import androidx.databinding.BindingAdapter
|
import androidx.databinding.BindingAdapter
|
||||||
import androidx.databinding.InverseBindingAdapter
|
import androidx.databinding.InverseBindingAdapter
|
||||||
import androidx.databinding.InverseBindingListener
|
import androidx.databinding.InverseBindingListener
|
||||||
@ -288,3 +292,8 @@ fun CardView.setCardBackgroundColorAttr(attr: Int) {
|
|||||||
context.theme.resolveAttribute(attr, tv, true)
|
context.theme.resolveAttribute(attr, tv, true)
|
||||||
setCardBackgroundColor(tv.data)
|
setCardBackgroundColor(tv.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("tint")
|
||||||
|
fun ImageView.setTint(color: Int) {
|
||||||
|
ImageViewCompat.setImageTintList(this, ColorStateList.valueOf(color))
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.topjohnwu.magisk.di
|
package com.topjohnwu.magisk.di
|
||||||
|
|
||||||
|
import android.view.ContextThemeWrapper
|
||||||
import com.topjohnwu.magisk.ui.MainViewModel
|
import com.topjohnwu.magisk.ui.MainViewModel
|
||||||
import com.topjohnwu.magisk.ui.flash.FlashFragmentArgs
|
import com.topjohnwu.magisk.ui.flash.FlashFragmentArgs
|
||||||
import com.topjohnwu.magisk.ui.flash.FlashViewModel
|
import com.topjohnwu.magisk.ui.flash.FlashViewModel
|
||||||
@ -21,7 +22,7 @@ val viewModelModules = module {
|
|||||||
viewModel { HomeViewModel(get()) }
|
viewModel { HomeViewModel(get()) }
|
||||||
viewModel { LogViewModel(get()) }
|
viewModel { LogViewModel(get()) }
|
||||||
viewModel { ModuleViewModel(get(), get(), get()) }
|
viewModel { ModuleViewModel(get(), get(), get()) }
|
||||||
viewModel { SafetynetViewModel() }
|
viewModel { (context: ContextThemeWrapper) -> SafetynetViewModel(context) }
|
||||||
viewModel { SettingsViewModel(get()) }
|
viewModel { SettingsViewModel(get()) }
|
||||||
viewModel { SuperuserViewModel(get(), get()) }
|
viewModel { SuperuserViewModel(get(), get()) }
|
||||||
viewModel { ThemeViewModel() }
|
viewModel { ThemeViewModel() }
|
||||||
|
@ -8,11 +8,14 @@ import com.topjohnwu.magisk.R
|
|||||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||||
import com.topjohnwu.magisk.databinding.FragmentSafetynetMd2Binding
|
import com.topjohnwu.magisk.databinding.FragmentSafetynetMd2Binding
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
import org.koin.core.parameter.parametersOf
|
||||||
|
|
||||||
class SafetynetFragment : BaseUIFragment<SafetynetViewModel, FragmentSafetynetMd2Binding>() {
|
class SafetynetFragment : BaseUIFragment<SafetynetViewModel, FragmentSafetynetMd2Binding>() {
|
||||||
|
|
||||||
override val layoutRes = R.layout.fragment_safetynet_md2
|
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() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
package com.topjohnwu.magisk.ui.safetynet
|
package com.topjohnwu.magisk.ui.safetynet
|
||||||
|
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.ContextThemeWrapper
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
import com.topjohnwu.magisk.ui.safetynet.SafetyNetState.*
|
|
||||||
import com.topjohnwu.magisk.utils.set
|
import com.topjohnwu.magisk.utils.set
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
enum class SafetyNetState {
|
|
||||||
LOADING, PASS, FAILED
|
|
||||||
}
|
|
||||||
|
|
||||||
data class SafetyNetResult(
|
data class SafetyNetResult(
|
||||||
val response: JSONObject? = null,
|
val response: JSONObject? = null,
|
||||||
val dismiss: Boolean = false
|
val dismiss: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
class SafetynetViewModel : BaseViewModel() {
|
class SafetynetViewModel(context: ContextThemeWrapper) : BaseViewModel() {
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
var safetyNetTitle = R.string.empty
|
var safetyNetTitle = R.string.empty
|
||||||
@ -36,23 +33,33 @@ class SafetynetViewModel : BaseViewModel() {
|
|||||||
set(value) = set(value, field, { field = it }, BR.evalType)
|
set(value) = set(value, field, { field = it }, BR.evalType)
|
||||||
|
|
||||||
@get:Bindable
|
@get:Bindable
|
||||||
val isChecking get() = currentState == LOADING
|
var isChecking = false
|
||||||
@get:Bindable
|
set(value) = set(value, field, { field = it }, BR.checking)
|
||||||
val isFailed get() = currentState == FAILED
|
|
||||||
@get:Bindable
|
|
||||||
val isSuccess get() = currentState == PASS
|
|
||||||
|
|
||||||
private var currentState = LOADING
|
@get:Bindable
|
||||||
set(value) = set(value, field, { field = it }, BR.checking, BR.failed, BR.success)
|
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 {
|
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 {
|
cachedResult?.also {
|
||||||
resolveResponse(SafetyNetResult(it))
|
resolveResponse(SafetyNetResult(it))
|
||||||
} ?: attest()
|
} ?: attest()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun attest() {
|
private fun attest() {
|
||||||
currentState = LOADING
|
isChecking = true
|
||||||
CheckSafetyNetEvent {
|
CheckSafetyNetEvent {
|
||||||
resolveResponse(it)
|
resolveResponse(it)
|
||||||
}.publish()
|
}.publish()
|
||||||
@ -61,6 +68,8 @@ class SafetynetViewModel : BaseViewModel() {
|
|||||||
fun reset() = attest()
|
fun reset() = attest()
|
||||||
|
|
||||||
private fun resolveResponse(response: SafetyNetResult) {
|
private fun resolveResponse(response: SafetyNetResult) {
|
||||||
|
isChecking = false
|
||||||
|
|
||||||
if (response.dismiss) {
|
if (response.dismiss) {
|
||||||
back()
|
back()
|
||||||
return
|
return
|
||||||
@ -76,19 +85,19 @@ class SafetynetViewModel : BaseViewModel() {
|
|||||||
ctsState = cts
|
ctsState = cts
|
||||||
basicIntegrityState = basic
|
basicIntegrityState = basic
|
||||||
evalType = if (eval.contains("HARDWARE")) "HARDWARE" else "BASIC"
|
evalType = if (eval.contains("HARDWARE")) "HARDWARE" else "BASIC"
|
||||||
currentState = if (result) PASS else FAILED
|
isSuccess = result
|
||||||
safetyNetTitle =
|
safetyNetTitle =
|
||||||
if (result) R.string.safetynet_attest_success
|
if (result) R.string.safetynet_attest_success
|
||||||
else R.string.safetynet_attest_failure
|
else R.string.safetynet_attest_failure
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
currentState = FAILED
|
isSuccess = false
|
||||||
ctsState = false
|
ctsState = false
|
||||||
basicIntegrityState = false
|
basicIntegrityState = false
|
||||||
evalType = "N/A"
|
evalType = "N/A"
|
||||||
safetyNetTitle = R.string.safetynet_res_invalid
|
safetyNetTitle = R.string.safetynet_res_invalid
|
||||||
}
|
}
|
||||||
} ?: {
|
} ?: {
|
||||||
currentState = FAILED
|
isSuccess = false
|
||||||
ctsState = false
|
ctsState = false
|
||||||
basicIntegrityState = false
|
basicIntegrityState = false
|
||||||
evalType = "N/A"
|
evalType = "N/A"
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@{viewModel.safetyNetTitle}"
|
android:text="@{viewModel.safetyNetTitle}"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Display.OnPrimary"
|
android:textAppearance="@style/AppearanceFoundation.Display.OnPrimary"
|
||||||
|
android:textColor="@{viewModel.textColor}"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
@ -93,7 +94,7 @@
|
|||||||
android:layout_height="4dp"
|
android:layout_height="4dp"
|
||||||
android:layout_marginTop="@dimen/l2"
|
android:layout_marginTop="@dimen/l2"
|
||||||
app:srcCompat="@drawable/bg_divider_rounded_on_primary"
|
app:srcCompat="@drawable/bg_divider_rounded_on_primary"
|
||||||
app:tint="?colorOnPrimary"
|
app:tint="@{viewModel.textColor}"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/safetynet_title" />
|
app:layout_constraintTop_toBottomOf="@+id/safetynet_title" />
|
||||||
@ -116,6 +117,7 @@
|
|||||||
android:text="basicIntegrity"
|
android:text="basicIntegrity"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:textColor="@{viewModel.textColor}"
|
||||||
android:layout_marginTop="@dimen/l2"
|
android:layout_marginTop="@dimen/l2"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="@id/snet_barrier"
|
app:layout_constraintEnd_toEndOf="@id/snet_barrier"
|
||||||
@ -131,6 +133,7 @@
|
|||||||
android:text="ctsProfile"
|
android:text="ctsProfile"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:textColor="@{viewModel.textColor}"
|
||||||
android:layout_marginTop="@dimen/l2"
|
android:layout_marginTop="@dimen/l2"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="@id/snet_barrier"
|
app:layout_constraintEnd_toEndOf="@id/snet_barrier"
|
||||||
@ -149,6 +152,7 @@
|
|||||||
isSelected="@{viewModel.basicIntegrityState}"
|
isSelected="@{viewModel.basicIntegrityState}"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
app:srcCompat="@drawable/ic_check_circle_md2"
|
app:srcCompat="@drawable/ic_check_circle_md2"
|
||||||
|
app:tint="@{viewModel.textColor}"
|
||||||
app:layout_constraintStart_toEndOf="@id/snet_barrier"
|
app:layout_constraintStart_toEndOf="@id/snet_barrier"
|
||||||
app:layout_constraintTop_toTopOf="@id/basic_text"
|
app:layout_constraintTop_toTopOf="@id/basic_text"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/basic_text"/>
|
app:layout_constraintBottom_toBottomOf="@id/basic_text"/>
|
||||||
@ -158,6 +162,7 @@
|
|||||||
isSelected="@{viewModel.ctsState}"
|
isSelected="@{viewModel.ctsState}"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
app:srcCompat="@drawable/ic_check_circle_md2"
|
app:srcCompat="@drawable/ic_check_circle_md2"
|
||||||
|
app:tint="@{viewModel.textColor}"
|
||||||
app:layout_constraintStart_toEndOf="@id/snet_barrier"
|
app:layout_constraintStart_toEndOf="@id/snet_barrier"
|
||||||
app:layout_constraintTop_toTopOf="@id/cts_text"
|
app:layout_constraintTop_toTopOf="@id/cts_text"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/cts_text"/>
|
app:layout_constraintBottom_toBottomOf="@id/cts_text"/>
|
||||||
@ -181,6 +186,7 @@
|
|||||||
android:text="evalType"
|
android:text="evalType"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:textColor="@{viewModel.textColor}"
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -189,6 +195,7 @@
|
|||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
android:textAppearance="@style/AppearanceFoundation.Body.OnPrimary"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
android:textColor="@{viewModel.textColor}"
|
||||||
android:layout_marginStart="@dimen/l1"
|
android:layout_marginStart="@dimen/l1"
|
||||||
android:text="@{viewModel.evalType}"
|
android:text="@{viewModel.evalType}"
|
||||||
tools:text="HARDWARE"/>
|
tools:text="HARDWARE"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user