diff options
Diffstat (limited to 'chrome/browser/ui/ash')
8 files changed, 500 insertions, 0 deletions
diff --git a/chrome/browser/ui/ash/accessibility/OWNERS b/chrome/browser/ui/ash/accessibility/OWNERS new file mode 100644 index 0000000..11e8fd8 --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/OWNERS @@ -0,0 +1,2 @@ +dmazzoni@chromium.org +dtseng@chromium.org diff --git a/chrome/browser/ui/ash/accessibility/automation_manager_views.cc b/chrome/browser/ui/ash/accessibility/automation_manager_views.cc new file mode 100644 index 0000000..92c8085 --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/automation_manager_views.cc @@ -0,0 +1,85 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/accessibility/automation_manager_views.h" + +#include <vector> + +#include "base/memory/singleton.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/api/automation_internal/automation_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "content/public/browser/ax_event_notification_details.h" +#include "ui/views/accessibility/ax_aura_obj_cache.h" +#include "ui/views/accessibility/ax_aura_obj_wrapper.h" +#include "ui/views/view.h" +#include "ui/views/widget/widget.h" + +// static +AutomationManagerViews* AutomationManagerViews::GetInstance() { + return Singleton<AutomationManagerViews>::get(); +} + +void AutomationManagerViews::Enable() { + enabled_ = true; + if (current_tree_serializer_.get()) + current_tree_serializer_->Reset(); +} + +void AutomationManagerViews::Disable() { + enabled_ = false; + current_tree_serializer_->Reset(); +} + +void AutomationManagerViews::HandleEvent(Profile* profile, + views::View* view, + ui::AXEvent event_type) { + if (!enabled_) { + return; + } + + // TODO(dtseng): Events should only be delivered to extensions with the + // desktop permission. + views::Widget* widget = view->GetWidget(); + if (!widget) + return; + + if (!profile && g_browser_process->profile_manager()) { + profile = g_browser_process->profile_manager()->GetLastUsedProfile(); + } + if (!profile) { + LOG(WARNING) << "Accessibility notification but no profile"; + return; + } + + if (!current_tree_.get()) { + current_tree_.reset(new AXTreeSourceViews()); + current_tree_serializer_.reset( + new ui::AXTreeSerializer<views::AXAuraObjWrapper*>( + current_tree_.get())); + } + + ui::AXTreeUpdate out_update; + views::AXAuraObjWrapper* aura_obj = + views::AXAuraObjCache::GetInstance()->GetOrCreate(view); + current_tree_serializer_->SerializeChanges(aura_obj, &out_update); + + // Route this event to special process/routing ids recognized by the + // Automation API as the desktop tree. + // TODO(dtseng): Would idealy define these special desktop constants in idl. + content::AXEventNotificationDetails detail(out_update.nodes, + event_type, + aura_obj->GetID(), + 0, /* process_id */ + 0 /* routing_id */); + std::vector<content::AXEventNotificationDetails> details; + details.push_back(detail); + extensions::automation_util::DispatchAccessibilityEventsToAutomation( + details, profile); +} + +AutomationManagerViews::AutomationManagerViews() : enabled_(false) {} + +AutomationManagerViews:: ~AutomationManagerViews() {} diff --git a/chrome/browser/ui/ash/accessibility/automation_manager_views.h b/chrome/browser/ui/ash/accessibility/automation_manager_views.h new file mode 100644 index 0000000..af34ff7 --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/automation_manager_views.h @@ -0,0 +1,60 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AUTOMATION_MANAGER_VIEWS_H_ +#define CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AUTOMATION_MANAGER_VIEWS_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" + +#include "chrome/browser/ui/ash/accessibility/ax_tree_source_views.h" +#include "ui/accessibility/ax_tree_serializer.h" + +template <typename T> struct DefaultSingletonTraits; + +class Profile; + +namespace views { +class AXAuraObjWrapper; +class View; +} // namespace views + +// Manages a tree of automation nodes. +class AutomationManagerViews { + public: + // Get the single instance of this class. + static AutomationManagerViews* GetInstance(); + + // Enable automation support for views. + void Enable(); + + // Disable automation support for views. + void Disable(); + + // Handle an event fired upon a |View|. + void HandleEvent(Profile* profile, views::View* view, ui::AXEvent event_type); + + private: + friend struct DefaultSingletonTraits<AutomationManagerViews>; + + AutomationManagerViews(); + ~AutomationManagerViews(); + + // Whether Views-based automation is enabled. + bool enabled_; + + // Holds the active views-based accessibility tree. A tree currently consists + // of all views descendant to a |Widget| (see |AXTreeSourceViews|). + // A tree becomes active when an event is fired on a descendant view. + scoped_ptr <AXTreeSourceViews> current_tree_; + + // Serializes incremental updates on the currently active tree + // |current_tree_|. + scoped_ptr<ui::AXTreeSerializer<views::AXAuraObjWrapper*> > + current_tree_serializer_; + + DISALLOW_COPY_AND_ASSIGN(AutomationManagerViews); +}; + +#endif // CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AUTOMATION_MANAGER_VIEWS_H_ diff --git a/chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.cc b/chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.cc new file mode 100644 index 0000000..39a5b8d --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.cc @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.h" + +#include "ash/shell.h" +#include "ui/accessibility/ax_node_data.h" +#include "ui/accessibility/ax_view_state.h" +#include "ui/aura/window.h" +#include "ui/views/accessibility/ax_aura_obj_cache.h" + +AXRootObjWrapper::AXRootObjWrapper(int32 id) : id_(id) { +} + +AXRootObjWrapper::~AXRootObjWrapper() {} + +bool AXRootObjWrapper::HasChild(views::AXAuraObjWrapper* child) { + std::vector<views::AXAuraObjWrapper*> children; + GetChildren(&children); + return std::find(children.begin(), children.end(), child) != children.end(); +} + +views::AXAuraObjWrapper* AXRootObjWrapper::GetParent() { + return NULL; +} + +void AXRootObjWrapper::GetChildren( + std::vector<views::AXAuraObjWrapper*>* out_children) { + // Only on ash is there a notion of a root with children. + aura::Window::Windows children = + ash::Shell::GetInstance()->GetAllRootWindows(); + for (size_t i = 0; i < children.size(); ++i) { + out_children->push_back( + views::AXAuraObjCache::GetInstance()->GetOrCreate(children[i])); + } +} + +void AXRootObjWrapper::Serialize(ui::AXNodeData* out_node_data) { + out_node_data->id = id_; + out_node_data->role = ui::AX_ROLE_DESKTOP; + // TODO(dtseng): Apply a richer set of states. + out_node_data->state = 0; +} + +int32 AXRootObjWrapper::GetID() { + return id_; +} diff --git a/chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.h b/chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.h new file mode 100644 index 0000000..d75c377 --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.h @@ -0,0 +1,32 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AX_ROOT_OBJ_WRAPPER_H_ +#define CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AX_ROOT_OBJ_WRAPPER_H_ + +#include "base/basictypes.h" +#include "ui/views/accessibility/ax_aura_obj_wrapper.h" + +class AXRootObjWrapper : public views::AXAuraObjWrapper { + public: + explicit AXRootObjWrapper(int32 id); + virtual ~AXRootObjWrapper(); + + // Convenience method to check for existence of a child. + bool HasChild(views::AXAuraObjWrapper* child); + + // views::AXAuraObjWrapper overrides. + virtual views::AXAuraObjWrapper* GetParent() OVERRIDE; + virtual void GetChildren( + std::vector<views::AXAuraObjWrapper*>* out_children) OVERRIDE; + virtual void Serialize(ui::AXNodeData* out_node_data) OVERRIDE; + virtual int32 GetID() OVERRIDE; + + private: + int32 id_; + + DISALLOW_COPY_AND_ASSIGN(AXRootObjWrapper); +}; + +#endif // CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AX_ROOT_OBJ_WRAPPER_H_ diff --git a/chrome/browser/ui/ash/accessibility/ax_tree_source_views.cc b/chrome/browser/ui/ash/accessibility/ax_tree_source_views.cc new file mode 100644 index 0000000..820310a --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/ax_tree_source_views.cc @@ -0,0 +1,85 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/ash/accessibility/ax_tree_source_views.h" + +#include <vector> + +#include "ui/views/accessibility/ax_aura_obj_cache.h" +#include "ui/views/accessibility/ax_aura_obj_wrapper.h" + +using views::AXAuraObjCache; +using views::AXAuraObjWrapper; + +AXTreeSourceViews::AXTreeSourceViews() { + root_.reset( + new AXRootObjWrapper(AXAuraObjCache::GetInstance()->GetNextID())); +} + +AXTreeSourceViews::~AXTreeSourceViews() { + root_.reset(); +} + +AXAuraObjWrapper* AXTreeSourceViews::GetRoot() const { + return root_.get(); +} + +AXAuraObjWrapper* AXTreeSourceViews::GetFromId(int32 id) const { + if (id == root_->GetID()) + return root_.get(); + return AXAuraObjCache::GetInstance()->Get(id); +} + +int32 AXTreeSourceViews::GetId(AXAuraObjWrapper* node) const { + return node->GetID(); +} + +void AXTreeSourceViews::GetChildren(AXAuraObjWrapper* node, + std::vector<AXAuraObjWrapper*>* out_children) const { + node->GetChildren(out_children); +} + +AXAuraObjWrapper* AXTreeSourceViews::GetParent(AXAuraObjWrapper* node) const { + AXAuraObjWrapper* parent = node->GetParent(); + if (!parent && root_->HasChild(node)) + parent = root_.get(); + return parent; +} + +bool AXTreeSourceViews::IsValid(AXAuraObjWrapper* node) const { + return node && node->GetID() != -1; +} + +bool AXTreeSourceViews::IsEqual(AXAuraObjWrapper* node1, + AXAuraObjWrapper* node2) const { + if (!node1 || !node2) + return false; + + return node1->GetID() == node2->GetID() && node1->GetID() != -1; +} + +AXAuraObjWrapper* AXTreeSourceViews::GetNull() const { + return NULL; +} + +void AXTreeSourceViews::SerializeNode( + AXAuraObjWrapper* node, ui::AXNodeData* out_data) const { + node->Serialize(out_data); +} + +std::string AXTreeSourceViews::ToString( + AXAuraObjWrapper* root, std::string prefix) { + ui::AXNodeData data; + root->Serialize(&data); + std::string output = prefix + data.ToString() + '\n'; + + std::vector<AXAuraObjWrapper*> children; + root->GetChildren(&children); + + prefix += prefix[0]; + for (size_t i = 0; i < children.size(); ++i) + output += ToString(children[i], prefix); + + return output; +} diff --git a/chrome/browser/ui/ash/accessibility/ax_tree_source_views.h b/chrome/browser/ui/ash/accessibility/ax_tree_source_views.h new file mode 100644 index 0000000..5a1a6d0 --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/ax_tree_source_views.h @@ -0,0 +1,51 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_ +#define CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/ash/accessibility/ax_root_obj_wrapper.h" +#include "ui/accessibility/ax_tree_source.h" + +namespace views { +class AXAuraObjWrapper; +} // namespace views + +// This class exposes the views hierarchy as an accessibility tree permitting +// use with other accessibility classes. +class AXTreeSourceViews + : public ui::AXTreeSource<views::AXAuraObjWrapper*> { + public: + AXTreeSourceViews(); + virtual ~AXTreeSourceViews(); + + // AXTreeSource implementation. + virtual views::AXAuraObjWrapper* GetRoot() const OVERRIDE; + virtual views::AXAuraObjWrapper* GetFromId(int32 id) const OVERRIDE; + virtual int32 GetId(views::AXAuraObjWrapper* node) const OVERRIDE; + virtual void GetChildren(views::AXAuraObjWrapper* node, + std::vector<views::AXAuraObjWrapper*>* out_children) const OVERRIDE; + virtual views::AXAuraObjWrapper* GetParent( + views::AXAuraObjWrapper* node) const OVERRIDE; + virtual bool IsValid(views::AXAuraObjWrapper* node) const OVERRIDE; + virtual bool IsEqual(views::AXAuraObjWrapper* node1, + views::AXAuraObjWrapper* node2) const OVERRIDE; + virtual views::AXAuraObjWrapper* GetNull() const OVERRIDE; + virtual void SerializeNode( + views::AXAuraObjWrapper* node, ui::AXNodeData* out_data) const OVERRIDE; + + // Useful for debugging. + std::string ToString(views::AXAuraObjWrapper* root, std::string prefix); + + private: + scoped_ptr<AXRootObjWrapper> root_; + + DISALLOW_COPY_AND_ASSIGN(AXTreeSourceViews); +}; + +#endif // CHROME_BROWSER_UI_ASH_ACCESSIBILITY_AX_TREE_SOURCE_VIEWS_H_ diff --git a/chrome/browser/ui/ash/accessibility/ax_tree_source_views_unittest.cc b/chrome/browser/ui/ash/accessibility/ax_tree_source_views_unittest.cc new file mode 100644 index 0000000..b1d2570 --- /dev/null +++ b/chrome/browser/ui/ash/accessibility/ax_tree_source_views_unittest.cc @@ -0,0 +1,137 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "ash/test/ash_test_base.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/ash/accessibility/ax_tree_source_views.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/accessibility/ax_enums.h" +#include "ui/accessibility/ax_node.h" +#include "ui/accessibility/ax_serializable_tree.h" +#include "ui/accessibility/ax_tree_serializer.h" +#include "ui/accessibility/ax_tree_update.h" +#include "ui/aura/window.h" +#include "ui/views/accessibility/ax_aura_obj_cache.h" +#include "ui/views/accessibility/ax_aura_obj_wrapper.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/test/views_test_base.h" +#include "ui/views/widget/widget.h" + +using views::AXAuraObjCache; +using views::AXAuraObjWrapper; +using views::Textfield; +using views::View; +using views::Widget; + +// Helper to count the number of nodes in a tree. +size_t GetSize(AXAuraObjWrapper* tree) { + size_t count = 1; + + std::vector<AXAuraObjWrapper*> out_children; + tree->GetChildren(&out_children); + + for (size_t i = 0; i < out_children.size(); ++i) + count += GetSize(out_children[i]); + + return count; +} + +class AXTreeSourceViewsTest : public ash::test::AshTestBase { + public: + AXTreeSourceViewsTest() {} + virtual ~AXTreeSourceViewsTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + + widget_ = new Widget(); + Widget::InitParams init_params(Widget::InitParams::TYPE_POPUP); + init_params.parent = CurrentContext(); + widget_->Init(init_params); + + content_ = new View(); + widget_->SetContentsView(content_); + + textfield_ = new Textfield(); + textfield_->SetText(base::ASCIIToUTF16("Value")); + content_->AddChildView(textfield_); + } + + protected: + Widget* widget_; + View* content_; + Textfield* textfield_; + + private: + DISALLOW_COPY_AND_ASSIGN(AXTreeSourceViewsTest); +}; + +TEST_F(AXTreeSourceViewsTest, Accessors) { + AXTreeSourceViews ax_tree; + ASSERT_TRUE(ax_tree.GetRoot()); + + // ID's should start at 1 and there should be a root. + ASSERT_EQ(1, ax_tree.GetRoot()->GetID()); + + // Grab the content view directly from cache to avoid walking down the tree. + AXAuraObjWrapper* content = + AXAuraObjCache::GetInstance()->GetOrCreate(content_); + std::vector<AXAuraObjWrapper*> content_children; + ax_tree.GetChildren(content, &content_children); + ASSERT_EQ(1U, content_children.size()); + + // Walk down to the text field and assert it is what we expect. + AXAuraObjWrapper* textfield = content_children[0]; + AXAuraObjWrapper* cached_textfield = + AXAuraObjCache::GetInstance()->GetOrCreate(textfield_); + ASSERT_EQ(cached_textfield, textfield); + std::vector<AXAuraObjWrapper*> textfield_children; + ax_tree.GetChildren(textfield, &textfield_children); + ASSERT_EQ(0U, textfield_children.size()); + + ASSERT_EQ(content, textfield->GetParent()); + + // Try walking up the tree to the root. + AXAuraObjWrapper* root_finder = content; + AXAuraObjWrapper* test_root = NULL; + while ((root_finder = ax_tree.GetParent(root_finder))) + test_root = root_finder; + ASSERT_EQ(ax_tree.GetRoot(), test_root); +} + +TEST_F(AXTreeSourceViewsTest, Serialization) { + AXTreeSourceViews ax_tree; + ui::AXTreeSerializer<AXAuraObjWrapper*> ax_serializer(&ax_tree); + ui::AXTreeUpdate out_update; + + // This is the initial serialization. + ax_serializer.SerializeChanges(ax_tree.GetRoot(), &out_update); + + // We should get an update per node. + ASSERT_EQ(GetSize(ax_tree.GetRoot()), out_update.nodes.size()); + + // Try removing some child views and re-adding. + content_->RemoveAllChildViews(false /* delete_children */); + content_->AddChildView(textfield_); + + // Grab the textfield since serialization only walks up the tree (not down + // from root). + AXAuraObjWrapper* textfield_wrapper = + AXAuraObjCache::GetInstance()->GetOrCreate(textfield_); + + // Now, re-serialize. + ui::AXTreeUpdate out_update2; + ax_serializer.SerializeChanges(textfield_wrapper, &out_update2); + + // We should have far fewer updates this time around. + ASSERT_EQ(2U, out_update2.nodes.size()); + ASSERT_EQ(ui::AX_ROLE_CLIENT, + out_update2.nodes[0].role); + + ASSERT_EQ(textfield_wrapper->GetID(), out_update2.nodes[1].id); + ASSERT_EQ(ui::AX_ROLE_TEXT_FIELD, + out_update2.nodes[1].role); +} |