Skip to content

Commit

Permalink
Fix accessibility not reporting changes (#842)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-sasha authored Oct 7, 2023
1 parent 5b48791 commit c4b9e67
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,35 +70,35 @@ internal class AccessibilityControllerImpl(
if (entry.value != prev) {
when (entry.key) {
SemanticsProperties.Text -> {
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_TEXT_PROPERTY,
prev, entry.value
)
}

SemanticsProperties.EditableText -> {
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_TEXT_PROPERTY,
prev, entry.value
)
}

SemanticsProperties.TextSelectionRange -> {
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_CARET_PROPERTY,
prev, (entry.value as TextRange).start
)
}

SemanticsProperties.Focused ->
if (entry.value as Boolean) {
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.FOCUSED
)
onFocusReceived(component)
} else {
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_STATE_PROPERTY,
AccessibleState.FOCUSED, null
)
Expand All @@ -107,13 +107,13 @@ internal class AccessibilityControllerImpl(
SemanticsProperties.ToggleableState -> {
when (entry.value as ToggleableState) {
ToggleableState.On ->
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.CHECKED
)

ToggleableState.Off, ToggleableState.Indeterminate ->
component.accessibleContext.firePropertyChange(
component.composeAccessibleContext.firePropertyChange(
ACCESSIBLE_STATE_PROPERTY,
AccessibleState.CHECKED, null
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,23 @@ private typealias ActionKey = SemanticsPropertyKey<AccessibilityAction<() -> Boo
internal class ComposeAccessible(
var semanticsNode: SemanticsNode,
val controller: AccessibilityControllerImpl? = null
) : Accessible {
) : Accessible,
// Must be a subclass of java.awt.Component because CAccessible only registers property
// listeners with the accessible context if the Accessible is an instance of java.awt.Component
// (see constructor of sun.lwawt.macosx.CAccessible), even though there's no reason for it.
// The property change listener is what allows us to update CAccessible when some value changes.
java.awt.Component()
{
private val isNativelyInitialized = AtomicBoolean(false)

val accessibleContext: ComposeAccessibleComponent by lazy { ComposeAccessibleComponent() }
val composeAccessibleContext: ComposeAccessibleComponent by lazy { ComposeAccessibleComponent() }

override fun getAccessibleContext(): AccessibleContext {
// see doc for [nativeInitializeAccessible] for details, why this initialization is needed
if (isNativelyInitialized.compareAndSet(false, true)) {
nativeInitializeAccessible(this)
}
return accessibleContext
return composeAccessibleContext
}

open inner class ComposeAccessibleComponent : AccessibleContext(), AccessibleComponent, AccessibleAction {
Expand Down Expand Up @@ -441,7 +447,7 @@ internal class ComposeAccessible(
}
}

open inner class ComposeAccessibleText() : AccessibleText,
open inner class ComposeAccessibleText : AccessibleText,
AccessibleExtendedText {
override fun getIndexAtPoint(p: Point): Int {
return textLayoutResult!!.getOffsetForPosition(p.toComposeOffset())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@ internal class ComposeSceneAccessible(
val controller = owner.accessibilityController as? AccessibilityControllerImpl
?: continue
val rootAccessible = controller.rootAccessible
val context =
rootAccessible.getAccessibleContext() as? AccessibleComponent
?: continue
val context = rootAccessible.composeAccessibleContext
val accessibleOnPoint = context.getAccessibleAt(p) ?: continue
if (accessibleOnPoint != rootAccessible) {
// TODO: ^ this check produce weird behavior
Expand Down Expand Up @@ -117,19 +115,19 @@ internal class ComposeSceneAccessible(
}

override fun getSize(): Dimension? {
return getMainOwnerAccessibleRoot()?.accessibleContext?.size
return getMainOwnerAccessibleRoot()?.composeAccessibleContext?.size
}

override fun getLocationOnScreen(): Point? {
return getMainOwnerAccessibleRoot()?.accessibleContext?.locationOnScreen
return getMainOwnerAccessibleRoot()?.composeAccessibleContext?.locationOnScreen
}

override fun getLocation(): Point? {
return getMainOwnerAccessibleRoot()?.accessibleContext?.location
return getMainOwnerAccessibleRoot()?.composeAccessibleContext?.location
}

override fun getBounds(): Rectangle? {
return getMainOwnerAccessibleRoot()?.accessibleContext?.bounds
return getMainOwnerAccessibleRoot()?.composeAccessibleContext?.bounds
}

override fun isShowing(): Boolean = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ class AccessibilityTest {
}

val node = rule.onNodeWithTag("text").fetchSemanticsNode()
val accessibleNode = ComposeAccessible(node)
val accessibleText = accessibleNode.accessibleContext.accessibleText!!
val accessibleContext = ComposeAccessible(node).accessibleContext
val accessibleText = accessibleContext.accessibleText!!
assertEquals(22, accessibleText.charCount)

assertEquals("H", accessibleText.getAtIndex(AccessibleText.CHARACTER, 0))
Expand Down Expand Up @@ -128,8 +128,8 @@ class AccessibilityTest {
}

private fun SemanticsNodeInteraction.assertHasAccessibleRole(role: AccessibleRole) {
val accessible = ComposeAccessible(fetchSemanticsNode())
assertThat(accessible.accessibleContext.accessibleRole).isEqualTo(role)
val accessibleContext = ComposeAccessible(fetchSemanticsNode()).accessibleContext
assertThat(accessibleContext.accessibleRole).isEqualTo(role)
}

}

0 comments on commit c4b9e67

Please sign in to comment.