TunnelEditorFragment: add hooks for biometric auth

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2020-03-29 19:34:27 -06:00
parent 2337fe37be
commit d44a83faaa
5 changed files with 51 additions and 11 deletions

View File

@ -6,6 +6,8 @@ package com.wireguard.android.databinding
import android.text.InputFilter
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import androidx.databinding.BindingAdapter
@ -13,6 +15,7 @@ import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableList
import androidx.databinding.ViewDataBinding
import androidx.databinding.adapters.ListenerUtil
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.wireguard.android.BR
@ -41,10 +44,10 @@ object BindingAdapters {
}
@JvmStatic
@BindingAdapter("items", "layout")
@BindingAdapter("items", "layout", "fragment")
fun <E> setItems(view: LinearLayout,
oldList: ObservableList<E>?, oldLayoutId: Int,
newList: ObservableList<E>?, newLayoutId: Int) {
oldList: ObservableList<E>?, oldLayoutId: Int, @Suppress("UNUSED_PARAMETER") oldFragment: Fragment?,
newList: ObservableList<E>?, newLayoutId: Int, newFragment: Fragment?) {
if (oldList === newList && oldLayoutId == newLayoutId)
return
var listener: ItemChangeListener<E>? = ListenerUtil.getListener(view, R.id.item_change_listener)
@ -59,7 +62,7 @@ object BindingAdapters {
if (newList == null || newLayoutId == 0)
return
if (listener == null) {
listener = ItemChangeListener(view, newLayoutId)
listener = ItemChangeListener(view, newLayoutId, newFragment)
ListenerUtil.trackListener(view, listener, R.id.item_change_listener)
}
// Either the list changed, or this is an entirely new listener because the layout changed.
@ -123,6 +126,13 @@ object BindingAdapters {
view.setOnBeforeCheckedChangeListener(listener)
}
@JvmStatic
@BindingAdapter("onFocusChange")
fun setOnFocusChange(view: EditText,
listener: View.OnFocusChangeListener?) {
view.setOnFocusChangeListener(listener)
}
@JvmStatic
@BindingAdapter("android:text")
fun setText(view: TextView, text: Optional<*>) {

View File

@ -10,13 +10,14 @@ import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableList
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import com.wireguard.android.BR
import java.lang.ref.WeakReference
/**
* Helper class for binding an ObservableList to the children of a ViewGroup.
*/
internal class ItemChangeListener<T>(private val container: ViewGroup, private val layoutId: Int) {
internal class ItemChangeListener<T>(private val container: ViewGroup, private val layoutId: Int, private val fragment: Fragment?) {
private val callback = OnListChangedCallback(this)
private val layoutInflater: LayoutInflater = LayoutInflater.from(container.context)
private var list: ObservableList<T>? = null
@ -29,6 +30,7 @@ internal class ItemChangeListener<T>(private val container: ViewGroup, private v
require(list != null) { "Trying to get a view while list is still null" }
binding!!.setVariable(BR.collection, list)
binding.setVariable(BR.item, list!![position])
binding.setVariable(BR.fragment, fragment)
binding.executePendingBindings()
return binding.root
}

View File

@ -6,6 +6,7 @@ package com.wireguard.android.fragment
import android.content.Context
import android.os.Bundle
import android.text.InputType
import android.util.Log
import android.view.LayoutInflater
import android.view.Menu
@ -15,9 +16,9 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputLayout
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.backend.Tunnel
@ -34,6 +35,7 @@ import com.wireguard.config.Config
* Fragment for editing a WireGuard configuration.
*/
class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
private var haveShownKeys = false
private var binding: TunnelEditorFragmentBinding? = null
private var tunnel: ObservableTunnel? = null
private fun onConfigLoaded(config: Config) {
@ -76,7 +78,6 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
setUpScrollingContent(mainContainer, null)
privateKeyTextLayout.setEndIconOnClickListener { config?.`interface`?.generateKeyPair() }
}
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
return binding?.root
}
@ -226,6 +227,23 @@ class TunnelEditorFragment : BaseFragment(), AppExclusionListener {
super.onViewStateRestored(savedInstanceState)
}
fun onKeyClick(view: View) = onKeyFocusChange(view, true)
fun onKeyFocusChange(view: View, isFocused: Boolean) {
if (!isFocused) return
val edit = view as? EditText ?: return
if (!haveShownKeys && edit.text.isNotEmpty()) {
if (true /* TODO: do biometric auth prompt */) {
haveShownKeys = true
} else {
/* Unauthorized, so return and don't change visibility. */
return
}
}
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
edit.inputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
}
companion object {
private const val KEY_LOCAL_CONFIG = "local_config"
private const val KEY_ORIGINAL_NAME = "original_name"

View File

@ -102,9 +102,11 @@
android:id="@+id/private_key_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textVisiblePassword"
android:inputType="textNoSuggestions|textPassword"
android:onClick="@{fragment::onKeyClick}"
android:text="@={config.interface.privateKey}"
app:filter="@{KeyInputFilter.newInstance()}" />
app:filter="@{KeyInputFilter.newInstance()}"
app:onFocusChange="@{fragment::onKeyFocusChange}" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
@ -234,6 +236,7 @@
android:layout_height="wrap_content"
android:divider="@null"
android:orientation="vertical"
app:fragment="@{fragment}"
app:items="@{config.peers}"
app:layout="@{@layout/tunnel_editor_peer}"
tools:ignore="UselessLeaf" />

View File

@ -15,6 +15,10 @@
<variable
name="item"
type="com.wireguard.android.viewmodel.PeerProxy" />
<variable
name="fragment"
type="com.wireguard.android.fragment.TunnelEditorFragment" />
</data>
<com.google.android.material.card.MaterialCardView
@ -91,8 +95,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_optional"
android:inputType="textNoSuggestions|textVisiblePassword"
android:text="@={item.preSharedKey}" />
android:inputType="textNoSuggestions|textPassword"
android:onClick="@{fragment::onKeyClick}"
android:text="@={item.preSharedKey}"
app:filter="@{KeyInputFilter.newInstance()}"
app:onFocusChange="@{fragment::onKeyFocusChange}" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout