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