[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
This commit is contained in:
Caitlin Shkuratov
2022-12-09 19:07:18 +00:00
parent 6fdfe2a862
commit 7e7dc9faa1
2 changed files with 36 additions and 6 deletions

View File

@@ -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"/>

View File

@@ -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