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
18class Profile;
19
20template <typename T> struct DefaultSingletonTraits;
21
22namespace views {
23class 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.
41class 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