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() { ...@@ -675,6 +675,7 @@ void AutomationInternalCustomBindings::AddRoutes() {
ROUTE_FUNCTION(GetState); ROUTE_FUNCTION(GetState);
ROUTE_FUNCTION(CreateAutomationPosition); ROUTE_FUNCTION(CreateAutomationPosition);
ROUTE_FUNCTION(GetAccessibilityFocus); ROUTE_FUNCTION(GetAccessibilityFocus);
ROUTE_FUNCTION(SetDesktopID);
#undef ROUTE_FUNCTION #undef ROUTE_FUNCTION
// Bindings that take a Tree ID and return a property of the tree. // Bindings that take a Tree ID and return a property of the tree.
...@@ -1913,26 +1914,33 @@ bool AutomationInternalCustomBindings::GetFocusInternal( ...@@ -1913,26 +1914,33 @@ bool AutomationInternalCustomBindings::GetFocusInternal(
void AutomationInternalCustomBindings::GetFocus( void AutomationInternalCustomBindings::GetFocus(
const v8::FunctionCallbackInfo<v8::Value>& args) { const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 1 || !args[0]->IsString()) { if (args.Length() != 0) {
ThrowInvalidArgumentsException(this); ThrowInvalidArgumentsException(this);
return; return;
} }
ui::AXTreeID tree_id = ui::AXTreeID::FromString( AutomationAXTreeWrapper* desktop_tree =
*v8::String::Utf8Value(args.GetIsolate(), args[0])); GetAutomationAXTreeWrapperFromTreeID(desktop_tree_id_);
AutomationAXTreeWrapper* tree_wrapper = AutomationAXTreeWrapper* focused_wrapper = nullptr;
GetAutomationAXTreeWrapperFromTreeID(tree_id);
if (!tree_wrapper)
return;
AutomationAXTreeWrapper* focused_tree_wrapper = nullptr;
ui::AXNode* focused_node = 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; 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( args.GetReturnValue().Set(
gin::DataObjectBuilder(GetIsolate()) gin::DataObjectBuilder(GetIsolate())
.Set("treeId", focused_tree_wrapper->GetTreeID().ToString()) .Set("treeId", focused_wrapper->GetTreeID().ToString())
.Set("nodeId", focused_node->id()) .Set("nodeId", focused_node->id())
.Build()); .Build());
} }
...@@ -1955,6 +1963,17 @@ void AutomationInternalCustomBindings::GetAccessibilityFocus( ...@@ -1955,6 +1963,17 @@ void AutomationInternalCustomBindings::GetAccessibilityFocus(
.Build()); .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( void AutomationInternalCustomBindings::GetHtmlAttributes(
const v8::FunctionCallbackInfo<v8::Value>& args) { const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = GetIsolate(); v8::Isolate* isolate = GetIsolate();
...@@ -2522,32 +2541,43 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur( ...@@ -2522,32 +2541,43 @@ void AutomationInternalCustomBindings::MaybeSendFocusAndBlur(
bool lost_old_focus = old_node == nullptr; bool lost_old_focus = old_node == nullptr;
// Determine whether there's a focus or blur event and take its event from. // 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; 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) { for (const auto& event : event_bundle.events) {
if (event.event_type == ax::mojom::Event::kBlur || bool is_blur = event.event_type == ax::mojom::Event::kBlur;
event.event_type == ax::mojom::Event::kFocus) { bool is_focus = event.event_type == ax::mojom::Event::kFocus;
if (is_blur || is_focus) {
event_from = event.event_from; event_from = event.event_from;
event_bundle_has_focus_or_blur = true; event_bundle_has_focus_or_blur = true;
break;
} }
if (is_focus)
raw_focus_target_id = event.id;
} }
bool is_from_desktop = tree->IsDesktopTree(); bool is_from_desktop = tree->IsDesktopTree();
if (!event_bundle_has_focus_or_blur && !lost_old_focus && !is_from_desktop) if (!event_bundle_has_focus_or_blur && !lost_old_focus && !is_from_desktop)
return; return;
// Get the root-most tree. AutomationAXTreeWrapper* desktop_tree =
AutomationAXTreeWrapper* root_tree = tree; GetAutomationAXTreeWrapperFromTreeID(desktop_tree_id_);
while ((tree = AutomationAXTreeWrapper::GetParentOfTreeId(
root_tree->GetTreeID())))
root_tree = tree;
ui::AXNode* new_node = nullptr; ui::AXNode* new_node = nullptr;
AutomationAXTreeWrapper* new_wrapper = nullptr; AutomationAXTreeWrapper* new_wrapper = nullptr;
if (!GetFocusInternal(root_tree, &new_wrapper, &new_node)) if (desktop_tree && !GetFocusInternal(desktop_tree, &new_wrapper, &new_node))
return; 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) if (new_wrapper == old_wrapper && new_node == old_node)
return; return;
......
...@@ -202,6 +202,9 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler { ...@@ -202,6 +202,9 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
// accessibility focus. // accessibility focus.
void GetAccessibilityFocus(const v8::FunctionCallbackInfo<v8::Value>& args); 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 // Args: string ax_tree_id, int node_id
// Returns: JS object with a map from html attribute key to value. // Returns: JS object with a map from html attribute key to value.
void GetHtmlAttributes(const v8::FunctionCallbackInfo<v8::Value>& args); void GetHtmlAttributes(const v8::FunctionCallbackInfo<v8::Value>& args);
...@@ -261,6 +264,9 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler { ...@@ -261,6 +264,9 @@ class AutomationInternalCustomBindings : public ObjectBackedNativeHandler {
// as used in ui::AXTree. // as used in ui::AXTree.
ui::AXTreeID accessibility_focused_tree_id_ = ui::AXTreeIDUnknown(); 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); DISALLOW_COPY_AND_ASSIGN(AutomationInternalCustomBindings);
}; };
......
...@@ -18,6 +18,8 @@ var RemoveTreeChangeObserver = ...@@ -18,6 +18,8 @@ var RemoveTreeChangeObserver =
var GetFocusNative = nativeAutomationInternal.GetFocus; var GetFocusNative = nativeAutomationInternal.GetFocus;
var GetAccessibilityFocusNative = var GetAccessibilityFocusNative =
nativeAutomationInternal.GetAccessibilityFocus; nativeAutomationInternal.GetAccessibilityFocus;
var SetDesktopID =
nativeAutomationInternal.SetDesktopID;
/** /**
* A namespace to export utility functions to other files in automation. * A namespace to export utility functions to other files in automation.
...@@ -102,10 +104,12 @@ automationUtil.tabIDToAutomationNode = {}; ...@@ -102,10 +104,12 @@ automationUtil.tabIDToAutomationNode = {};
if (bindingUtil.hasLastError()) { if (bindingUtil.hasLastError()) {
AutomationRootNode.destroy(treeId); AutomationRootNode.destroy(treeId);
desktopId = undefined; desktopId = undefined;
SetDesktopID('');
callback(); callback();
return; return;
} }
desktopId = treeId; desktopId = treeId;
SetDesktopID(desktopId);
desktopTree = AutomationRootNode.getOrCreate(desktopId); desktopTree = AutomationRootNode.getOrCreate(desktopId);
callback(desktopTree); callback(desktopTree);
...@@ -118,10 +122,7 @@ automationUtil.tabIDToAutomationNode = {}; ...@@ -118,10 +122,7 @@ automationUtil.tabIDToAutomationNode = {};
}); });
apiFunctions.setHandleRequest('getFocus', function(callback) { apiFunctions.setHandleRequest('getFocus', function(callback) {
if (desktopId === undefined) var focusedNodeInfo = GetFocusNative();
return;
var focusedNodeInfo = GetFocusNative(desktopId);
if (!focusedNodeInfo) { if (!focusedNodeInfo) {
callback(null); callback(null);
return; 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