1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <string>
6
7 #include "base/message_loop.h"
8 #include "base/string_util.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/extensions/extension_accessibility_api.h"
11 #include "chrome/browser/ui/views/accessibility_event_router_views.h"
12 #include "chrome/test/testing_profile.h"
13 #include "content/common/notification_registrar.h"
14 #include "content/common/notification_service.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "views/controls/button/native_button.h"
17 #include "views/layout/grid_layout.h"
18 #include "views/views_delegate.h"
19 #include "views/widget/native_widget.h"
20 #include "views/widget/root_view.h"
21 #include "views/widget/widget.h"
22 #include "views/window/window.h"
23 #include "views/window/window_delegate.h"
24
25 #if defined(TOOLKIT_VIEWS)
26
27 class AccessibilityViewsDelegate : public views::ViewsDelegate {
28 public:
AccessibilityViewsDelegate()29 AccessibilityViewsDelegate() {}
~AccessibilityViewsDelegate()30 virtual ~AccessibilityViewsDelegate() {}
31
32 // Overridden from views::ViewsDelegate:
GetClipboard() const33 virtual ui::Clipboard* GetClipboard() const { return NULL; }
SaveWindowPlacement(views::Window * window,const std::wstring & window_name,const gfx::Rect & bounds,bool maximized)34 virtual void SaveWindowPlacement(views::Window* window,
35 const std::wstring& window_name,
36 const gfx::Rect& bounds,
37 bool maximized) {
38 }
GetSavedWindowBounds(views::Window * window,const std::wstring & window_name,gfx::Rect * bounds) const39 virtual bool GetSavedWindowBounds(views::Window* window,
40 const std::wstring& window_name,
41 gfx::Rect* bounds) const {
42 return false;
43 }
GetSavedMaximizedState(views::Window * window,const std::wstring & window_name,bool * maximized) const44 virtual bool GetSavedMaximizedState(views::Window* window,
45 const std::wstring& window_name,
46 bool* maximized) const {
47 return false;
48 }
NotifyAccessibilityEvent(views::View * view,ui::AccessibilityTypes::Event event_type)49 virtual void NotifyAccessibilityEvent(
50 views::View* view, ui::AccessibilityTypes::Event event_type) {
51 AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent(
52 view, event_type);
53 }
NotifyMenuItemFocused(const std::wstring & menu_name,const std::wstring & menu_item_name,int item_index,int item_count,bool has_submenu)54 virtual void NotifyMenuItemFocused(
55 const std::wstring& menu_name,
56 const std::wstring& menu_item_name,
57 int item_index,
58 int item_count,
59 bool has_submenu) {}
60 #if defined(OS_WIN)
GetDefaultWindowIcon() const61 virtual HICON GetDefaultWindowIcon() const {
62 return NULL;
63 }
64 #endif
AddRef()65 virtual void AddRef() {}
ReleaseRef()66 virtual void ReleaseRef() {}
67
68 DISALLOW_COPY_AND_ASSIGN(AccessibilityViewsDelegate);
69 };
70
71 class AccessibilityWindowDelegate : public views::WindowDelegate {
72 public:
AccessibilityWindowDelegate(views::View * contents)73 explicit AccessibilityWindowDelegate(views::View* contents)
74 : contents_(contents) { }
75
DeleteDelegate()76 virtual void DeleteDelegate() { delete this; }
77
GetContentsView()78 virtual views::View* GetContentsView() { return contents_; }
79
80 private:
81 views::View* contents_;
82 };
83
84 class AccessibilityEventRouterViewsTest
85 : public testing::Test,
86 public NotificationObserver {
87 public:
SetUp()88 virtual void SetUp() {
89 views::ViewsDelegate::views_delegate = new AccessibilityViewsDelegate();
90 window_delegate_ = NULL;
91 }
92
TearDown()93 virtual void TearDown() {
94 delete views::ViewsDelegate::views_delegate;
95 views::ViewsDelegate::views_delegate = NULL;
96 if (window_delegate_)
97 delete window_delegate_;
98 }
99
CreateWindowWithContents(views::View * contents)100 views::Window* CreateWindowWithContents(views::View* contents) {
101 window_delegate_ = new AccessibilityWindowDelegate(contents);
102 return views::Window::CreateChromeWindow(
103 NULL, gfx::Rect(0, 0, 500, 500), window_delegate_);
104 }
105
106 protected:
107 // Implement NotificationObserver::Observe and store information about a
108 // ACCESSIBILITY_CONTROL_FOCUSED event.
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)109 virtual void Observe(NotificationType type,
110 const NotificationSource& source,
111 const NotificationDetails& details) {
112 ASSERT_EQ(type.value, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED);
113 const AccessibilityControlInfo* info =
114 Details<const AccessibilityControlInfo>(details).ptr();
115 focus_event_count_++;
116 last_control_name_ = info->name();
117 }
118
119 MessageLoopForUI message_loop_;
120 int focus_event_count_;
121 std::string last_control_name_;
122 AccessibilityWindowDelegate* window_delegate_;
123 };
124
TEST_F(AccessibilityEventRouterViewsTest,TestFocusNotification)125 TEST_F(AccessibilityEventRouterViewsTest, TestFocusNotification) {
126 const char kButton1ASCII[] = "Button1";
127 const char kButton2ASCII[] = "Button2";
128 const char kButton3ASCII[] = "Button3";
129 const char kButton3NewASCII[] = "Button3New";
130
131 // Create a contents view with 3 buttons.
132 views::View* contents = new views::View();
133 views::NativeButton* button1 = new views::NativeButton(
134 NULL, ASCIIToWide(kButton1ASCII));
135 contents->AddChildView(button1);
136 views::NativeButton* button2 = new views::NativeButton(
137 NULL, ASCIIToWide(kButton2ASCII));
138 contents->AddChildView(button2);
139 views::NativeButton* button3 = new views::NativeButton(
140 NULL, ASCIIToWide(kButton3ASCII));
141 contents->AddChildView(button3);
142
143 // Put the view in a window.
144 views::Window* window = CreateWindowWithContents(contents);
145
146 // Set focus to the first button initially.
147 button1->RequestFocus();
148
149 // Start listening to ACCESSIBILITY_CONTROL_FOCUSED notifications.
150 NotificationRegistrar registrar;
151 registrar.Add(this,
152 NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
153 NotificationService::AllSources());
154
155 // Switch on accessibility event notifications.
156 ExtensionAccessibilityEventRouter* accessibility_event_router =
157 ExtensionAccessibilityEventRouter::GetInstance();
158 accessibility_event_router->SetAccessibilityEnabled(true);
159
160 // Create a profile and associate it with this window.
161 TestingProfile profile;
162 window->AsWidget()->native_widget()->SetNativeWindowProperty(
163 Profile::kProfileKey, &profile);
164
165 // Change the accessible name of button3.
166 button3->SetAccessibleName(ASCIIToUTF16(kButton3NewASCII));
167
168 // Advance focus to the next button and test that we got the
169 // expected notification with the name of button 2.
170 views::FocusManager* focus_manager = contents->GetWidget()->GetFocusManager();
171 focus_event_count_ = 0;
172 focus_manager->AdvanceFocus(false);
173 EXPECT_EQ(1, focus_event_count_);
174 EXPECT_EQ(kButton2ASCII, last_control_name_);
175
176 // Advance to button 3. Expect the new accessible name we assigned.
177 focus_manager->AdvanceFocus(false);
178 EXPECT_EQ(2, focus_event_count_);
179 EXPECT_EQ(kButton3NewASCII, last_control_name_);
180
181 // Advance to button 1 and check the notification.
182 focus_manager->AdvanceFocus(false);
183 EXPECT_EQ(3, focus_event_count_);
184 EXPECT_EQ(kButton1ASCII, last_control_name_);
185 }
186
187 #endif // defined(TOOLKIT_VIEWS)
188