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 22 namespace 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. 27 std::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 37 ExtensionAccessibilityEventRouter* 38 ExtensionAccessibilityEventRouter::GetInstance() { 39 return Singleton<ExtensionAccessibilityEventRouter>::get(); 40 } 41 42 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter() 43 : enabled_(false) {} 44 45 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() { 46 STLDeleteElements(&on_enabled_listeners_); 47 STLDeleteElements(&on_disabled_listeners_); 48 } 49 50 void 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 78 void 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 109 void 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 124 bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const { 125 return enabled_; 126 } 127 128 void ExtensionAccessibilityEventRouter::AddOnEnabledListener( 129 Callback* callback) { 130 on_enabled_listeners_.push_back(callback); 131 } 132 133 void ExtensionAccessibilityEventRouter::AddOnDisabledListener( 134 Callback* callback) { 135 on_disabled_listeners_.push_back(callback); 136 } 137 138 void ExtensionAccessibilityEventRouter::OnWindowOpened( 139 const AccessibilityWindowInfo* info) { 140 std::string json_args = ControlInfoToJsonString(info); 141 DispatchEvent(info->profile(), keys::kOnWindowOpened, json_args); 142 } 143 144 void ExtensionAccessibilityEventRouter::OnWindowClosed( 145 const AccessibilityWindowInfo* info) { 146 std::string json_args = ControlInfoToJsonString(info); 147 DispatchEvent(info->profile(), keys::kOnWindowClosed, json_args); 148 } 149 150 void 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 158 void ExtensionAccessibilityEventRouter::OnControlAction( 159 const AccessibilityControlInfo* info) { 160 std::string json_args = ControlInfoToJsonString(info); 161 DispatchEvent(info->profile(), keys::kOnControlAction, json_args); 162 } 163 164 void ExtensionAccessibilityEventRouter::OnTextChanged( 165 const AccessibilityControlInfo* info) { 166 std::string json_args = ControlInfoToJsonString(info); 167 DispatchEvent(info->profile(), keys::kOnTextChanged, json_args); 168 } 169 170 void ExtensionAccessibilityEventRouter::OnMenuOpened( 171 const AccessibilityMenuInfo* info) { 172 std::string json_args = ControlInfoToJsonString(info); 173 DispatchEvent(info->profile(), keys::kOnMenuOpened, json_args); 174 } 175 176 void ExtensionAccessibilityEventRouter::OnMenuClosed( 177 const AccessibilityMenuInfo* info) { 178 std::string json_args = ControlInfoToJsonString(info); 179 DispatchEvent(info->profile(), keys::kOnMenuClosed, json_args); 180 } 181 182 void 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 192 bool SetAccessibilityEnabledFunction::RunImpl() { 193 bool enabled; 194 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled)); 195 ExtensionAccessibilityEventRouter::GetInstance() 196 ->SetAccessibilityEnabled(enabled); 197 return true; 198 } 199 200 bool 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