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
27class AccessibilityViewsDelegate : public views::ViewsDelegate {
28 public:
29  AccessibilityViewsDelegate() {}
30  virtual ~AccessibilityViewsDelegate() {}
31
32  // Overridden from views::ViewsDelegate:
33  virtual ui::Clipboard* GetClipboard() const { return NULL; }
34  virtual void SaveWindowPlacement(views::Window* window,
35                                   const std::wstring& window_name,
36                                   const gfx::Rect& bounds,
37                                   bool maximized) {
38  }
39  virtual bool GetSavedWindowBounds(views::Window* window,
40                                    const std::wstring& window_name,
41                                    gfx::Rect* bounds) const {
42    return false;
43  }
44  virtual bool GetSavedMaximizedState(views::Window* window,
45                                      const std::wstring& window_name,
46                                      bool* maximized) const {
47    return false;
48  }
49  virtual void NotifyAccessibilityEvent(
50      views::View* view, ui::AccessibilityTypes::Event event_type) {
51    AccessibilityEventRouterViews::GetInstance()->HandleAccessibilityEvent(
52        view, event_type);
53  }
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)
61  virtual HICON GetDefaultWindowIcon() const {
62    return NULL;
63  }
64#endif
65  virtual void AddRef() {}
66  virtual void ReleaseRef() {}
67
68  DISALLOW_COPY_AND_ASSIGN(AccessibilityViewsDelegate);
69};
70
71class AccessibilityWindowDelegate : public views::WindowDelegate {
72 public:
73  explicit AccessibilityWindowDelegate(views::View* contents)
74      : contents_(contents) { }
75
76  virtual void DeleteDelegate() { delete this; }
77
78  virtual views::View* GetContentsView() { return contents_; }
79
80 private:
81  views::View* contents_;
82};
83
84class AccessibilityEventRouterViewsTest
85    : public testing::Test,
86      public NotificationObserver {
87 public:
88  virtual void SetUp() {
89    views::ViewsDelegate::views_delegate = new AccessibilityViewsDelegate();
90    window_delegate_ = NULL;
91  }
92
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
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.
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
125TEST_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