diff --git a/android/src/main/java/com/facebook/sonar/plugins/inspector/InspectorSonarPlugin.java b/android/src/main/java/com/facebook/sonar/plugins/inspector/InspectorSonarPlugin.java index 5396b0a73..384b7c713 100644 --- a/android/src/main/java/com/facebook/sonar/plugins/inspector/InspectorSonarPlugin.java +++ b/android/src/main/java/com/facebook/sonar/plugins/inspector/InspectorSonarPlugin.java @@ -221,7 +221,8 @@ public class InspectorSonarPlugin implements SonarPlugin { final SonarArray.Builder result = new SonarArray.Builder(); // getNodes called to refresh accessibility focus - final boolean forFocusEvent = params.getBoolean("forFocusEvent"); + final boolean forAccessibilityEvent = params.getBoolean("forAccessibilityEvent"); + final String selected = params.getString("selected"); for (int i = 0, count = ids.length(); i < count; i++) { final String id = ids.getString(i); @@ -231,7 +232,7 @@ public class InspectorSonarPlugin implements SonarPlugin { if (node == null) { // some nodes may be null since we are searching through all current and previous known nodes - if (forFocusEvent) { + if (forAccessibilityEvent) { continue; } @@ -243,11 +244,11 @@ public class InspectorSonarPlugin implements SonarPlugin { return; } else { - // only need to get the focused node in this case - if (forFocusEvent) { - if (node.getObject("extraInfo").getBoolean("focused")) { + // always add currently selected node for live updates to the sidebar + // also add focused node for updates + if (forAccessibilityEvent) { + if (id.equals(selected) || node.getObject("extraInfo").getBoolean("focused")) { result.put(node); - break; } // normal getNodes call, put any nodes in result diff --git a/android/src/main/java/com/facebook/sonar/plugins/inspector/descriptors/ApplicationDescriptor.java b/android/src/main/java/com/facebook/sonar/plugins/inspector/descriptors/ApplicationDescriptor.java index da1b7b14e..b07bc4ba7 100644 --- a/android/src/main/java/com/facebook/sonar/plugins/inspector/descriptors/ApplicationDescriptor.java +++ b/android/src/main/java/com/facebook/sonar/plugins/inspector/descriptors/ApplicationDescriptor.java @@ -101,6 +101,12 @@ public class ApplicationDescriptor extends NodeDescriptor { new SonarObject.Builder() .put("isFocus", false) .build()); + } else if (eventType == AccessibilityEvent.TYPE_VIEW_CLICKED) { + mConnection.send("axFocusEvent", + new SonarObject.Builder() + .put("isFocus", false) + .put("isClick", true) + .build()); } } diff --git a/src/plugins/layout/index.js b/src/plugins/layout/index.js index 1d41f79b1..ac20f5f56 100644 --- a/src/plugins/layout/index.js +++ b/src/plugins/layout/index.js @@ -76,6 +76,7 @@ type UpdateAXElementsArgs = {| type AXFocusEventResult = {| isFocus: boolean, + isClick?: boolean, |}; type SetRootArgs = {| @@ -89,7 +90,7 @@ type GetNodesResult = {| type GetNodesOptions = {| force: boolean, ax: boolean, - forFocusEvent?: boolean, + forAccessibilityEvent?: boolean, |}; type TrackArgs = {| @@ -519,36 +520,51 @@ export default class Layout extends SonarPlugin { }); }); - this.client.subscribe('axFocusEvent', ({isFocus}: AXFocusEventResult) => { - this.props.logger.track('usage', 'accessibility:focusEvent', { - isFocus, - inAXMode: this.state.inAXMode, - }); + this.client.subscribe( + 'axFocusEvent', + ({isFocus, isClick}: AXFocusEventResult) => { + this.props.logger.track('usage', 'accessibility:focusEvent', { + isFocus, + isClick, + inAXMode: this.state.inAXMode, + }); - // if focusing, need to update all elements in the tree because - // we don't know which one now has focus - const keys = isFocus ? Object.keys(this.state.AXelements) : []; + // if focusing, need to update all elements in the tree because + // we don't know which one now has focus + const keys = isFocus ? Object.keys(this.state.AXelements) : []; - // if unfocusing and currently focused element exists, update only the - // focused element (and only if it is/was loaded in tree) - if ( - !isFocus && - this.state.AXfocused && - this.state.AXelements[this.state.AXfocused] - ) { - keys.push(this.state.AXfocused); - } + // if unfocusing, update only the focused and selected elements and + // only if they have been loaded into tree + if (!isFocus) { + if ( + this.state.AXfocused && + this.state.AXelements[this.state.AXfocused] + ) { + keys.push(this.state.AXfocused); + } - this.getNodes(keys, {force: true, ax: true, forFocusEvent: true}).then( - (elements: Array) => { + // also update current selected element live, so data shown is not invalid + if ( + this.state.AXselected && + this.state.AXelements[this.state.AXselected] + ) { + keys.push(this.state.AXselected); + } + } + + this.getNodes(keys, { + force: true, + ax: true, + forAccessibilityEvent: true, + }).then((elements: Array) => { this.dispatchAction({ elements, - forFocusEvent: true, + forFocusEvent: !isClick, type: 'UpdateAXElements', }); - }, - ); - }); + }); + }, + ); this.client.subscribe( 'invalidateAX', @@ -668,7 +684,7 @@ export default class Layout extends SonarPlugin { ids: Array = [], options: GetNodesOptions, ): Promise> { - const {force, ax, forFocusEvent} = options; + const {force, ax, forAccessibilityEvent} = options; if (!force) { const elems = ax ? this.state.AXelements : this.state.elements; // always force undefined elements and elements that need to be expanded @@ -692,7 +708,8 @@ export default class Layout extends SonarPlugin { return this.client .call(ax ? 'getAXNodes' : 'getNodes', { ids, - forFocusEvent, + forAccessibilityEvent, + selected: this.state.AXselected, }) .then(({elements}: GetNodesResult) => { this.props.logger.trackTimeSince(mark, eventName);