From 60e1e07e873d7b72aa3b6f80a0c8f65dad588699 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 13 Sep 2020 00:23:23 -0700 Subject: [PATCH] Proper SafetyNet UI databinding --- .../magisk/databinding/DataBindingAdapters.kt | 13 +++++- .../topjohnwu/magisk/di/ViewModelsModule.kt | 3 +- .../magisk/ui/safetynet/SafetynetFragment.kt | 5 ++- .../magisk/ui/safetynet/SafetynetViewModel.kt | 43 +++++++++++-------- .../res/layout/fragment_safetynet_md2.xml | 9 +++- 5 files changed, 51 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt b/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt index 84a7de70d..e6301a0cf 100644 --- a/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt +++ b/app/src/main/java/com/topjohnwu/magisk/databinding/DataBindingAdapters.kt @@ -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)) +} diff --git a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt index 2c364d71d..2e3537f3c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt @@ -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() } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetFragment.kt index 033da6ef0..10ffd746c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetFragment.kt @@ -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() { override val layoutRes = R.layout.fragment_safetynet_md2 - override val viewModel by viewModel() + override val viewModel by viewModel() { + parametersOf(activity) + } override fun onStart() { super.onStart() diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt index b3abea3ba..a3e77fe56 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/safetynet/SafetynetViewModel.kt @@ -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" diff --git a/app/src/main/res/layout/fragment_safetynet_md2.xml b/app/src/main/res/layout/fragment_safetynet_md2.xml index 238a4ca27..438dd2dc1 100644 --- a/app/src/main/res/layout/fragment_safetynet_md2.xml +++ b/app/src/main/res/layout/fragment_safetynet_md2.xml @@ -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" />