1 // Copyright (c) 2012 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 #ifndef CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_ 6 #define CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_ 7 8 #include <string> 9 10 #include "base/basictypes.h" 11 #include "base/gtest_prod_util.h" 12 #include "base/strings/string16.h" 13 #include "chrome/browser/accessibility/accessibility_events.h" 14 #include "content/public/browser/notification_observer.h" 15 #include "content/public/browser/notification_registrar.h" 16 #include "ui/accessibility/ax_enums.h" 17 18 class Profile; 19 20 template <typename T> struct DefaultSingletonTraits; 21 22 namespace views { 23 class View; 24 } 25 26 // NOTE: This class is part of the Accessibility Extension API, which lets 27 // extensions receive accessibility events. It's distinct from code that 28 // implements platform accessibility APIs like MSAA or ATK. 29 // 30 // Singleton class that adds listeners to many views, then sends an 31 // accessibility notification whenever a relevant event occurs in an 32 // accessible view. 33 // 34 // Views are not accessible by default. When you register a root widget, 35 // that widget and all of its descendants will start sending accessibility 36 // event notifications. You can then override the default behavior for 37 // specific descendants using other methods. 38 // 39 // You can use Profile::PauseAccessibilityEvents to prevent a flurry 40 // of accessibility events when a window is being created or initialized. 41 class AccessibilityEventRouterViews : public content::NotificationObserver { 42 public: 43 // Get the single instance of this class. 44 static AccessibilityEventRouterViews* GetInstance(); 45 46 // Handle an accessibility event generated by a view. 47 void HandleAccessibilityEvent( 48 views::View* view, ui::AXEvent event_type); 49 50 // Handle a menu item being focused (separate because a menu item is 51 // not necessarily its own view). 52 void HandleMenuItemFocused(const base::string16& menu_name, 53 const base::string16& menu_item_name, 54 int item_index, 55 int item_count, 56 bool has_submenu); 57 58 // NotificationObserver implementation. 59 virtual void Observe(int type, 60 const content::NotificationSource& source, 61 const content::NotificationDetails& details) OVERRIDE; 62 63 private: 64 friend struct DefaultSingletonTraits<AccessibilityEventRouterViews>; 65 66 FRIEND_TEST_ALL_PREFIXES(AccessibilityEventRouterViewsTest, 67 TestFocusNotification); 68 FRIEND_TEST_ALL_PREFIXES(AccessibilityEventRouterViewsTest, 69 MenuIndexAndCountForInvisibleMenu); 70 FRIEND_TEST_ALL_PREFIXES(AccessibilityEventRouterViewsTest, 71 AccessibilityFocusableView); 72 73 AccessibilityEventRouterViews(); 74 virtual ~AccessibilityEventRouterViews(); 75 76 // Call DispatchAccessibilityEvent using a view storage id. 77 static void DispatchEventOnViewStorageId( 78 int view_storage_id, 79 ui::AXEvent event); 80 81 // Checks the type of the view and calls one of the more specific 82 // Send*Notification methods, below. 83 void DispatchAccessibilityEvent( 84 views::View* view, 85 ui::AXEvent event); 86 87 // Each of these methods constructs an AccessibilityControlInfo object 88 // and sends a notification of a specific accessibility event. 89 static void SendButtonNotification( 90 views::View* view, 91 ui::AXEvent event, 92 Profile* profile); 93 static void SendStaticTextNotification( 94 views::View* view, 95 ui::AXEvent event, 96 Profile* profile); 97 static void SendLinkNotification( 98 views::View* view, 99 ui::AXEvent event, 100 Profile* profile); 101 static void SendMenuNotification( 102 views::View* view, 103 ui::AXEvent event, 104 Profile* profile); 105 static void SendTabNotification( 106 views::View* view, 107 ui::AXEvent event, 108 Profile* profile); 109 static void SendMenuItemNotification( 110 views::View* view, 111 ui::AXEvent event, 112 Profile* profile); 113 static void SendTreeNotification( 114 views::View* view, 115 ui::AXEvent event, 116 Profile* profile); 117 static void SendTreeItemNotification( 118 views::View* view, 119 ui::AXEvent event, 120 Profile* profile); 121 static void SendTextfieldNotification( 122 views::View* view, 123 ui::AXEvent event, 124 Profile* profile); 125 static void SendComboboxNotification( 126 views::View* view, 127 ui::AXEvent event, 128 Profile* profile); 129 static void SendCheckboxNotification( 130 views::View* view, 131 ui::AXEvent event, 132 Profile* profile); 133 static void SendWindowNotification( 134 views::View* view, 135 ui::AXEvent event, 136 Profile* profile); 137 static void SendSliderNotification( 138 views::View* view, 139 ui::AXEvent event, 140 Profile* profile); 141 static void SendAlertControlNotification( 142 views::View* view, 143 ui::AXEvent event, 144 Profile* profile); 145 146 // Return the name of a view. 147 static std::string GetViewName(views::View* view); 148 149 // Get the context of a view - the name of the enclosing group, toolbar, etc. 150 static std::string GetViewContext(views::View* view); 151 152 // Return a descendant of this view with a given accessible role, if found. 153 static views::View* FindDescendantWithAccessibleRole( 154 views::View* view, 155 ui::AXRole role); 156 157 // Recursively explore all menu items of |menu| and return in |count| 158 // the total number of items, and in |index| the 0-based index of 159 // |item|, if found. Initialize |count| to zero before calling this 160 // method. |index| will be unchanged if the item is not found, so 161 // initialize it to -1 to detect this case. 162 static void RecursiveGetMenuItemIndexAndCount(views::View* menu, 163 views::View* item, 164 int* index, 165 int* count); 166 167 // Recursively explore the subviews and return the text from the first 168 // subview with a role of STATIC_TEXT. 169 static std::string RecursiveGetStaticText(views::View* view); 170 171 // Returns the first ancestor of |view| (including |view|) that is 172 // accessible. 173 static views::View* FindFirstAccessibleAncestor(views::View* view); 174 175 // The profile associated with the most recent window event - used to 176 // figure out where to route a few events that can't be directly traced 177 // to a window with a profile (like menu events). 178 Profile* most_recent_profile_; 179 180 // The most recent accessibility focusable view is stored in view storage 181 // and is used to prevent multiple events from being dispatched on a 182 // hoverable view from its multiple children. This is the id for the most 183 // recent view we put in view storage. 184 const int most_recent_view_id_; 185 186 // Notification registrar so we can clear most_recent_profile_ when a 187 // profile is destroyed. 188 content::NotificationRegistrar registrar_; 189 190 DISALLOW_COPY_AND_ASSIGN(AccessibilityEventRouterViews); 191 }; 192 193 #endif // CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_ACCESSIBILITY_EVENT_ROUTER_VIEWS_H_ 194