Add focus option to context menu in the accessibility tree
Summary: Allow user to open the context menu on an element in the ax tree and request accessibility focus to that element. If the element is focusable (and talkback or another accessibility service is running), accessibility focus will change to that element, if not, it will not change anything. Differential Revision: D9162382 fbshipit-source-id: 5dda9b87a2cc6eba4130e3feee978b5fa38ac9f1
This commit is contained in:
committed by
Facebook Github Bot
parent
ae0b8f6b53
commit
1fb2c4ee76
@@ -142,6 +142,7 @@ public class InspectorSonarPlugin implements SonarPlugin {
|
||||
connection.receive("getSearchResults", mGetSearchResults);
|
||||
connection.receive("getAXRoot", mGetAXRoot);
|
||||
connection.receive("getAXNodes", mGetAXNodes);
|
||||
connection.receive("onRequestAXFocus", mOnRequestAXFocus);
|
||||
|
||||
if (mExtensionCommands != null) {
|
||||
for (ExtensionCommand extensionCommand : mExtensionCommands) {
|
||||
@@ -260,6 +261,22 @@ public class InspectorSonarPlugin implements SonarPlugin {
|
||||
}
|
||||
};
|
||||
|
||||
final SonarReceiver mOnRequestAXFocus =
|
||||
new MainThreadSonarReceiver(mConnection) {
|
||||
@Override
|
||||
public void onReceiveOnMainThread(final SonarObject params, final SonarResponder responder)
|
||||
throws Exception {
|
||||
final String nodeId = params.getString("id");
|
||||
|
||||
final Object obj = mObjectTracker.get(nodeId);
|
||||
if (obj == null || !(obj instanceof View)) {
|
||||
return;
|
||||
}
|
||||
|
||||
((View) obj).sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
||||
}
|
||||
};
|
||||
|
||||
final SonarReceiver mSetData =
|
||||
new MainThreadSonarReceiver(mConnection) {
|
||||
@Override
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
*/
|
||||
|
||||
import {Component} from 'react';
|
||||
import type {Element, ElementID, ElementSearchResultSet} from 'sonar';
|
||||
import type {
|
||||
Element,
|
||||
ElementID,
|
||||
ElementSearchResultSet,
|
||||
ContextMenuExtension,
|
||||
} from 'sonar';
|
||||
|
||||
export class AXElementsInspector extends Component<{
|
||||
onElementExpanded: (key: ElementID, deep: boolean) => void,
|
||||
@@ -19,6 +24,7 @@ export class AXElementsInspector extends Component<{
|
||||
root: ?ElementID,
|
||||
elements: {[key: ElementID]: Element},
|
||||
useAppSidebar?: boolean,
|
||||
contextMenuExtensions: Array<ContextMenuExtension>,
|
||||
}> {
|
||||
render() {
|
||||
return null;
|
||||
|
||||
@@ -791,6 +791,17 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
||||
});
|
||||
});
|
||||
|
||||
getAXContextMenuExtensions() {
|
||||
return [
|
||||
{
|
||||
label: 'Focus',
|
||||
click: (id: ElementID) => {
|
||||
this.client.send('onRequestAXFocus', {id});
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
onDataValueChanged = (path: Array<string>, value: any) => {
|
||||
const selected = this.state.inAXMode
|
||||
? this.state.AXselected
|
||||
@@ -935,6 +946,7 @@ export default class Layout extends SonarPlugin<InspectorState> {
|
||||
searchResults={null}
|
||||
root={AXroot}
|
||||
elements={AXelements}
|
||||
contextMenuExtensions={this.getAXContextMenuExtensions()}
|
||||
/>
|
||||
) : null}
|
||||
</FlexRow>
|
||||
|
||||
@@ -215,6 +215,7 @@ type ElementsRowProps = {
|
||||
childrenCount: number,
|
||||
onElementHovered: ?(key: ?ElementID) => void,
|
||||
style: ?Object,
|
||||
contextMenuExtensions: Array<ContextMenuExtension>,
|
||||
};
|
||||
|
||||
type ElementsRowState = {|
|
||||
@@ -232,7 +233,7 @@ class ElementsRow extends PureComponent<ElementsRowProps, ElementsRowState> {
|
||||
|
||||
getContextMenu = (): Array<Electron$MenuItemOptions> => {
|
||||
const {props} = this;
|
||||
return [
|
||||
const items = [
|
||||
{
|
||||
type: 'separator',
|
||||
},
|
||||
@@ -249,6 +250,15 @@ class ElementsRow extends PureComponent<ElementsRowProps, ElementsRowState> {
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (const extension of props.contextMenuExtensions) {
|
||||
items.push({
|
||||
label: extension.label,
|
||||
click: () => extension.click(this.props.id),
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
onClick = () => {
|
||||
@@ -390,6 +400,7 @@ type ElementsProps = {|
|
||||
onElementExpanded: (key: ElementID, deep: boolean) => void,
|
||||
onElementHovered: ?(key: ?ElementID) => void,
|
||||
alternateRowColor?: boolean,
|
||||
contextMenuExtensions?: Array<ContextMenuExtension>,
|
||||
|};
|
||||
|
||||
type ElementsState = {|
|
||||
@@ -398,6 +409,11 @@ type ElementsState = {|
|
||||
maxDepth: number,
|
||||
|};
|
||||
|
||||
export type ContextMenuExtension = {|
|
||||
label: string,
|
||||
click: ElementID => void,
|
||||
|};
|
||||
|
||||
export class Elements extends PureComponent<ElementsProps, ElementsState> {
|
||||
static defaultProps = {
|
||||
alternateRowColor: true,
|
||||
@@ -554,6 +570,7 @@ export class Elements extends PureComponent<ElementsProps, ElementsState> {
|
||||
selected,
|
||||
focused,
|
||||
searchResults,
|
||||
contextMenuExtensions,
|
||||
} = this.props;
|
||||
const {flatElements} = this.state;
|
||||
const row = flatElements[index];
|
||||
@@ -593,6 +610,7 @@ export class Elements extends PureComponent<ElementsProps, ElementsState> {
|
||||
elements={elements}
|
||||
childrenCount={childrenCount}
|
||||
style={style}
|
||||
contextMenuExtensions={contextMenuExtensions || []}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -159,6 +159,9 @@ export type {
|
||||
ElementSearchResultSet,
|
||||
} from './components/elements-inspector/ElementsInspector.js';
|
||||
export {Elements} from './components/elements-inspector/elements.js';
|
||||
export type {
|
||||
ContextMenuExtension,
|
||||
} from './components/elements-inspector/elements.js';
|
||||
export {
|
||||
default as ElementsInspector,
|
||||
} from './components/elements-inspector/ElementsInspector.js';
|
||||
|
||||
Reference in New Issue
Block a user