Commit 0bb3bf21 authored by David Tseng's avatar David Tseng Committed by Chromium LUCI CQ

Support chrome.automation.getFocus on non-Aura platforms

R=dmazzoni@chromium.org

Test: manual; on Mac, verify chrome.automation.getFocus returns the correct value.
Change-Id: Iff9665c613ebf55920e7bf5afac2033b5abceeda
AX-Relnotes: n/a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2610925
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#840843}
parent cb02c2c5
......@@ -675,6 +675,7 @@ void AutomationInternalCustomBindings::AddRoutes() {
ROUTE_FUNCTION(GetState);
ROUTE_FUNCTION(CreateAutomationPosition);
ROUTE_FUNCTION(GetAccessibilityFocus);
ROUTE_FUNCTION(SetDesktopID);
#undef ROUTE_FUNCTION
// Bindings that take a Tree ID and return a property of the tree.
......@@ -1913,26 +1914,33 @@ bool AutomationInternalCustomBindings::GetFocusInternal(
void AutomationInternalCustomBindings::GetFocus(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 1 || !args[0]->IsString()) {
if (args.Length() != 0) {
ThrowInvalidArgumentsException(this);
return;
}
ui::AXTreeID tree_id = ui::AXTreeID::FromString(
*v8::String::Utf8Value(args.GetIsolate(), args[0]));
AutomationAXTreeWrapper* tree_wrapper =
GetAutomationAXTreeWrapperFromTreeID(tree_id);
if (!tree_wrapper)
return;
AutomationAXTreeWrapper* focused_tree_wrapper = nullptr;
AutomationAXTreeWrapper* desktop_tree =
GetAutomationAXTreeWrapperFromTreeID(desktop_tree_id_);
AutomationAXTreeWrapper* focused_wrapper = nullptr;
ui::AXNode* focused_node = nullptr;
if (!GetFocusInternal(tree_wrapper, &focused_tree_wrapper, &focused_node))
if (desktop_tree &&
!GetFocusInternal(desktop_tree, &focused_wrapper, &focused_node))
return;
if (!desktop_tree) {
focused_wrapper = GetAutomationAXTreeWrapperFromTreeID(focus_tree_id_);
if (!focused_wrapper)
return;
focused_node = focused_wrapper->GetNodeFromTree(
focused_wrapper->GetTreeID(), focus_id_);
if (!focused_node)
return;
}
args.GetReturnValue().Set(
gin::DataObjectBuilder(GetIsolate())
.Set("treeId", focused_tree_wrapper->GetTreeID().ToString())
.Set("treeId", focused_wrapper->GetTreeID().ToString())
.Set("nodeId", focused_node->id())
.Build());
}
......@@ -1955,6 +1963,17 @@ void AutomationInternalCustomBindings::GetAccessibilityFocus(
.Build());
}
void AutomationInternalCustomBindings::SetDesktopID(
const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 1 || !args[0]->IsString()) {
ThrowInvalidArgumentsException(this);
return;
}
desktop_tree_id_ = ui::AXTreeID::FromString(
*v8::String::Utf8Value(args.GetIsolate(), args[0]));
}
void AutomationInternalCustomBindings::GetHtmlAttributes(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = GetIsolate();
......@@ -2522,32 +2541,43 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur(
bool lost_old_focus = old_node == nullptr;
// Determine whether there's a focus or blur event and take its event from.
// Also, save the raw event target (tree + node).
ax::mojom::EventFrom event_from = ax::mojom::EventFrom::kNone;
bool event_bundle_has_focus_or_blur;
ui::AXNodeData::AXID raw_focus_target_id = ui::AXNodeData::kInvalidAXID;
bool event_bundle_has_focus_or_blur = false;
for (const auto& event : event_bundle.events) {
if (event.event_type == ax::mojom::Event::kBlur ||
event.event_type == ax::mojom::Event::kFocus) {
bool is_blur = event.event_type == ax::mojom::Event::kBlur;
bool is_focus = event.event_type == ax::mojom::Event::kFocus;
if (is_blur || is_focus) {
event_from = event.event_from;
event_bundle_has_focus_or_blur = true;
break;
}
if (is_focus)
raw_focus_target_id = event.id;
}
bool is_from_desktop = tree->IsDesktopTree();
if (!event_bundle_has_focus_or_blur && !lost_old_focus && !is_from_desktop)
return;
// Get the root-most tree.
AutomationAXTreeWrapper* root_tree = tree;
while ((tree = AutomationAXTreeWrapper::GetParentOfTreeId(
root_tree->GetTreeID())))
root_tree = tree;
AutomationAXTreeWrapper* desktop_tree =
GetAutomationAXTreeWrapperFromTreeID(desktop_tree_id_);
ui::AXNode* new_node = nullptr;
AutomationAXTreeWrapper* new_wrapper = nullptr;
if (!GetFocusInternal(root_tree, &new_wrapper, &new_node))
if (desktop_tree && !GetFocusInternal(desktop_tree, &new_wrapper, &new_node))
return;
if (!desktop_tree) {
// Can occur if the extension does not have desktop permission,
// chrome.automation.getDesktop has yet to be called, or if this platform
// does not support Aura.
new_wrapper = tree;
new_node = tree->tree()->GetFromId(raw_focus_target_id);
if (!new_node)
return;
}
if (new_wrapper == old_wrapper && new_node == old_node)
return;
......
......@@ -202,6 +202,9 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
// accessibility focus.
void GetAccessibilityFocus(const v8::FunctionCallbackInfo<v8::Value>& args);
// Args: string ax_tree_id.
void SetDesktopID(const v8::FunctionCallbackInfo<v8::Value>& args);
// Args: string ax_tree_id, int node_id
// Returns: JS object with a map from html attribute key to value.
void GetHtmlAttributes(const v8::FunctionCallbackInfo<v8::Value>& args);
......@@ -261,6 +264,9 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
// as used in ui::AXTree.
ui::AXTreeID accessibility_focused_tree_id_ = ui::AXTreeIDUnknown();
// Keeps track of the single desktop tree, if it exists.
ui::AXTreeID desktop_tree_id_ = ui::AXTreeIDUnknown();
DISALLOW_COPY_AND_ASSIGN(AutomationInternalCustomBindings);
};
......
......@@ -18,6 +18,8 @@ var RemoveTreeChangeObserver =
var GetFocusNative = nativeAutomationInternal.GetFocus;
var GetAccessibilityFocusNative =
nativeAutomationInternal.GetAccessibilityFocus;
var SetDesktopID =
nativeAutomationInternal.SetDesktopID;
/**
* A namespace to export utility functions to other files in automation.
......@@ -102,10 +104,12 @@ automationUtil.tabIDToAutomationNode = {};
if (bindingUtil.hasLastError()) {
AutomationRootNode.destroy(treeId);
desktopId = undefined;
SetDesktopID('');
callback();
return;
}
desktopId = treeId;
SetDesktopID(desktopId);
desktopTree = AutomationRootNode.getOrCreate(desktopId);
callback(desktopTree);
......@@ -118,10 +122,7 @@ automationUtil.tabIDToAutomationNode = {};
});
apiFunctions.setHandleRequest('getFocus', function(callback) {
if (desktopId === undefined)
return;
var focusedNodeInfo = GetFocusNative(desktopId);
var focusedNodeInfo = GetFocusNative();
if (!focusedNodeInfo) {
callback(null);
return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment