diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 7ca42f7d70159..b5ac9405be0c0 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -142,6 +142,9 @@ + + + diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt index 14ba63a2738ff..f37ef828ebdd8 100644 --- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/chipbar/ChipbarCoordinator.kt @@ -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(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(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(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