Commit b4514da6 authored by Yuki Awano's avatar Yuki Awano Committed by Commit Bot

Reland: Directly attach ax tree to contents view of focused window

- Remove focus stealer and directly attach ax tree to contents view of
  widget delegate of focused widget.
- Returns contents view of widget delegate as focused view if no view is
  focused.

Bug: 852653
Test: Enable ChromeVox arc native support and confirm that it works.
Change-Id: Ib370a6a2efa11d04211d8dbeae92b95a7e125dfb
Reviewed-on: https://chromium-review.googlesource.com/1117720Reviewed-by: default avatarDavid Reveman <reveman@chromium.org>
Reviewed-by: default avatarDavid Tseng <dtseng@chromium.org>
Commit-Queue: Yuki Awano <yawano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571035}
parent 9e9f14c8
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/views/controls/native/native_view_host.h" #include "ui/views/controls/native/native_view_host.h"
#include "ui/views/widget/widget.h"
using ash::ArcNotificationSurface; using ash::ArcNotificationSurface;
using ash::ArcNotificationSurfaceManager; using ash::ArcNotificationSurfaceManager;
...@@ -263,8 +264,23 @@ void ArcAccessibilityHelperBridge::OnAccessibilityEvent( ...@@ -263,8 +264,23 @@ void ArcAccessibilityHelperBridge::OnAccessibilityEvent(
if (task_id != event_data->task_id) if (task_id != event_data->task_id)
return; return;
tree_source = GetOrCreateFromTaskId(event_data->task_id); tree_source = GetFromTaskId(event_data->task_id);
tree_source->Focus(active_window);
if (!tree_source) {
tree_source = CreateFromTaskId(event_data->task_id);
ui::AXTreeData tree_data;
tree_source->GetTreeData(&tree_data);
exo::Surface* surface =
exo::ShellSurfaceBase::GetMainSurface(active_window);
if (surface) {
views::Widget* widget =
views::Widget::GetWidgetForNativeWindow(active_window);
static_cast<exo::ShellSurfaceBase*>(
widget->widget_delegate()->GetContentsView())
->SetChildAxTreeId(tree_data.tree_id);
}
}
} }
if (!tree_source) if (!tree_source)
...@@ -324,17 +340,18 @@ void ArcAccessibilityHelperBridge::OnNotificationStateChanged( ...@@ -324,17 +340,18 @@ void ArcAccessibilityHelperBridge::OnNotificationStateChanged(
} }
} }
AXTreeSourceArc* ArcAccessibilityHelperBridge::GetOrCreateFromTaskId( AXTreeSourceArc* ArcAccessibilityHelperBridge::GetFromTaskId(int32_t task_id) {
int32_t task_id) {
AXTreeSourceArc* tree_source = nullptr;
auto tree_it = task_id_to_tree_.find(task_id); auto tree_it = task_id_to_tree_.find(task_id);
if (tree_it == task_id_to_tree_.end()) { if (tree_it == task_id_to_tree_.end())
task_id_to_tree_[task_id].reset(new AXTreeSourceArc(this)); return nullptr;
tree_source = task_id_to_tree_[task_id].get();
} else { return tree_it->second.get();
tree_source = tree_it->second.get(); }
}
return tree_source; AXTreeSourceArc* ArcAccessibilityHelperBridge::CreateFromTaskId(
int32_t task_id) {
task_id_to_tree_[task_id].reset(new AXTreeSourceArc(this));
return task_id_to_tree_[task_id].get();
} }
AXTreeSourceArc* ArcAccessibilityHelperBridge::CreateFromNotificationKey( AXTreeSourceArc* ArcAccessibilityHelperBridge::CreateFromNotificationKey(
......
...@@ -115,7 +115,8 @@ class ArcAccessibilityHelperBridge ...@@ -115,7 +115,8 @@ class ArcAccessibilityHelperBridge
void UpdateTreeIdOfNotificationSurface(const std::string& notification_key, void UpdateTreeIdOfNotificationSurface(const std::string& notification_key,
uint32_t tree_id); uint32_t tree_id);
AXTreeSourceArc* GetOrCreateFromTaskId(int32_t task_id); AXTreeSourceArc* GetFromTaskId(int32_t task_id);
AXTreeSourceArc* CreateFromTaskId(int32_t task_id);
AXTreeSourceArc* GetFromNotificationKey(const std::string& notification_key); AXTreeSourceArc* GetFromNotificationKey(const std::string& notification_key);
AXTreeSourceArc* CreateFromNotificationKey( AXTreeSourceArc* CreateFromNotificationKey(
const std::string& notification_key); const std::string& notification_key);
......
...@@ -14,10 +14,12 @@ ...@@ -14,10 +14,12 @@
#include "components/exo/wm_helper.h" #include "components/exo/wm_helper.h"
#include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_enum_util.h"
#include "ui/accessibility/platform/ax_android_constants.h" #include "ui/accessibility/platform/ax_android_constants.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/views/focus/focus_manager.h" #include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace arc { namespace arc {
...@@ -132,37 +134,13 @@ void PopulateAXState(AXNodeInfoData* node, ui::AXNodeData* out_data) { ...@@ -132,37 +134,13 @@ void PopulateAXState(AXNodeInfoData* node, ui::AXNodeData* out_data) {
} }
} }
// This class keeps focus on a |ShellSurface| without interfering with default
// focus management in |ShellSurface|. For example, touch causes the
// |ShellSurface| to lose focus to its ancestor containing View.
class AXTreeSourceArc::FocusStealer : public views::View {
public:
explicit FocusStealer(int32_t id) : id_(id) { set_owned_by_client(); }
void Steal() {
SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
RequestFocus();
}
// views::View overrides.
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
node_data->AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId, id_);
node_data->role = ax::mojom::Role::kClient;
}
private:
const int32_t id_;
DISALLOW_COPY_AND_ASSIGN(FocusStealer);
};
AXTreeSourceArc::AXTreeSourceArc(Delegate* delegate) AXTreeSourceArc::AXTreeSourceArc(Delegate* delegate)
: current_tree_serializer_(new AXTreeArcSerializer(this)), : current_tree_serializer_(new AXTreeArcSerializer(this)),
root_id_(-1), root_id_(-1),
window_id_(-1), window_id_(-1),
focused_node_id_(-1), focused_node_id_(-1),
is_notification_(false), is_notification_(false),
delegate_(delegate), delegate_(delegate) {}
focus_stealer_(new FocusStealer(tree_id())) {}
AXTreeSourceArc::~AXTreeSourceArc() { AXTreeSourceArc::~AXTreeSourceArc() {
Reset(); Reset();
...@@ -243,20 +221,6 @@ void AXTreeSourceArc::NotifyActionResult(const ui::AXActionData& data, ...@@ -243,20 +221,6 @@ void AXTreeSourceArc::NotifyActionResult(const ui::AXActionData& data,
data, result); data, result);
} }
void AXTreeSourceArc::Focus(aura::Window* window) {
if (focus_stealer_->HasFocus())
return;
views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
if (!widget || !widget->GetContentsView())
return;
views::View* view = widget->GetContentsView();
if (!view->Contains(focus_stealer_.get()))
view->AddChildView(focus_stealer_.get());
focus_stealer_->Steal();
}
bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const { bool AXTreeSourceArc::GetTreeData(ui::AXTreeData* data) const {
data->tree_id = tree_id(); data->tree_id = tree_id();
if (focused_node_id_ >= 0) if (focused_node_id_ >= 0)
...@@ -542,25 +506,32 @@ const gfx::Rect AXTreeSourceArc::GetBounds(AXNodeInfoData* node, ...@@ -542,25 +506,32 @@ const gfx::Rect AXTreeSourceArc::GetBounds(AXNodeInfoData* node,
aura::Window* toplevel_window = focused_window->GetToplevelWindow(); aura::Window* toplevel_window = focused_window->GetToplevelWindow();
float scale = toplevel_window->layer()->device_scale_factor(); float scale = toplevel_window->layer()->device_scale_factor();
// When window is maximized, Android content is rendered without considering
// caption bar. When window is not maximized, Android content is rendered
// with considering caption bar. We need to do nothing for the later case.
int caption_bar_offset = 0;
views::Widget* widget = views::Widget* widget =
views::Widget::GetTopLevelWidgetForNativeView(toplevel_window); views::Widget::GetWidgetForNativeView(focused_window);
DCHECK(widget);
DCHECK(widget->widget_delegate());
DCHECK(widget->widget_delegate()->GetContentsView());
const gfx::Rect bounds =
widget->widget_delegate()->GetContentsView()->GetBoundsInScreen();
// Bounds of root node is relative to its container, i.e. contents view
// (ShellSurfaceBase).
node_bounds.Offset(
static_cast<int>(-1.0f * scale * static_cast<float>(bounds.x())),
static_cast<int>(-1.0f * scale * static_cast<float>(bounds.y())));
// On Android side, content is rendered without considering height of
// caption bar, e.g. content is rendered at y:0 instead of y:32 where 32 is
// height of caption bar. Add back height of caption bar here.
if (widget->IsMaximized()) { if (widget->IsMaximized()) {
caption_bar_offset = node_bounds.Offset(
widget->non_client_view()->frame_view()->GetBoundsForClientView().y(); 0, static_cast<int>(scale *
static_cast<float>(widget->non_client_view()
->frame_view()
->GetBoundsForClientView()
.y())));
} }
// Bounds of root node is relative to its container, i.e. focused window.
node_bounds.Offset(
static_cast<int>(-1.0f * scale *
static_cast<float>(toplevel_window->bounds().x())),
static_cast<int>(-1.0f * scale *
static_cast<float>(toplevel_window->bounds().y()) +
scale * static_cast<float>(caption_bar_offset)));
return node_bounds; return node_bounds;
} }
...@@ -637,12 +608,6 @@ void AXTreeSourceArc::Reset() { ...@@ -637,12 +608,6 @@ void AXTreeSourceArc::Reset() {
current_tree_serializer_.reset(new AXTreeArcSerializer(this)); current_tree_serializer_.reset(new AXTreeArcSerializer(this));
root_id_ = -1; root_id_ = -1;
focused_node_id_ = -1; focused_node_id_ = -1;
if (focus_stealer_->parent()) {
views::View* parent = focus_stealer_->parent();
parent->RemoveChildView(focus_stealer_.get());
parent->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
}
focus_stealer_.reset();
extensions::AutomationEventRouter* router = extensions::AutomationEventRouter* router =
extensions::AutomationEventRouter::GetInstance(); extensions::AutomationEventRouter::GetInstance();
if (!router) if (!router)
......
...@@ -120,7 +120,6 @@ class AXTreeSourceArc ...@@ -120,7 +120,6 @@ class AXTreeSourceArc
// A delegate that handles accessibility actions on behalf of this tree. The // A delegate that handles accessibility actions on behalf of this tree. The
// delegate is valid during the lifetime of this tree. // delegate is valid during the lifetime of this tree.
const Delegate* const delegate_; const Delegate* const delegate_;
std::unique_ptr<FocusStealer> focus_stealer_;
std::string package_name_; std::string package_name_;
std::map<mojom::AccessibilityNodeInfoData*, gfx::Rect> std::map<mojom::AccessibilityNodeInfoData*, gfx::Rect>
cached_computed_bounds_; cached_computed_bounds_;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "components/exo/surface.h" #include "components/exo/surface.h"
#include "components/exo/wm_helper.h" #include "components/exo/wm_helper.h"
#include "services/ui/public/interfaces/window_tree_constants.mojom.h" #include "services/ui/public/interfaces/window_tree_constants.mojom.h"
#include "ui/accessibility/ax_node_data.h"
#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h" #include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
...@@ -63,6 +64,8 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kApplicationIdKey, nullptr); ...@@ -63,6 +64,8 @@ DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kApplicationIdKey, nullptr);
// Application Id set by the client. // Application Id set by the client.
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kStartupIdKey, nullptr); DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kStartupIdKey, nullptr);
const int32_t kInvalidChildAxTreeId = -1;
// The accelerator keys used to close ShellSurfaces. // The accelerator keys used to close ShellSurfaces.
const struct { const struct {
ui::KeyboardCode keycode; ui::KeyboardCode keycode;
...@@ -570,6 +573,16 @@ void ShellSurfaceBase::SetStartupId(const char* startup_id) { ...@@ -570,6 +573,16 @@ void ShellSurfaceBase::SetStartupId(const char* startup_id) {
SetStartupId(widget_->GetNativeWindow(), startup_id_); SetStartupId(widget_->GetNativeWindow(), startup_id_);
} }
void ShellSurfaceBase::SetChildAxTreeId(int32_t child_ax_tree_id) {
// We don't expect that child ax tree id is changed once it's set.
DCHECK_EQ(child_ax_tree_id_, kInvalidChildAxTreeId);
DCHECK_NE(child_ax_tree_id, kInvalidChildAxTreeId);
child_ax_tree_id_ = child_ax_tree_id;
this->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
}
void ShellSurfaceBase::Close() { void ShellSurfaceBase::Close() {
if (!close_callback_.is_null()) if (!close_callback_.is_null())
close_callback_.Run(); close_callback_.Run();
...@@ -1044,6 +1057,16 @@ gfx::Size ShellSurfaceBase::GetMaximumSize() const { ...@@ -1044,6 +1057,16 @@ gfx::Size ShellSurfaceBase::GetMaximumSize() const {
return maximum_size_; return maximum_size_;
} }
void ShellSurfaceBase::GetAccessibleNodeData(ui::AXNodeData* node_data) {
node_data->role = ax::mojom::Role::kClient;
if (child_ax_tree_id_ == kInvalidChildAxTreeId)
return;
node_data->AddIntAttribute(ax::mojom::IntAttribute::kChildTreeId,
child_ax_tree_id_);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// aura::WindowObserver overrides: // aura::WindowObserver overrides:
...@@ -1152,8 +1175,10 @@ void ShellSurfaceBase::CreateShellSurfaceWidget( ...@@ -1152,8 +1175,10 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
aura::Window* window = widget_->GetNativeWindow(); aura::Window* window = widget_->GetNativeWindow();
window->SetName("ExoShellSurface"); window->SetName("ExoShellSurface");
// TODO(yawano): This needs to be set to false if TalkBack is handling this
// window.
window->SetProperty(aura::client::kAccessibilityFocusFallsbackToWidgetKey, window->SetProperty(aura::client::kAccessibilityFocusFallsbackToWidgetKey,
false); true);
window->AddChild(host_window()); window->AddChild(host_window());
// Use DESCENDANTS_ONLY event targeting policy for mus/mash. // Use DESCENDANTS_ONLY event targeting policy for mus/mash.
// TODO(https://crbug.com/839521): Revisit after event dispatching code is // TODO(https://crbug.com/839521): Revisit after event dispatching code is
......
...@@ -128,6 +128,9 @@ class ShellSurfaceBase : public SurfaceTreeHost, ...@@ -128,6 +128,9 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// Set the startup ID for the surface. // Set the startup ID for the surface.
void SetStartupId(const char* startup_id); void SetStartupId(const char* startup_id);
// Set the child ax tree ID for the surface.
void SetChildAxTreeId(int32_t child_ax_tree_id);
// Signal a request to close the window. It is up to the implementation to // Signal a request to close the window. It is up to the implementation to
// actually decide to do so though. // actually decide to do so though.
void Close(); void Close();
...@@ -208,6 +211,7 @@ class ShellSurfaceBase : public SurfaceTreeHost, ...@@ -208,6 +211,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
gfx::Size GetMinimumSize() const override; gfx::Size GetMinimumSize() const override;
gfx::Size GetMaximumSize() const override; gfx::Size GetMaximumSize() const override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
// Overridden from aura::WindowObserver: // Overridden from aura::WindowObserver:
void OnWindowBoundsChanged(aura::Window* window, void OnWindowBoundsChanged(aura::Window* window,
...@@ -360,6 +364,7 @@ class ShellSurfaceBase : public SurfaceTreeHost, ...@@ -360,6 +364,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
gfx::Size pending_minimum_size_; gfx::Size pending_minimum_size_;
gfx::Size maximum_size_; gfx::Size maximum_size_;
gfx::Size pending_maximum_size_; gfx::Size pending_maximum_size_;
int32_t child_ax_tree_id_ = -1;
DISALLOW_COPY_AND_ASSIGN(ShellSurfaceBase); DISALLOW_COPY_AND_ASSIGN(ShellSurfaceBase);
}; };
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "ui/views/accessibility/ax_window_obj_wrapper.h" #include "ui/views/accessibility/ax_window_obj_wrapper.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
namespace views { namespace views {
...@@ -168,7 +169,15 @@ View* AXAuraObjCache::GetFocusedView() { ...@@ -168,7 +169,15 @@ View* AXAuraObjCache::GetFocusedView() {
if (focused_window->GetProperty( if (focused_window->GetProperty(
aura::client::kAccessibilityFocusFallsbackToWidgetKey)) { aura::client::kAccessibilityFocusFallsbackToWidgetKey)) {
// If no view is focused, falls back to root view. // If focused widget has non client view, falls back to first child view of
// its client view. We don't expect that non client view gets keyboard
// focus.
if (focused_widget->non_client_view() &&
focused_widget->non_client_view()->client_view() &&
focused_widget->non_client_view()->client_view()->has_children()) {
return focused_widget->non_client_view()->client_view()->child_at(0);
}
return focused_widget->GetRootView(); return focused_widget->GetRootView();
} }
......
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