Bug 1802584 - Announce "Find in page" edit box when using Talkback

When using talkback, the focus keeps jumping between the dismiss
button and the "Find in page" edit text. Seems like giving up
the view stub fixes this issue. Considering that the view inflation
performance wins are rather small for such added complexity,
we have given up the view stub.
fenix/114.1.0
DreVla 1 year ago committed by mergify[bot]
parent 900e1169e0
commit ac4f4ccaca

@ -434,7 +434,7 @@ abstract class BaseBrowserFragment :
feature = FindInPageIntegration(
store = store,
sessionId = customTabSessionId,
stub = binding.stubFindInPage,
view = binding.findInPageView,
engineView = binding.engineView,
toolbarInfo = FindInPageIntegration.ToolbarInfo(
browserToolbarView.view,

@ -6,7 +6,7 @@ package org.mozilla.fenix.components
import android.view.View
import android.view.ViewGroup.MarginLayoutParams
import android.view.ViewStub
import androidx.annotation.UiThread
import androidx.annotation.VisibleForTesting
import androidx.core.view.isVisible
import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab
@ -14,8 +14,9 @@ import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.browser.toolbar.BrowserToolbar
import mozilla.components.concept.engine.EngineView
import mozilla.components.feature.findinpage.FindInPageFeature
import mozilla.components.feature.findinpage.view.FindInPageView
import mozilla.components.feature.findinpage.view.FindInPageBar
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.base.feature.UserInteractionHandler
import org.mozilla.fenix.components.FindInPageIntegration.ToolbarInfo
/**
@ -30,19 +31,38 @@ import org.mozilla.fenix.components.FindInPageIntegration.ToolbarInfo
class FindInPageIntegration(
private val store: BrowserStore,
private val sessionId: String? = null,
stub: ViewStub,
private val view: FindInPageBar,
private val engineView: EngineView,
private val toolbarInfo: ToolbarInfo,
) : InflationAwareFeature(stub) {
override fun onViewInflated(view: View): LifecycleAwareFeature {
return FindInPageFeature(store, view as FindInPageView, engineView) {
restorePreviousLayout()
) : LifecycleAwareFeature, UserInteractionHandler {
private val feature by lazy { FindInPageFeature(store, view, engineView, ::onClose) }
view.visibility = View.GONE
}
override fun start() {
feature.start()
}
override fun stop() {
feature.stop()
}
override fun onBackPressed(): Boolean {
return feature.onBackPressed()
}
private fun onClose() {
view.visibility = View.GONE
restorePreviousLayout()
}
/**
* Start the find in page functionality.
*/
@UiThread
fun launch() {
onLaunch(view, feature)
}
override fun onLaunch(view: View, feature: LifecycleAwareFeature) {
private fun onLaunch(view: View, feature: LifecycleAwareFeature) {
store.state.findCustomTabOrSelectedTab(sessionId)?.let { tab ->
prepareLayoutForFindBar()

@ -1,89 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components
import android.view.View
import android.view.ViewStub
import androidx.annotation.UiThread
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.base.feature.UserInteractionHandler
import java.lang.ref.WeakReference
/**
* A base feature class that enables lazy inflation of a view needed by a feature.
*
* When a feature needs to be launched (e.g. by user interaction) calling [launch]
* will inflate the view only then, start the feature, and then executes [onLaunch]
* for any feature-specific startup needs.
*/
abstract class InflationAwareFeature(
private val stub: ViewStub,
) : LifecycleAwareFeature, UserInteractionHandler {
internal lateinit var view: WeakReference<View>
internal var feature: LifecycleAwareFeature? = null
private val stubListener = ViewStub.OnInflateListener { _, inflated ->
view = WeakReference(inflated)
feature = onViewInflated(inflated).also {
it.start()
onLaunch(inflated, it)
}
}
/**
* Invoked when a view-dependent feature needs to be started along with the feature itself.
*/
@UiThread
fun launch() {
// If we have a feature and view, we can launch immediately.
if (feature != null && view.get() != null) {
onLaunch(view.get()!!, feature!!)
} else {
stub.apply {
setOnInflateListener(stubListener)
inflate()
}
}
}
/**
* Implementation notes: This implemented method does nothing since we only start the feature
* when the view is inflated.
*/
override fun start() {
feature?.start()
}
override fun stop() {
feature?.stop()
}
/**
* Called when the feature gets the option to handle the user pressing the back key.
*
* @return true if the feature also implements [UserInteractionHandler] and the feature has
* been initiated.
*/
override fun onBackPressed(): Boolean {
return (feature as? UserInteractionHandler)?.onBackPressed() ?: false
}
/**
* Invoked when the view has been inflated for the feature to be created with it.
*
* @param view The newly created view.
* @return The feature initiated with the view.
*/
abstract fun onViewInflated(view: View): LifecycleAwareFeature
/**
* Invoked after the feature is instantiated. If the feature already exists,
* this is invoked immediately.
*
* @param view The view that is attached to the feature.
* @param feature The feature that was instantiated.
*/
abstract fun onLaunch(view: View, feature: LifecycleAwareFeature)
}

@ -35,13 +35,18 @@
android:visibility="gone" />
</mozilla.components.ui.widgets.VerticalSwipeRefreshLayout>
<ViewStub
android:id="@+id/stubFindInPage"
<mozilla.components.feature.findinpage.view.FindInPageBar
android:id="@+id/findInPageView"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="bottom"
android:inflatedId="@+id/findInPageView"
android:layout="@layout/stub_find_in_page" />
android:background="?attr/layer1"
android:clickable="true"
android:focusable="true"
android:visibility="gone"
app:findInPageNoMatchesTextColor="?attr/textWarning"
app:findInPageButtonsTint="?attr/textPrimary"
app:findInPageResultCountTextColor="?attr/textPrimary" />
<include
android:id="@+id/viewDynamicDownloadDialog"

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<mozilla.components.feature.findinpage.view.FindInPageBar xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/findInPageView"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_gravity="bottom"
android:background="?attr/layer1"
android:clickable="true"
android:focusable="true"
app:findInPageNoMatchesTextColor="?attr/textWarning"
app:findInPageButtonsTint="?attr/textPrimary"
app:findInPageResultCountTextColor="?attr/textPrimary" />

@ -1,101 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.components
import android.view.View
import android.view.ViewStub
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.support.base.feature.LifecycleAwareFeature
import mozilla.components.support.base.feature.UserInteractionHandler
import org.junit.Test
import java.lang.ref.WeakReference
class InflationAwareFeatureTest {
@Test
fun `stub inflates if no feature or view exists`() {
val stub: ViewStub = mockk(relaxed = true)
val feature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
feature.launch()
verify { stub.setOnInflateListener(any()) }
verify { stub.inflate() }
}
@Test
fun `stub immediately launches if the feature is available`() {
val stub: ViewStub = mockk()
val feature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
feature.feature = mockk(relaxed = true)
feature.view = WeakReference(mockk())
feature.launch()
verify(exactly = 0) { stub.setOnInflateListener(any()) }
verify(exactly = 0) { stub.inflate() }
verify { feature.onLaunch(any(), any()) }
}
@Test
fun `feature calls stop if created`() {
val stub: ViewStub = mockk()
val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
val innerFeature: LifecycleAwareFeature = mockk(relaxed = true)
inflationFeature.stop()
verify(exactly = 0) { innerFeature.stop() }
inflationFeature.feature = innerFeature
inflationFeature.stop()
verify { innerFeature.stop() }
}
@Test
fun `start should be delegated to the inner feature`() {
val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(mockk()))
val innerFeature: LifecycleAwareFeature = mockk(relaxed = true)
inflationFeature.feature = innerFeature
inflationFeature.start()
verify { innerFeature.start() }
}
@Test
fun `if feature has implemented UserInteractionHandler invoke it`() {
val stub: ViewStub = mockk()
val inflationFeature: InflationAwareFeature = spyk(TestableInflationAwareFeature(stub))
val innerFeature: LifecycleAwareFeature = mockk()
val userInteractionHandlerFeature = object : LifecycleAwareFeature, UserInteractionHandler {
override fun onBackPressed() = true
override fun start() {}
override fun stop() {}
}
assert(!inflationFeature.onBackPressed())
inflationFeature.feature = innerFeature
assert(!inflationFeature.onBackPressed())
inflationFeature.feature = userInteractionHandlerFeature
assert(inflationFeature.onBackPressed())
}
}
class TestableInflationAwareFeature(stub: ViewStub) : InflationAwareFeature(stub) {
override fun onViewInflated(view: View): LifecycleAwareFeature = mockk()
override fun onLaunch(view: View, feature: LifecycleAwareFeature) = Unit
}
Loading…
Cancel
Save