summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-10-19 10:01:05 -0300
committerJanito Vaqueiro Ferreira Filho <janito@mullvad.net>2020-10-19 10:01:05 -0300
commita702afabaee292e92a80a1d6c0a75f80f2babb8d (patch)
treed853e5951b9fc4768f7e4605002d3823df607fe3 /android
parent8ad9aa6fdd743cbcd6ea97d837243cd4d9cb0e46 (diff)
parent62050280478d255e03e20dc1fdd54d707d4751f8 (diff)
downloadmullvadvpn-a702afabaee292e92a80a1d6c0a75f80f2babb8d.tar.xz
mullvadvpn-a702afabaee292e92a80a1d6c0a75f80f2babb8d.zip
Merge branch 'improve-keyboard-navigation'
Diffstat (limited to 'android')
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt19
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt7
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt2
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt21
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt12
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt1
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt1
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt61
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt7
-rw-r--r--android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt39
-rw-r--r--android/src/main/res/drawable/app_list_item_background.xml9
-rw-r--r--android/src/main/res/drawable/blue_button_background.xml10
-rw-r--r--android/src/main/res/drawable/cell_button_background.xml9
-rw-r--r--android/src/main/res/drawable/green_button_background.xml10
-rw-r--r--android/src/main/res/drawable/red_button_background.xml10
-rw-r--r--android/src/main/res/drawable/transparent_red_button_background.xml10
-rw-r--r--android/src/main/res/drawable/transparent_red_left_half_button_background.xml11
-rw-r--r--android/src/main/res/drawable/transparent_red_right_half_button_background.xml11
-rw-r--r--android/src/main/res/drawable/white20_button_background.xml10
-rw-r--r--android/src/main/res/layout/account_history_entry.xml1
-rw-r--r--android/src/main/res/layout/app_list_item.xml3
-rw-r--r--android/src/main/res/layout/connect.xml1
-rw-r--r--android/src/main/res/layout/notification_banner.xml1
-rw-r--r--android/src/main/res/layout/relay_list_item.xml68
-rw-r--r--android/src/main/res/layout/welcome.xml1
-rw-r--r--android/src/main/res/values/colors.xml1
26 files changed, 233 insertions, 103 deletions
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt
index e375bf2113..a215930194 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemHolder.kt
@@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.relaylist
import android.support.v7.widget.RecyclerView.ViewHolder
import android.view.View
+import android.view.ViewGroup.MarginLayoutParams
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
@@ -14,6 +15,8 @@ class RelayItemHolder(
) : ViewHolder(view) {
private val name: TextView = view.findViewById(R.id.name)
private val chevron: ImageButton = view.findViewById(R.id.chevron)
+ private val clickArea: View = view.findViewById(R.id.click_area)
+ private val relayStatus: View = view.findViewById(R.id.status)
private val relayActive: ImageView = view.findViewById(R.id.relay_active)
private val selectedIcon: View = view.findViewById(R.id.selected)
@@ -42,7 +45,7 @@ class RelayItemHolder(
init {
chevron.setOnClickListener { toggle() }
- view.setOnClickListener { adapter.selectItem(item, this) }
+ clickArea.setOnClickListener { adapter.selectItem(item, this) }
}
private fun updateView() {
@@ -71,7 +74,7 @@ class RelayItemHolder(
}
}
- view.setEnabled(item.active)
+ clickArea.setEnabled(item.active)
when (item.type) {
RelayItemType.Country -> setViewStyle(countryColor, countryPadding)
@@ -98,19 +101,17 @@ class RelayItemHolder(
private fun setViewStyle(rowColor: Int, padding: Int) {
var backgroundColor = rowColor
- val paddingLeft = padding
- val paddingTop = view.paddingTop
- val paddingRight = view.paddingRight
- val paddingBottom = view.paddingBottom
if (selected) {
backgroundColor = selectedColor
}
- view.apply {
- setBackgroundColor(backgroundColor)
- setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom)
+ (relayStatus.layoutParams as? MarginLayoutParams)?.let { parameters ->
+ parameters.leftMargin = padding
+ relayStatus.layoutParams = parameters
}
+
+ view.setBackgroundColor(backgroundColor)
}
private fun toggle() {
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
index f4b2ea0f7c..c84961fc53 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/LoginFragment.kt
@@ -31,6 +31,7 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
private lateinit var loginFailStatus: View
private lateinit var accountLogin: AccountLogin
private lateinit var scrollArea: ScrollView
+ private lateinit var background: View
private val loggedIn = CompletableDeferred<LoginResult>()
@@ -57,8 +58,8 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
scrollArea = view.findViewById(R.id.scroll_area)
- view.findViewById<View>(R.id.contents).setOnClickListener {
- accountLogin.clearFocus()
+ background = view.findViewById<View>(R.id.contents).apply {
+ setOnClickListener { requestFocus() }
}
scrollToShow(accountLogin)
@@ -124,6 +125,8 @@ class LoginFragment : ServiceDependentFragment(OnNoService.GoToLaunchScreen) {
loginFailStatus.visibility = View.GONE
loggedInStatus.visibility = View.GONE
+ background.requestFocus()
+
accountLogin.state = LoginState.InProgress
scrollToShow(loggingInStatus)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt
index 6e88a2d9a1..737e4a3859 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryAdapter.kt
@@ -20,6 +20,7 @@ class AccountHistoryAdapter : Adapter<AccountHistoryHolder>() {
var onSelectEntry: ((String) -> Unit)? = null
var onRemoveEntry: ((String) -> Unit)? = null
+ var onChildFocusChanged: ((String, Boolean) -> Unit)? = null
override fun onCreateViewHolder(parentView: ViewGroup, type: Int): AccountHistoryHolder {
val inflater = LayoutInflater.from(parentView.context)
@@ -28,6 +29,7 @@ class AccountHistoryAdapter : Adapter<AccountHistoryHolder>() {
return AccountHistoryHolder(view, formatter).apply {
onSelect = { account -> onSelectEntry?.invoke(account) }
onRemove = { account -> onRemoveEntry?.invoke(account) }
+ onFocusChanged = { account, hasFocus -> onChildFocusChanged?.invoke(account, hasFocus) }
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt
index e91897af4b..e0e911467b 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountHistoryHolder.kt
@@ -19,14 +19,27 @@ class AccountHistoryHolder(
var onSelect: ((String) -> Unit)? = null
var onRemove: ((String) -> Unit)? = null
+ var onFocusChanged: ((String, Boolean) -> Unit)? = null
init {
- view.setOnClickListener {
- onSelect?.invoke(accountToken)
+ view.findViewById<View>(R.id.remove).apply {
+ setOnClickListener {
+ onRemove?.invoke(accountToken)
+ }
+
+ setOnFocusChangeListener { _, hasFocus ->
+ onFocusChanged?.invoke(accountToken, hasFocus)
+ }
}
- view.findViewById<View>(R.id.remove).setOnClickListener {
- onRemove?.invoke(accountToken)
+ label.apply {
+ setOnClickListener {
+ onSelect?.invoke(accountToken)
+ }
+
+ setOnFocusChangeListener { _, hasFocus ->
+ onFocusChanged?.invoke(accountToken, hasFocus)
+ }
}
}
}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt
index 3cc2935c21..9052a2e63e 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/AccountLogin.kt
@@ -17,12 +17,17 @@ import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.ui.ListItemDividerDecoration
import net.mullvad.mullvadvpn.ui.LoginState
import net.mullvad.mullvadvpn.ui.widget.AccountLoginBorder.BorderState
+import net.mullvad.mullvadvpn.util.Debouncer
class AccountLogin : RelativeLayout {
companion object {
private val MAX_ACCOUNT_HISTORY_ENTRIES = 3
}
+ private val focusDebouncer = Debouncer(false).apply {
+ listener = { hasFocus -> focused = hasFocus }
+ }
+
private val container =
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service ->
val inflater = service as LayoutInflater
@@ -36,6 +41,7 @@ class AccountLogin : RelativeLayout {
private val historyAdapter = AccountHistoryAdapter().apply {
onSelectEntry = { account -> input.loginWith(account) }
+ onChildFocusChanged = { _, hasFocus -> focusDebouncer.rawValue = hasFocus }
}
private val dividerHeight = resources.getDimensionPixelSize(R.dimen.account_history_divider)
@@ -70,7 +76,7 @@ class AccountLogin : RelativeLayout {
}
}
- private var inputHasFocus by observable(false) { _, _, hasFocus ->
+ private var focused by observable(false) { _, _, hasFocus ->
updateBorder()
shouldShowAccountHistory = hasFocus
@@ -137,7 +143,7 @@ class AccountLogin : RelativeLayout {
input.apply {
onFocusChanged.subscribe(this) { hasFocus ->
- inputHasFocus = hasFocus
+ focusDebouncer.rawValue = hasFocus
}
onTextChanged.subscribe(this) { _ ->
@@ -173,7 +179,7 @@ class AccountLogin : RelativeLayout {
private fun updateBorder() {
if (state == LoginState.Failure) {
border.borderState = BorderState.ERROR
- } else if (inputHasFocus) {
+ } else if (focused) {
border.borderState = BorderState.FOCUSED
} else {
border.borderState = BorderState.UNFOCUSED
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt
index b0ae6024ec..b0833fd49d 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/BackButton.kt
@@ -40,6 +40,7 @@ class BackButton : LinearLayout {
}
init {
+ setFocusable(true)
isClickable = true
gravity = Gravity.CENTER_VERTICAL or Gravity.LEFT
orientation = HORIZONTAL
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt
index cb87408251..a533b5e758 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/Cell.kt
@@ -43,6 +43,7 @@ open class Cell : LinearLayout {
val leftPadding = resources.getDimensionPixelSize(R.dimen.cell_left_padding)
val rightPadding = resources.getDimensionPixelSize(R.dimen.cell_right_padding)
+ setFocusable(true)
isClickable = true
gravity = Gravity.CENTER
orientation = HORIZONTAL
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt
index 59b5154fb8..d80506a5dd 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/InformationView.kt
@@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
+import kotlin.properties.Delegates.observable
import net.mullvad.mullvadvpn.R
open class InformationView : LinearLayout {
@@ -27,7 +28,7 @@ open class InformationView : LinearLayout {
}
}
- private val container =
+ private val container: View =
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE).let { service ->
val inflater = service as LayoutInflater
@@ -41,55 +42,23 @@ open class InformationView : LinearLayout {
private val informationDisplay: TextView = findViewById(R.id.information_display)
private val spinner: View = findViewById(R.id.spinner)
- var displayFormatter: ((String) -> String)? = null
- set(value) {
- field = value
- updateStatus()
- }
-
- var shouldEnable = false
- set(value) {
- field = value
- updateEnabled()
- }
-
- var error: String? = null
- set(value) {
- field = value
- updateStatus()
- }
-
- var errorColor = context.getColor(R.color.red)
- set(value) {
- field = value
- updateStatus()
- }
+ var error by observable<String?>(null) { _, _, _ -> updateStatus() }
+ var information by observable<String?>(null) { _, _, _ -> updateStatus() }
- var information: String? = null
- set(value) {
- field = value
- updateStatus()
- }
+ var errorColor by observable(context.getColor(R.color.red)) { _, _, _ -> updateStatus() }
+ var informationColor by observable(context.getColor(R.color.white)) { _, _, _ ->
+ updateStatus()
+ }
- var informationColor = context.getColor(R.color.white)
- set(value) {
- field = value
- updateStatus()
- }
+ var displayFormatter by observable<((String) -> String)?>(null) { _, _, _ -> updateStatus() }
+ var maxLength by observable(0) { _, _, _ -> updateStatus() }
+ var whenMissing by observable(WhenMissing.Nothing) { _, _, _ -> updateStatus() }
- var maxLength = 0
- set(value) {
- field = value
- updateStatus()
- }
+ var shouldEnable by observable(false) { _, _, _ -> updateEnabled() }
- var whenMissing = WhenMissing.Nothing
- set(value) {
- field = value
- updateStatus()
- }
-
- var onClick: (() -> Unit)? = null
+ var onClick by observable<(() -> Unit)?>(null) { _, _, callback ->
+ container.setFocusable(callback != null)
+ }
constructor(context: Context) : super(context) {}
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt
index eb1463cd45..94ddc2838e 100644
--- a/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/ui/widget/MtuCell.kt
@@ -66,8 +66,11 @@ class MtuCell : Cell {
) {}
init {
- cell.setEnabled(false)
- cell.addView(input)
+ cell.apply {
+ setEnabled(false)
+ setFocusable(false)
+ addView(input)
+ }
footer?.text =
context.getString(R.string.wireguard_mtu_footer, MIN_MTU_VALUE, MAX_MTU_VALUE)
diff --git a/android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt b/android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt
new file mode 100644
index 0000000000..7afb4c508f
--- /dev/null
+++ b/android/src/main/kotlin/net/mullvad/mullvadvpn/util/Debouncer.kt
@@ -0,0 +1,39 @@
+package net.mullvad.mullvadvpn.util
+
+import kotlin.properties.Delegates.observable
+import kotlinx.coroutines.delay
+
+// Helper to filter out bursts of events so that only the latest event in an interval is notified.
+//
+// An interval of zero means that it will only debounce events that are sent before the job is
+// started. If the events are coming from the UI thread, this means that this class will only send
+// the last event received before the UI thread finishes its current task.
+//
+// This can be used for example to filter out focus events coming from different views. Android will
+// first send a "focus lost" event from a view followed by a "focus gained" event from another view.
+// If the only thing the listener is interested in is if any of a set of views has focus, this class
+// can be used to debounce focus events from the set of views to obtain an event that represents a
+// change from when the set contains a focused view to when the set contains no focused views (and
+// an event for the reverse situation).
+class Debouncer<T>(initialValue: T, val intervalInMs: Long = 0) {
+ private val jobTracker = JobTracker()
+
+ var listener: ((T) -> Unit)? = null
+
+ var debouncedValue = initialValue
+ private set
+
+ var rawValue by observable(initialValue) { _, oldValue, newValue ->
+ if (newValue != oldValue) {
+ jobTracker.cancelJob("notifyNewValue")
+
+ if (newValue != debouncedValue) {
+ jobTracker.newUiJob("notifyNewValue") {
+ delay(intervalInMs)
+ listener?.invoke(newValue)
+ debouncedValue = newValue
+ }
+ }
+ }
+ }
+}
diff --git a/android/src/main/res/drawable/app_list_item_background.xml b/android/src/main/res/drawable/app_list_item_background.xml
index 9cde2e4032..a55c1e6d01 100644
--- a/android/src/main/res/drawable/app_list_item_background.xml
+++ b/android/src/main/res/drawable/app_list_item_background.xml
@@ -1,10 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<solid android:color="@color/blue40" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/blue80" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/blue60" />
diff --git a/android/src/main/res/drawable/blue_button_background.xml b/android/src/main/res/drawable/blue_button_background.xml
index 44f0406e46..e87b080bee 100644
--- a/android/src/main/res/drawable/blue_button_background.xml
+++ b/android/src/main/res/drawable/blue_button_background.xml
@@ -1,11 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/blue80" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp" />
+ <solid android:color="@color/blue40" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
diff --git a/android/src/main/res/drawable/cell_button_background.xml b/android/src/main/res/drawable/cell_button_background.xml
index e00f49464d..857a8386e1 100644
--- a/android/src/main/res/drawable/cell_button_background.xml
+++ b/android/src/main/res/drawable/cell_button_background.xml
@@ -1,10 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<solid android:color="@color/blue" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <solid android:color="@color/blue60" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<solid android:color="@color/blue80" />
diff --git a/android/src/main/res/drawable/green_button_background.xml b/android/src/main/res/drawable/green_button_background.xml
index 275f4fc3cb..b2a50d5678 100644
--- a/android/src/main/res/drawable/green_button_background.xml
+++ b/android/src/main/res/drawable/green_button_background.xml
@@ -1,11 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/green" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp" />
+ <solid android:color="@color/green80" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
diff --git a/android/src/main/res/drawable/red_button_background.xml b/android/src/main/res/drawable/red_button_background.xml
index 69f16f298f..e41121638f 100644
--- a/android/src/main/res/drawable/red_button_background.xml
+++ b/android/src/main/res/drawable/red_button_background.xml
@@ -1,11 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/red" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp" />
+ <solid android:color="@color/red80" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
diff --git a/android/src/main/res/drawable/transparent_red_button_background.xml b/android/src/main/res/drawable/transparent_red_button_background.xml
index e284fb9bfb..84a3a77c38 100644
--- a/android/src/main/res/drawable/transparent_red_button_background.xml
+++ b/android/src/main/res/drawable/transparent_red_button_background.xml
@@ -1,11 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/red60" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp" />
+ <solid android:color="@color/red95" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
diff --git a/android/src/main/res/drawable/transparent_red_left_half_button_background.xml b/android/src/main/res/drawable/transparent_red_left_half_button_background.xml
index 1102ec771b..dab41c1f57 100644
--- a/android/src/main/res/drawable/transparent_red_left_half_button_background.xml
+++ b/android/src/main/res/drawable/transparent_red_left_half_button_background.xml
@@ -1,12 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:topLeftRadius="4dp"
android:bottomLeftRadius="4dp" />
<solid android:color="@color/red60" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:topLeftRadius="4dp"
+ android:bottomLeftRadius="4dp" />
+ <solid android:color="@color/red95" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:topLeftRadius="4dp"
diff --git a/android/src/main/res/drawable/transparent_red_right_half_button_background.xml b/android/src/main/res/drawable/transparent_red_right_half_button_background.xml
index 0c31d5f429..f23bde9841 100644
--- a/android/src/main/res/drawable/transparent_red_right_half_button_background.xml
+++ b/android/src/main/res/drawable/transparent_red_right_half_button_background.xml
@@ -1,12 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:topRightRadius="4dp"
android:bottomRightRadius="4dp" />
<solid android:color="@color/red60" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:topRightRadius="4dp"
+ android:bottomRightRadius="4dp" />
+ <solid android:color="@color/red95" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:topRightRadius="4dp"
diff --git a/android/src/main/res/drawable/white20_button_background.xml b/android/src/main/res/drawable/white20_button_background.xml
index 8a2601fdf8..f52c7cf182 100644
--- a/android/src/main/res/drawable/white20_button_background.xml
+++ b/android/src/main/res/drawable/white20_button_background.xml
@@ -1,11 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false">
+ <item android:state_pressed="false"
+ android:state_focused="false">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/white20" />
</shape>
</item>
+ <item android:state_pressed="false"
+ android:state_focused="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="4dp" />
+ <solid android:color="@color/white60" />
+ </shape>
+ </item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="4dp" />
diff --git a/android/src/main/res/layout/account_history_entry.xml b/android/src/main/res/layout/account_history_entry.xml
index d410b5138c..746de82d3c 100644
--- a/android/src/main/res/layout/account_history_entry.xml
+++ b/android/src/main/res/layout/account_history_entry.xml
@@ -4,6 +4,7 @@
<TextView android:id="@+id/label"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:focusable="true"
android:background="@drawable/account_history_entry_background"
android:paddingHorizontal="12dp"
android:gravity="center_vertical"
diff --git a/android/src/main/res/layout/app_list_item.xml b/android/src/main/res/layout/app_list_item.xml
index c705db1085..eebfccf88e 100644
--- a/android/src/main/res/layout/app_list_item.xml
+++ b/android/src/main/res/layout/app_list_item.xml
@@ -5,7 +5,8 @@
android:background="@drawable/app_list_item_background"
android:orientation="horizontal"
android:gravity="center"
- android:clickable="true">
+ android:clickable="true"
+ android:focusable="true">
<ProgressBar android:id="@+id/loading"
android:layout_width="@dimen/app_list_item_icon_size"
android:layout_height="@dimen/app_list_item_icon_size"
diff --git a/android/src/main/res/layout/connect.xml b/android/src/main/res/layout/connect.xml
index 7fd06fd4bc..254dd05442 100644
--- a/android/src/main/res/layout/connect.xml
+++ b/android/src/main/res/layout/connect.xml
@@ -73,6 +73,7 @@
android:paddingHorizontal="@dimen/side_margin"
android:gravity="bottom"
android:clickable="true"
+ android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/android/src/main/res/layout/notification_banner.xml b/android/src/main/res/layout/notification_banner.xml
index abd28193d8..3fb5ef4d10 100644
--- a/android/src/main/res/layout/notification_banner.xml
+++ b/android/src/main/res/layout/notification_banner.xml
@@ -4,6 +4,7 @@
android:paddingVertical="8dp"
android:paddingLeft="16dp"
android:paddingRight="12dp"
+ android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<RelativeLayout android:id="@+id/notification_status_container"
android:layout_width="wrap_content"
diff --git a/android/src/main/res/layout/relay_list_item.xml b/android/src/main/res/layout/relay_list_item.xml
index c8af318778..e0b084901c 100644
--- a/android/src/main/res/layout/relay_list_item.xml
+++ b/android/src/main/res/layout/relay_list_item.xml
@@ -1,34 +1,48 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingLeft="@dimen/country_row_padding"
android:background="@color/blue"
- android:orientation="horizontal"
- android:gravity="center">
- <FrameLayout android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="0">
- <ImageView android:id="@+id/relay_active"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:src="@drawable/icon_relay_active" />
- <ImageView android:id="@+id/selected"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/icon_tick"
- android:visibility="invisible" />
- </FrameLayout>
- <TextView android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginHorizontal="8dp"
- android:layout_marginVertical="14dp"
- android:textColor="@color/white"
- android:textSize="@dimen/text_medium_plus"
- android:textStyle="bold"
- android:text="" />
+ android:orientation="horizontal">
+ <RelativeLayout android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="1">
+ <View android:id="@+id/click_area"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentRight="true"
+ android:focusable="true"
+ android:clickable="true"
+ android:background="?android:attr/selectableItemBackground" />
+ <FrameLayout android:id="@+id/status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="@dimen/country_row_padding">
+ <ImageView android:id="@+id/relay_active"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:src="@drawable/icon_relay_active" />
+ <ImageView android:id="@+id/selected"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/icon_tick"
+ android:visibility="invisible" />
+ </FrameLayout>
+ <TextView android:id="@+id/name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="8dp"
+ android:layout_marginVertical="14dp"
+ android:layout_alignParentRight="true"
+ android:layout_toRightOf="@id/status"
+ android:textColor="@color/white"
+ android:textSize="@dimen/text_medium_plus"
+ android:textStyle="bold"
+ android:text="" />
+ </RelativeLayout>
<ImageButton android:id="@+id/chevron"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/android/src/main/res/layout/welcome.xml b/android/src/main/res/layout/welcome.xml
index 43348fd11d..e1c887ab96 100644
--- a/android/src/main/res/layout/welcome.xml
+++ b/android/src/main/res/layout/welcome.xml
@@ -35,6 +35,7 @@
android:paddingHorizontal="@dimen/side_margin"
android:paddingVertical="11dp"
android:clickable="true"
+ android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:textColor="@color/white"
android:textSize="@dimen/text_big"
diff --git a/android/src/main/res/values/colors.xml b/android/src/main/res/values/colors.xml
index bc18d267f5..23d4ff564f 100644
--- a/android/src/main/res/values/colors.xml
+++ b/android/src/main/res/values/colors.xml
@@ -14,6 +14,7 @@
<color name="white10">#1AFFFFFF</color>
<color name="green">#44AD4D</color>
<color name="green90">#E644AD4D</color>
+ <color name="green80">#CC44AD4D</color>
<color name="red">#FFE34039</color>
<color name="red95">#F2E34039</color>
<color name="red80">#CCE34039</color>