@@ -75,7 +75,7 @@ private typealias ActionKey = SemanticsPropertyKey<AccessibilityAction<() -> Boo
7575 */
7676internal class ComposeAccessible (
7777 semanticsNode : SemanticsNode ,
78- private val controller : AccessibilityController
78+ private val ownerAccessibility : SemanticsOwnerAccessibility
7979) : Accessible,
8080 // Must be a subclass of java.awt.Component because CAccessible only registers property
8181 // listeners with the accessible context if the Accessible is an instance of java.awt.Component
@@ -171,7 +171,7 @@ internal class ComposeAccessible(
171171 get() = semanticsConfig.getOrNull(SemanticsProperties .Selected )
172172
173173 private val density: Density
174- get() = controller .desktopComponent.density
174+ get() = ownerAccessibility .desktopComponent.density
175175
176176 val horizontalScroll
177177 get() = semanticsConfig.getOrNull(SemanticsProperties .HorizontalScrollAxisRange )
@@ -266,60 +266,61 @@ internal class ComposeAccessible(
266266 }
267267
268268 override fun getAccessibleParent (): Accessible ? {
269- val parentNode = semanticsNode.parent ? : return controller.parentAccessible
270- return controller.accessibleByNodeId(parentNode.id)!!
269+ return ownerAccessibility.accessibleParentOf(this @ComposeAccessible)
271270 }
272271
273272 override fun getAccessibleIndexInParent (): Int {
274- val parent = semanticsNode.parent ? : return controller .indexInScene()
273+ val parent = semanticsNode.parent ? : return ownerAccessibility .indexInScene()
275274 return parent.traversalOrderedChildren().indexOfFirst { it.id == semanticsNode.id }
276275 }
277276
278277 override fun getAccessibleComponent (): AccessibleComponent ? {
279278 return this
280279 }
281280
282- // we have to store a reference to AccessibleAction, because AWT itself uses weak
283- // references and GC could delete an object which is, in fact, in use
284- private var accessibleAction: AccessibleAction ? = null
281+ private var accessibleActions: List <Pair <String , ActionKey >>? = null
285282
286- override fun getAccessibleAction (): AccessibleAction ? {
287- val actions = mutableListOf<Pair <String ? , ActionKey >>()
283+ private fun updateAccessibleActions () {
284+ val actions = mutableListOf<Pair <String , ActionKey >>()
288285
289- fun addActionIfExist (key : SemanticsPropertyKey <AccessibilityAction <() - > Boolean >>) {
290- semanticsConfig.getOrNull(key)?.let {
291- actions.add(Pair (it.label, key))
292- }
293- }
294- semanticsConfig.getOrNull(SemanticsActions .OnClick )?.let {
295- // AWT expects "click" label for click actions, at least on macOS...
296- actions.add(Pair (" click" , SemanticsActions .OnClick ))
286+ fun addActionIfExist (
287+ key : SemanticsPropertyKey <AccessibilityAction <() - > Boolean >>,
288+ label : String? = null,
289+ ) {
290+ val action = semanticsConfig.getOrNull(key) ? : return
291+ val label = label ? : action.label ? : return // No point to add an action without a label
292+ actions.add(Pair (label, key))
297293 }
298294
295+ // AWT expects a "click" label for click actions, at least on macOS...
296+ addActionIfExist(SemanticsActions .OnClick , AccessibleAction .CLICK )
299297 addActionIfExist(SemanticsActions .OnLongClick )
300298 addActionIfExist(SemanticsActions .Expand )
301299 addActionIfExist(SemanticsActions .Collapse )
302300 addActionIfExist(SemanticsActions .Dismiss )
303301
304- if (actions.isEmpty()) {
305- return null
306- }
307- accessibleAction = object : AccessibleAction {
308- override fun getAccessibleActionCount (): Int = actions.size
302+ accessibleActions = actions.takeIf { it.isNotEmpty() }
303+ }
309304
310- override fun getAccessibleActionDescription ( i : Int ): String ? {
311- val (label, _) = actions[i]
312- return label
313- }
305+ override fun getAccessibleAction ( ): AccessibleAction ? {
306+ updateAccessibleActions()
307+ return if (accessibleActions == null ) null else this
308+ }
314309
315- override fun doAccessibleAction (i : Int ): Boolean {
316- val (_, actionKey) = actions[i]
317- return semanticsConfig.getOrNull(actionKey)?.let {
318- it.action?.invoke()
319- } ? : false
320- }
321- }
322- return accessibleAction
310+ override fun getAccessibleActionCount (): Int = accessibleActions?.size ? : 0
311+
312+ override fun getAccessibleActionDescription (i : Int ): String? {
313+ val actions = accessibleActions!!
314+ val (label, _) = actions[i]
315+ return label
316+ }
317+
318+ override fun doAccessibleAction (i : Int ): Boolean {
319+ val actions = accessibleActions!!
320+ val (_, actionKey) = actions[i]
321+ return semanticsConfig.getOrNull(actionKey)?.let {
322+ it.action?.invoke()
323+ } ? : false
323324 }
324325
325326 override fun getAccessibleValue (): AccessibleValue ? {
@@ -341,7 +342,7 @@ internal class ComposeAccessible(
341342 val regularChildren = semanticsNode.traversalOrderedChildren()
342343 val childrenSize = regularChildren.size
343344 return if (index < childrenSize) {
344- controller .accessibleByNodeId(regularChildren[index].id)
345+ ownerAccessibility .accessibleByNodeId(regularChildren[index].id)
345346 } else {
346347 auxiliaryChildren[index - childrenSize]
347348 }
@@ -381,7 +382,7 @@ internal class ComposeAccessible(
381382 override fun getAccessibleAt (p : Point ): Accessible ? {
382383 val accessibleChildren = semanticsNode.traversalOrderedChildren()
383384 for (child in accessibleChildren) {
384- val accessible = controller .accessibleByNodeId(child.id) as ? Accessible ? : continue
385+ val accessible = ownerAccessibility .accessibleByNodeId(child.id) as ? Accessible ? : continue
385386 val accessibleComponent = (accessible.accessibleContext as ? AccessibleComponent ) ? : continue
386387 accessibleComponent.getAccessibleAt(p)?.let {
387388 return it
@@ -464,7 +465,7 @@ internal class ComposeAccessible(
464465 }
465466
466467 override fun getAccessibleRole (): AccessibleRole {
467- AccessibilityController .AccessibilityUsage .notifyInUse()
468+ SemanticsOwnerAccessibility .AccessibilityUsage .notifyInUse()
468469 return computeAccessibleRole()
469470 }
470471
@@ -884,20 +885,6 @@ internal class ComposeAccessible(
884885 TODO (" Not yet implemented" )
885886 }
886887
887- // For some reasons JDK's CAccessibility does not call getAccessibleAction
888- // and performs actions on current component itself
889- override fun getAccessibleActionCount (): Int {
890- return accessibleAction?.accessibleActionCount ? : 0
891- }
892-
893- override fun getAccessibleActionDescription (i : Int ): String {
894- return accessibleAction?.getAccessibleActionDescription(i) ? : " "
895- }
896-
897- override fun doAccessibleAction (i : Int ): Boolean {
898- return accessibleAction?.doAccessibleAction(i) ? : false
899- }
900-
901888 private fun List<CharSequence>.mergeText () = joinToString(" , " )
902889 }
903890}
0 commit comments