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: 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 71 class 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 84 class 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 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