extension_accessibility_api.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 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 "chrome/browser/extensions/extension_tabs_module.h"
6
7#include "base/json/json_writer.h"
8#include "base/stl_util-inl.h"
9#include "base/string_util.h"
10#include "base/values.h"
11#include "chrome/browser/browser_list.h"
12#include "chrome/browser/browser_window.h"
13#include "chrome/browser/extensions/extension_accessibility_api.h"
14#include "chrome/browser/extensions/extension_accessibility_api_constants.h"
15#include "chrome/browser/extensions/extension_event_router.h"
16#include "chrome/browser/extensions/extension_function_dispatcher.h"
17#include "chrome/browser/extensions/extension_service.h"
18#include "chrome/browser/profiles/profile.h"
19#include "chrome/common/extensions/extension.h"
20#include "chrome/common/notification_service.h"
21
22namespace keys = extension_accessibility_api_constants;
23
24// Returns the AccessibilityControlInfo serialized into a JSON string,
25// consisting of an array of a single object of type AccessibilityObject,
26// as defined in the accessibility extension api's json schema.
27std::string ControlInfoToJsonString(const AccessibilityControlInfo* info) {
28  ListValue args;
29  DictionaryValue* dict = new DictionaryValue();
30  info->SerializeToDict(dict);
31  args.Append(dict);
32  std::string json_args;
33  base::JSONWriter::Write(&args, false, &json_args);
34  return json_args;
35}
36
37ExtensionAccessibilityEventRouter*
38    ExtensionAccessibilityEventRouter::GetInstance() {
39  return Singleton<ExtensionAccessibilityEventRouter>::get();
40}
41
42ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
43    : enabled_(false) {}
44
45ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
46  STLDeleteElements(&on_enabled_listeners_);
47  STLDeleteElements(&on_disabled_listeners_);
48}
49
50void ExtensionAccessibilityEventRouter::ObserveProfile(Profile* profile) {
51  last_focused_control_dict_.Clear();
52
53  if (registrar_.IsEmpty()) {
54    registrar_.Add(this,
55                   NotificationType::ACCESSIBILITY_WINDOW_OPENED,
56                   NotificationService::AllSources());
57    registrar_.Add(this,
58                   NotificationType::ACCESSIBILITY_WINDOW_CLOSED,
59                   NotificationService::AllSources());
60    registrar_.Add(this,
61                   NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
62                   NotificationService::AllSources());
63    registrar_.Add(this,
64                   NotificationType::ACCESSIBILITY_CONTROL_ACTION,
65                   NotificationService::AllSources());
66    registrar_.Add(this,
67                   NotificationType::ACCESSIBILITY_TEXT_CHANGED,
68                   NotificationService::AllSources());
69    registrar_.Add(this,
70                   NotificationType::ACCESSIBILITY_MENU_OPENED,
71                   NotificationService::AllSources());
72    registrar_.Add(this,
73                   NotificationType::ACCESSIBILITY_MENU_CLOSED,
74                   NotificationService::AllSources());
75  }
76}
77
78void ExtensionAccessibilityEventRouter::Observe(
79    NotificationType type,
80    const NotificationSource& source,
81    const NotificationDetails& details) {
82  switch (type.value) {
83    case NotificationType::ACCESSIBILITY_WINDOW_OPENED:
84      OnWindowOpened(Details<const AccessibilityWindowInfo>(details).ptr());
85      break;
86    case NotificationType::ACCESSIBILITY_WINDOW_CLOSED:
87      OnWindowClosed(Details<const AccessibilityWindowInfo>(details).ptr());
88      break;
89    case NotificationType::ACCESSIBILITY_CONTROL_FOCUSED:
90      OnControlFocused(Details<const AccessibilityControlInfo>(details).ptr());
91      break;
92    case NotificationType::ACCESSIBILITY_CONTROL_ACTION:
93      OnControlAction(Details<const AccessibilityControlInfo>(details).ptr());
94      break;
95    case NotificationType::ACCESSIBILITY_TEXT_CHANGED:
96      OnTextChanged(Details<const AccessibilityControlInfo>(details).ptr());
97      break;
98    case NotificationType::ACCESSIBILITY_MENU_OPENED:
99      OnMenuOpened(Details<const AccessibilityMenuInfo>(details).ptr());
100      break;
101    case NotificationType::ACCESSIBILITY_MENU_CLOSED:
102      OnMenuClosed(Details<const AccessibilityMenuInfo>(details).ptr());
103      break;
104    default:
105      NOTREACHED();
106  }
107}
108
109void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled) {
110  if (enabled_ != enabled) {
111    enabled_ = enabled;
112    if (enabled_) {
113      for (unsigned int i = 0; i < on_enabled_listeners_.size(); i++) {
114        on_enabled_listeners_[i]->Run();
115      }
116    } else {
117      for (unsigned int i = 0; i < on_disabled_listeners_.size(); i++) {
118        on_disabled_listeners_[i]->Run();
119      }
120    }
121  }
122}
123
124bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const {
125  return enabled_;
126}
127
128void ExtensionAccessibilityEventRouter::AddOnEnabledListener(
129    Callback* callback) {
130  on_enabled_listeners_.push_back(callback);
131}
132
133void ExtensionAccessibilityEventRouter::AddOnDisabledListener(
134    Callback* callback) {
135  on_disabled_listeners_.push_back(callback);
136}
137
138void ExtensionAccessibilityEventRouter::OnWindowOpened(
139    const AccessibilityWindowInfo* info) {
140  std::string json_args = ControlInfoToJsonString(info);
141  DispatchEvent(info->profile(), keys::kOnWindowOpened, json_args);
142}
143
144void ExtensionAccessibilityEventRouter::OnWindowClosed(
145    const AccessibilityWindowInfo* info) {
146  std::string json_args = ControlInfoToJsonString(info);
147  DispatchEvent(info->profile(), keys::kOnWindowClosed, json_args);
148}
149
150void ExtensionAccessibilityEventRouter::OnControlFocused(
151    const AccessibilityControlInfo* info) {
152  last_focused_control_dict_.Clear();
153  info->SerializeToDict(&last_focused_control_dict_);
154  std::string json_args = ControlInfoToJsonString(info);
155  DispatchEvent(info->profile(), keys::kOnControlFocused, json_args);
156}
157
158void ExtensionAccessibilityEventRouter::OnControlAction(
159    const AccessibilityControlInfo* info) {
160  std::string json_args = ControlInfoToJsonString(info);
161  DispatchEvent(info->profile(), keys::kOnControlAction, json_args);
162}
163
164void ExtensionAccessibilityEventRouter::OnTextChanged(
165    const AccessibilityControlInfo* info) {
166  std::string json_args = ControlInfoToJsonString(info);
167  DispatchEvent(info->profile(), keys::kOnTextChanged, json_args);
168}
169
170void ExtensionAccessibilityEventRouter::OnMenuOpened(
171    const AccessibilityMenuInfo* info) {
172  std::string json_args = ControlInfoToJsonString(info);
173  DispatchEvent(info->profile(), keys::kOnMenuOpened, json_args);
174}
175
176void ExtensionAccessibilityEventRouter::OnMenuClosed(
177    const AccessibilityMenuInfo* info) {
178  std::string json_args = ControlInfoToJsonString(info);
179  DispatchEvent(info->profile(), keys::kOnMenuClosed, json_args);
180}
181
182void ExtensionAccessibilityEventRouter::DispatchEvent(
183    Profile* profile,
184    const char* event_name,
185    const std::string& json_args) {
186  if (enabled_ && profile && profile->GetExtensionEventRouter()) {
187    profile->GetExtensionEventRouter()->DispatchEventToRenderers(
188        event_name, json_args, NULL, GURL());
189  }
190}
191
192bool SetAccessibilityEnabledFunction::RunImpl() {
193  bool enabled;
194  EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled));
195  ExtensionAccessibilityEventRouter::GetInstance()
196      ->SetAccessibilityEnabled(enabled);
197  return true;
198}
199
200bool GetFocusedControlFunction::RunImpl() {
201  // Get the serialized dict from the last focused control and return it.
202  // However, if the dict is empty, that means we haven't seen any focus
203  // events yet, so return null instead.
204  ExtensionAccessibilityEventRouter *accessibility_event_router =
205      ExtensionAccessibilityEventRouter::GetInstance();
206  DictionaryValue *last_focused_control_dict =
207      accessibility_event_router->last_focused_control_dict();
208  if (last_focused_control_dict->size()) {
209    result_.reset(last_focused_control_dict->DeepCopyWithoutEmptyChildren());
210  } else {
211    result_.reset(Value::CreateNullValue());
212  }
213  return true;
214}
215