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 "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/extensions/extension_accessibility_api.h" 12#include "chrome/browser/extensions/extension_accessibility_api_constants.h" 13#include "chrome/browser/extensions/extension_event_router.h" 14#include "chrome/browser/extensions/extension_function_dispatcher.h" 15#include "chrome/browser/extensions/extension_service.h" 16#include "chrome/browser/profiles/profile.h" 17#include "chrome/browser/ui/browser_list.h" 18#include "chrome/browser/ui/browser_window.h" 19#include "chrome/common/extensions/extension.h" 20#include "content/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