Commit d1005dd2 authored by codrut.topliceanu's avatar codrut.topliceanu Committed by Emily Kager
Browse files

For #8589 - Fix for accessibility navigation in ETP panel

parent 824022c2
......@@ -73,7 +73,8 @@ class TrackingProtectionPanelDialogFragment : AppCompatDialogFragment(), UserInt
args.url,
args.trackingProtectionEnabled,
listTrackers = listOf(),
mode = TrackingProtectionState.Mode.Normal
mode = TrackingProtectionState.Mode.Normal,
lastAccessedCategory = ""
)
)
}
......
......@@ -7,11 +7,17 @@ package org.mozilla.fenix.trackingprotection
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.net.toUri
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.component_tracking_protection_panel.*
import kotlinx.android.synthetic.main.component_tracking_protection_panel.details_blocking_header
import kotlinx.android.synthetic.main.switch_with_description.view.*
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
import org.mozilla.fenix.R
......@@ -55,6 +61,7 @@ interface TrackingProtectionPanelViewInteractor {
/**
* View that contains and configures the Tracking Protection Panel
*/
@SuppressWarnings("TooManyFunctions")
class TrackingProtectionPanelView(
override val containerView: ViewGroup,
val interactor: TrackingProtectionPanelInteractor
......@@ -68,6 +75,8 @@ class TrackingProtectionPanelView(
private var bucketedTrackers = TrackerBuckets()
private var shouldFocusAccessibilityView: Boolean = true
fun update(state: TrackingProtectionState) {
if (state.mode != mode) {
mode = state.mode
......@@ -82,6 +91,8 @@ class TrackingProtectionPanelView(
mode.categoryBlocked
)
}
setAccessibilityViewHierarchy(details_back, category_title)
}
private fun setUIForNormalMode(state: TrackingProtectionState) {
......@@ -99,6 +110,40 @@ class TrackingProtectionPanelView(
blocking_header.isGone = bucketedTrackers.blockedIsEmpty()
updateCategoryVisibility()
setCategoryClickListeners()
focusAccessibilityLastUsedCategory(state.lastAccessedCategory)
}
/**
* Will force accessibility focus to last entered details category.
* Called when user returns from details_mode.
* */
private fun focusAccessibilityLastUsedCategory(categoryTitle: String) {
if (categoryTitle.isNotEmpty()) {
val viewToFocus = getLastUsedCategoryView(categoryTitle)
if (viewToFocus != null && viewToFocus.isVisible && shouldFocusAccessibilityView) {
viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
shouldFocusAccessibilityView = false
}
}
}
private fun getLastUsedCategoryView(categoryTitle: String) = when (categoryTitle) {
CROSS_SITE_TRACKING_COOKIES.name -> {
cross_site_tracking
}
SOCIAL_MEDIA_TRACKERS.name -> {
if (social_media_trackers.isGone) social_media_trackers_loaded else social_media_trackers
}
FINGERPRINTERS.name -> {
if (fingerprinters.isGone) fingerprinters_loaded else fingerprinters
}
TRACKING_CONTENT.name -> {
if (tracking_content.isGone) tracking_content_loaded else tracking_content
}
CRYPTOMINERS.name -> {
if (cryptominers.isGone) cryptominers_loaded else cryptominers
}
else -> null
}
private fun updateCategoryVisibility() {
......@@ -131,6 +176,7 @@ class TrackingProtectionPanelView(
override fun onClick(v: View) {
val category = getCategory(v) ?: return
v.context.metrics.track(Event.TrackingProtectionTrackerList)
shouldFocusAccessibilityView = true
interactor.openDetails(category, categoryBlocked = !isLoaded(v))
}
......@@ -155,6 +201,9 @@ class TrackingProtectionPanelView(
details_back.setOnClickListener {
interactor.onBackPressed()
}
details_back.requestFocus()
details_back.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
}
private fun bindUrl(url: String) {
......@@ -183,6 +232,21 @@ class TrackingProtectionPanelView(
}
}
/**
* Makes sure [view1] is followed by [view2] when navigating in accessibility mode.
* */
private fun setAccessibilityViewHierarchy(view1: View, view2: View) {
ViewCompat.setAccessibilityDelegate(view2, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(
host: View?,
info: AccessibilityNodeInfoCompat?
) {
info?.setTraversalAfter(view1)
super.onInitializeAccessibilityNodeInfo(host, info)
}
})
}
companion object {
/**
......
......@@ -50,13 +50,16 @@ sealed class TrackingProtectionAction : Action {
* @property isTrackingProtectionEnabled Current status of tracking protection for this session (ie is an exception)
* @property listTrackers Current Tracker Log list of blocked and loaded tracker categories
* @property mode Current Mode of TrackingProtection
* @property lastAccessedCategory Remembers the last accessed details category, used to move
* accessibly focus after returning from details_moode
*/
data class TrackingProtectionState(
val session: Session?,
val url: String,
val isTrackingProtectionEnabled: Boolean,
val listTrackers: List<TrackerLog>,
val mode: Mode
val mode: Mode,
val lastAccessedCategory: String
) : State {
sealed class Mode {
object Normal : Mode()
......@@ -112,7 +115,8 @@ fun trackingProtectionStateReducer(
mode = TrackingProtectionState.Mode.Details(
action.category,
action.categoryBlocked
)
),
lastAccessedCategory = action.category.name
)
is TrackingProtectionAction.TrackerBlockingChanged ->
state.copy(isTrackingProtectionEnabled = action.isTrackingProtectionEnabled)
......
......@@ -43,6 +43,7 @@
<TextView
android:id="@+id/blocking_header"
style="@style/QuickSettingsText"
android:accessibilityHeading="true"
android:layout_width="wrap_content"
android:layout_height="@dimen/tracking_protection_item_height"
android:text="@string/enhanced_tracking_protection_blocked"
......@@ -50,7 +51,8 @@
android:textStyle="bold"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/trackingProtectionSwitch" />
app:layout_constraintTop_toBottomOf="@id/trackingProtectionSwitch"
tools:targetApi="p" />
<TextView
android:id="@+id/cross_site_tracking"
......@@ -106,12 +108,14 @@
android:id="@+id/not_blocking_header"
style="@style/QuickSettingsText"
android:layout_width="wrap_content"
android:accessibilityHeading="true"
android:layout_height="@dimen/tracking_protection_item_height"
android:text="@string/enhanced_tracking_protection_allowed"
android:textStyle="bold"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tracking_content" />
app:layout_constraintTop_toBottomOf="@id/tracking_content"
tools:targetApi="p" />
<TextView
android:id="@+id/fingerprinters_loaded"
......@@ -227,6 +231,7 @@
<TextView
android:id="@+id/details_blocking_header"
android:accessibilityHeading="true"
style="@style/QuickSettingsText"
android:layout_width="wrap_content"
android:layout_height="@dimen/tracking_protection_item_height"
......@@ -237,7 +242,8 @@
android:text="@string/enhanced_tracking_protection_blocked"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/line_divider_details" />
app:layout_constraintTop_toBottomOf="@id/line_divider_details"
tools:targetApi="p" />
<androidx.core.widget.NestedScrollView
android:id="@+id/blocking_scrollview"
......
......@@ -33,6 +33,7 @@ class TrackingProtectionStoreTest {
store.state.mode,
TrackingProtectionState.Mode.Details(TrackingProtectionCategory.FINGERPRINTERS, true)
)
assertEquals(store.state.lastAccessedCategory, TrackingProtectionCategory.FINGERPRINTERS.name)
}
@Test
......@@ -46,6 +47,7 @@ class TrackingProtectionStoreTest {
store.state.mode,
TrackingProtectionState.Mode.Normal
)
assertEquals(store.state.lastAccessedCategory, initialState.lastAccessedCategory)
}
@Test
......@@ -133,7 +135,8 @@ class TrackingProtectionStoreTest {
url = "www.mozilla.org",
isTrackingProtectionEnabled = true,
listTrackers = listOf(),
mode = TrackingProtectionState.Mode.Normal
mode = TrackingProtectionState.Mode.Normal,
lastAccessedCategory = ""
)
private fun detailsState(): TrackingProtectionState = TrackingProtectionState(
......@@ -141,6 +144,7 @@ class TrackingProtectionStoreTest {
url = "www.mozilla.org",
isTrackingProtectionEnabled = true,
listTrackers = listOf(),
mode = TrackingProtectionState.Mode.Details(TrackingProtectionCategory.CRYPTOMINERS, true)
mode = TrackingProtectionState.Mode.Details(TrackingProtectionCategory.CRYPTOMINERS, true),
lastAccessedCategory = TrackingProtectionCategory.CRYPTOMINERS.name
)
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment