Live update sidebar with click and focus accessibility events

Summary: Lets AX inspector live update the sidebar when a view is clicked (state may change) or accessibility focus changes (previously only updated the sidebar live if it became the focused element).

Differential Revision: D9489376

fbshipit-source-id: 8959f722370ce1d3a622b24c7b049b03f0d662e6
This commit is contained in:
Sara Valderrama
2018-08-24 09:41:35 -07:00
committed by Facebook Github Bot
parent 61258d4b64
commit 364883f661
3 changed files with 56 additions and 32 deletions

View File

@@ -221,7 +221,8 @@ public class InspectorSonarPlugin implements SonarPlugin {
final SonarArray.Builder result = new SonarArray.Builder(); final SonarArray.Builder result = new SonarArray.Builder();
// getNodes called to refresh accessibility focus // 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++) { for (int i = 0, count = ids.length(); i < count; i++) {
final String id = ids.getString(i); final String id = ids.getString(i);
@@ -231,7 +232,7 @@ public class InspectorSonarPlugin implements SonarPlugin {
if (node == null) { if (node == null) {
// some nodes may be null since we are searching through all current and previous known nodes // some nodes may be null since we are searching through all current and previous known nodes
if (forFocusEvent) { if (forAccessibilityEvent) {
continue; continue;
} }
@@ -243,11 +244,11 @@ public class InspectorSonarPlugin implements SonarPlugin {
return; return;
} else { } else {
// only need to get the focused node in this case // always add currently selected node for live updates to the sidebar
if (forFocusEvent) { // also add focused node for updates
if (node.getObject("extraInfo").getBoolean("focused")) { if (forAccessibilityEvent) {
if (id.equals(selected) || node.getObject("extraInfo").getBoolean("focused")) {
result.put(node); result.put(node);
break;
} }
// normal getNodes call, put any nodes in result // normal getNodes call, put any nodes in result

View File

@@ -101,6 +101,12 @@ public class ApplicationDescriptor extends NodeDescriptor<ApplicationWrapper> {
new SonarObject.Builder() new SonarObject.Builder()
.put("isFocus", false) .put("isFocus", false)
.build()); .build());
} else if (eventType == AccessibilityEvent.TYPE_VIEW_CLICKED) {
mConnection.send("axFocusEvent",
new SonarObject.Builder()
.put("isFocus", false)
.put("isClick", true)
.build());
} }
} }

View File

@@ -76,6 +76,7 @@ type UpdateAXElementsArgs = {|
type AXFocusEventResult = {| type AXFocusEventResult = {|
isFocus: boolean, isFocus: boolean,
isClick?: boolean,
|}; |};
type SetRootArgs = {| type SetRootArgs = {|
@@ -89,7 +90,7 @@ type GetNodesResult = {|
type GetNodesOptions = {| type GetNodesOptions = {|
force: boolean, force: boolean,
ax: boolean, ax: boolean,
forFocusEvent?: boolean, forAccessibilityEvent?: boolean,
|}; |};
type TrackArgs = {| type TrackArgs = {|
@@ -519,9 +520,12 @@ export default class Layout extends SonarPlugin<InspectorState> {
}); });
}); });
this.client.subscribe('axFocusEvent', ({isFocus}: AXFocusEventResult) => { this.client.subscribe(
'axFocusEvent',
({isFocus, isClick}: AXFocusEventResult) => {
this.props.logger.track('usage', 'accessibility:focusEvent', { this.props.logger.track('usage', 'accessibility:focusEvent', {
isFocus, isFocus,
isClick,
inAXMode: this.state.inAXMode, inAXMode: this.state.inAXMode,
}); });
@@ -529,26 +533,38 @@ export default class Layout extends SonarPlugin<InspectorState> {
// we don't know which one now has focus // we don't know which one now has focus
const keys = isFocus ? Object.keys(this.state.AXelements) : []; const keys = isFocus ? Object.keys(this.state.AXelements) : [];
// if unfocusing and currently focused element exists, update only the // if unfocusing, update only the focused and selected elements and
// focused element (and only if it is/was loaded in tree) // only if they have been loaded into tree
if (!isFocus) {
if ( if (
!isFocus &&
this.state.AXfocused && this.state.AXfocused &&
this.state.AXelements[this.state.AXfocused] this.state.AXelements[this.state.AXfocused]
) { ) {
keys.push(this.state.AXfocused); keys.push(this.state.AXfocused);
} }
this.getNodes(keys, {force: true, ax: true, forFocusEvent: true}).then( // also update current selected element live, so data shown is not invalid
(elements: Array<Element>) => { 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<Element>) => {
this.dispatchAction({ this.dispatchAction({
elements, elements,
forFocusEvent: true, forFocusEvent: !isClick,
type: 'UpdateAXElements', type: 'UpdateAXElements',
}); });
});
}, },
); );
});
this.client.subscribe( this.client.subscribe(
'invalidateAX', 'invalidateAX',
@@ -668,7 +684,7 @@ export default class Layout extends SonarPlugin<InspectorState> {
ids: Array<ElementID> = [], ids: Array<ElementID> = [],
options: GetNodesOptions, options: GetNodesOptions,
): Promise<Array<Element>> { ): Promise<Array<Element>> {
const {force, ax, forFocusEvent} = options; const {force, ax, forAccessibilityEvent} = options;
if (!force) { if (!force) {
const elems = ax ? this.state.AXelements : this.state.elements; const elems = ax ? this.state.AXelements : this.state.elements;
// always force undefined elements and elements that need to be expanded // always force undefined elements and elements that need to be expanded
@@ -692,7 +708,8 @@ export default class Layout extends SonarPlugin<InspectorState> {
return this.client return this.client
.call(ax ? 'getAXNodes' : 'getNodes', { .call(ax ? 'getAXNodes' : 'getNodes', {
ids, ids,
forFocusEvent, forAccessibilityEvent,
selected: this.state.AXselected,
}) })
.then(({elements}: GetNodesResult) => { .then(({elements}: GetNodesResult) => {
this.props.logger.trackTimeSince(mark, eventName); this.props.logger.trackTimeSince(mark, eventName);