From 9bd2028ee955b33272239a24b50bf0a248ecedf2 Mon Sep 17 00:00:00 2001 From: Eitan Isaacson Date: Wed, 27 Mar 2019 11:14:36 -0700 Subject: [PATCH] [fenix] Fixes https://github.com/mozilla-mobile/fenix/issues/1186: Add AccessibilityActions to quick action sheet's handle Adding the 'click' action allows the user to activate the button with a default action (double tap in TalkBack). This is instead of conditionally setting up a click listener if TalkBack is enabled. This is a more generalized solution that accomodates other ATs besides TalkBack. Adding an expand or collapse action also tells TalkBack what the current state of the sheet is, and reports it to the user. So they will initially hear "collapsed, quick actions, button". When they double tap, they will hear "expanded". Adding those actions also allows TalkBack and other AT users to explicitly call those actions on that element with a menu or a gesture binding. --- .../quickactionsheet/QuickActionSheet.kt | 65 +++++++++++++++---- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/quickactionsheet/QuickActionSheet.kt b/app/src/main/java/org/mozilla/fenix/quickactionsheet/QuickActionSheet.kt index febf011fb7..5af750e697 100644 --- a/app/src/main/java/org/mozilla/fenix/quickactionsheet/QuickActionSheet.kt +++ b/app/src/main/java/org/mozilla/fenix/quickactionsheet/QuickActionSheet.kt @@ -15,7 +15,9 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import mozilla.components.browser.toolbar.BrowserToolbar import org.mozilla.fenix.R import android.animation.ValueAnimator -import android.view.accessibility.AccessibilityManager +import android.os.Bundle +import android.view.accessibility.AccessibilityEvent +import android.view.accessibility.AccessibilityNodeInfo import androidx.interpolator.view.animation.FastOutSlowInInterpolator import org.mozilla.fenix.utils.Settings @@ -39,23 +41,13 @@ class QuickActionSheet @JvmOverloads constructor( val handle = findViewById(R.id.quick_action_sheet_handle) val linearLayout = findViewById(R.id.quick_action_sheet) val quickActionSheetBehavior = BottomSheetBehavior.from(linearLayout.parent as View) as QuickActionSheetBehavior - val accessibilityManager = context - .getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager - - if (accessibilityManager.isTouchExplorationEnabled) { - linearLayout.setOnClickListener { - quickActionSheetBehavior.state = when (quickActionSheetBehavior.state) { - BottomSheetBehavior.STATE_EXPANDED -> BottomSheetBehavior.STATE_COLLAPSED - else -> BottomSheetBehavior.STATE_EXPANDED - } - } - return - } handle.setOnClickListener { bounceSheet(quickActionSheetBehavior) } + handle.setAccessibilityDelegate(HandleAccessibilityDelegate(quickActionSheetBehavior)) + val settings = Settings.getInstance(context) if (settings.shouldAutoBounceQuickActionSheet) { settings.incrementAutomaticBounceQuickActionSheetCount() @@ -87,6 +79,53 @@ class QuickActionSheet @JvmOverloads constructor( } } + class HandleAccessibilityDelegate( + private val quickActionSheetBehavior: QuickActionSheetBehavior + ) : View.AccessibilityDelegate() { + private var finalState = BottomSheetBehavior.STATE_COLLAPSED + get() = when (quickActionSheetBehavior.state) { + BottomSheetBehavior.STATE_EXPANDED, + BottomSheetBehavior.STATE_HIDDEN, + BottomSheetBehavior.STATE_COLLAPSED -> { + quickActionSheetBehavior.state + } + else -> field + } + set(value) { + field = value + quickActionSheetBehavior.state = value + } + + override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean { + when (action) { + AccessibilityNodeInfo.ACTION_CLICK -> { + finalState = when (quickActionSheetBehavior.state) { + BottomSheetBehavior.STATE_EXPANDED -> BottomSheetBehavior.STATE_COLLAPSED + else -> BottomSheetBehavior.STATE_EXPANDED + } + } + AccessibilityNodeInfo.ACTION_COLLAPSE -> + finalState = BottomSheetBehavior.STATE_COLLAPSED + AccessibilityNodeInfo.ACTION_EXPAND -> + finalState = BottomSheetBehavior.STATE_EXPANDED + else -> return super.performAccessibilityAction(host, action, args) + } + + host?.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED) + + return true + } + + override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfo?) { + super.onInitializeAccessibilityNodeInfo(host, info) + info?.addAction(when (finalState) { + BottomSheetBehavior.STATE_COLLAPSED, + BottomSheetBehavior.STATE_HIDDEN -> AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND + else -> AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE + }) + } + } + companion object { const val demoBounceAnimationLength = 600L const val bounceAnimationLength = 400L