Context
I have a setup with a title (text view), some web content (web view) and a footer (button). When talk back is enabled, the user can use standard Swipe left -> next item
and swipe right -> previous item
to navigate through the screen. The user can also use swipe up
and swipe down
to jump between lines, paragraphs, headings, containers etc.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_text" />
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="300dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button" />
</LinearLayout>
Problem
Once the user is inside the webview, they have to go through the entire content of the the webview before they can jump out of it and the only way out of the webview seems to be the swipe left
or swipe right
gestures. I would like to provide a way for the user to move to the Footer button
from any view.
Attemped solutions I created a custom accessibility delegate that will let the user jump to the footer button at any point by opening the talkback context menu.
class WebViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityWebviewBinding.inflate(layoutInflater)
setContentView(binding.root)
val htmlContent =
"""<html>
<h1>This is a webview</h1>
<body>
<p>This is a paragraph inside web view</p>
<p>This is another paragraph inside web view</p>
</body>
</html>
""".trimMargin()
binding.webView.loadData(htmlContent, "text/html", "utf-8")
binding.webView.accessibilityDelegate = CustomFocusAccessibilityDelegate {
binding.btnFooter.apply {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
requestFocus()
}
}
binding.tvTitle.accessibilityDelegate = CustomFocusAccessibilityDelegate {
binding.btnFooter.apply {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED)
requestFocus()
}
}
}
}
class CustomFocusAccessibilityDelegate(
private val focusFooterButton: () -> Unit
) : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(host, info)
val action = AccessibilityAction(
R.id.action_focus_footer,
"Focus on footer button"
)
info.addAction(action)
}
override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
if (action == R.id.action_focus_footer) {
focusFooterButton()
return true
}
return super.performAccessibilityAction(host, action, args)
}
}
This delegate seems to be working for all views except for the webview.
When the talkback focus is on text view. Bringing up the context menu correctly displays the custom actions
However, when the focus is on the webview, the custom action is never added or displayed.
Question How can I add custom action to the webview, allowing the user to the jump to the footer button?