Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7e7dc9fa authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[Chipbar] Only request a11y focus if the chipbar has a button.

Any time the chipbar's content description updates, there will be an
a11y announcement, but the view won't get focus.

Fixes: 260941580
Test: display active unlock chip -> verify chip text is announced but
view isn't focused
Test: display ttt chip that isn't succeeded -> verify chip text is
announced but view isn't focused
Test: display ttt success chip -> verify chip view gets focus (and is
announces)
Test: atest ChipbarCoordinatorTest

Change-Id: I28a29966868611d98d40edbd3d59b1073856e0b4
parent 6fdfe2a8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -142,6 +142,9 @@

    <item type="id" name="row_tag_for_content_view" />

    <!-- Chipbar -->
    <item type="id" name="tag_chipbar_info"/>

    <!-- Optional cancel button on Keyguard -->
    <item type="id" name="cancel_button"/>

+33 −6
Original line number Diff line number Diff line
@@ -22,10 +22,13 @@ import android.os.PowerManager
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE
import android.view.View.ACCESSIBILITY_LIVE_REGION_NONE
import android.view.ViewGroup
import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.widget.TextView
import androidx.annotation.IdRes
import com.android.internal.widget.CachingIconView
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
@@ -113,6 +116,8 @@ open class ChipbarCoordinator @Inject constructor(
            }
        )

        currentView.setTag(INFO_TAG, newInfo)

        // Detect falsing touches on the chip.
        parent = currentView.requireViewById(R.id.chipbar_root_view)
        parent.touchHandler = object : Gefingerpoken {
@@ -165,8 +170,11 @@ open class ChipbarCoordinator @Inject constructor(
        } else {
            ""
        }
        currentView.requireViewById<ViewGroup>(R.id.chipbar_inner).contentDescription =
            "$loadedIconDesc${newInfo.text.loadText(context)}"

        val chipInnerView = currentView.getInnerView()
        chipInnerView.contentDescription = "$loadedIconDesc${newInfo.text.loadText(context)}"
        chipInnerView.accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_ASSERTIVE
        maybeGetAccessibilityFocus(newInfo, currentView)

        // ---- Haptics ----
        newInfo.vibrationEffect?.let {
@@ -174,23 +182,37 @@ open class ChipbarCoordinator @Inject constructor(
        }
    }

    private fun maybeGetAccessibilityFocus(info: ChipbarInfo?, view: ViewGroup) {
        // Don't steal focus unless the chipbar has something interactable.
        // (The chipbar is marked as a live region, so its content will be announced whenever the
        // content changes.)
        if (info?.endItem is ChipbarEndItem.Button) {
            view.getInnerView().requestAccessibilityFocus()
        } else {
            view.getInnerView().clearAccessibilityFocus()
        }
    }

    override fun animateViewIn(view: ViewGroup) {
        val chipInnerView = view.requireViewById<ViewGroup>(R.id.chipbar_inner)
        ViewHierarchyAnimator.animateAddition(
            chipInnerView,
            view.getInnerView(),
            ViewHierarchyAnimator.Hotspot.TOP,
            Interpolators.EMPHASIZED_DECELERATE,
            duration = ANIMATION_IN_DURATION,
            includeMargins = true,
            includeFadeIn = true,
            // We can only request focus once the animation finishes.
            onAnimationEnd = { chipInnerView.requestAccessibilityFocus() },
            onAnimationEnd = {
                maybeGetAccessibilityFocus(view.getTag(INFO_TAG) as ChipbarInfo?, view)
            },
        )
    }

    override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
        val innerView = view.getInnerView()
        innerView.accessibilityLiveRegion = ACCESSIBILITY_LIVE_REGION_NONE
        ViewHierarchyAnimator.animateRemoval(
            view.requireViewById<ViewGroup>(R.id.chipbar_inner),
            innerView,
            ViewHierarchyAnimator.Hotspot.TOP,
            Interpolators.EMPHASIZED_ACCELERATE,
            ANIMATION_OUT_DURATION,
@@ -199,6 +221,10 @@ open class ChipbarCoordinator @Inject constructor(
        )
    }

    private fun ViewGroup.getInnerView(): ViewGroup {
        return requireViewById(R.id.chipbar_inner)
    }

    override fun start() {}

    override fun getTouchableRegion(view: View, outRect: Rect) {
@@ -216,3 +242,4 @@ open class ChipbarCoordinator @Inject constructor(

private const val ANIMATION_IN_DURATION = 500L
private const val ANIMATION_OUT_DURATION = 250L
@IdRes private val INFO_TAG = R.id.tag_chipbar_info