// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/extension_tabs_module.h" #include "base/json/json_writer.h" #include "base/stl_util-inl.h" #include "base/string_util.h" #include "base/values.h" #include "chrome/browser/extensions/extension_accessibility_api.h" #include "chrome/browser/extensions/extension_accessibility_api_constants.h" #include "chrome/browser/extensions/extension_event_router.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/common/extensions/extension.h" #include "content/common/notification_service.h" namespace keys = extension_accessibility_api_constants; // Returns the AccessibilityControlInfo serialized into a JSON string, // consisting of an array of a single object of type AccessibilityObject, // as defined in the accessibility extension api's json schema. std::string ControlInfoToJsonString(const AccessibilityControlInfo* info) { ListValue args; DictionaryValue* dict = new DictionaryValue(); info->SerializeToDict(dict); args.Append(dict); std::string json_args; base::JSONWriter::Write(&args, false, &json_args); return json_args; } ExtensionAccessibilityEventRouter* ExtensionAccessibilityEventRouter::GetInstance() { return Singleton::get(); } ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter() : enabled_(false) {} ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() { STLDeleteElements(&on_enabled_listeners_); STLDeleteElements(&on_disabled_listeners_); } void ExtensionAccessibilityEventRouter::ObserveProfile(Profile* profile) { last_focused_control_dict_.Clear(); if (registrar_.IsEmpty()) { registrar_.Add(this, NotificationType::ACCESSIBILITY_WINDOW_OPENED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::ACCESSIBILITY_WINDOW_CLOSED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::ACCESSIBILITY_CONTROL_FOCUSED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::ACCESSIBILITY_CONTROL_ACTION, NotificationService::AllSources()); registrar_.Add(this, NotificationType::ACCESSIBILITY_TEXT_CHANGED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::ACCESSIBILITY_MENU_OPENED, NotificationService::AllSources()); registrar_.Add(this, NotificationType::ACCESSIBILITY_MENU_CLOSED, NotificationService::AllSources()); } } void ExtensionAccessibilityEventRouter::Observe( NotificationType type, const NotificationSource& source, const NotificationDetails& details) { switch (type.value) { case NotificationType::ACCESSIBILITY_WINDOW_OPENED: OnWindowOpened(Details(details).ptr()); break; case NotificationType::ACCESSIBILITY_WINDOW_CLOSED: OnWindowClosed(Details(details).ptr()); break; case NotificationType::ACCESSIBILITY_CONTROL_FOCUSED: OnControlFocused(Details(details).ptr()); break; case NotificationType::ACCESSIBILITY_CONTROL_ACTION: OnControlAction(Details(details).ptr()); break; case NotificationType::ACCESSIBILITY_TEXT_CHANGED: OnTextChanged(Details(details).ptr()); break; case NotificationType::ACCESSIBILITY_MENU_OPENED: OnMenuOpened(Details(details).ptr()); break; case NotificationType::ACCESSIBILITY_MENU_CLOSED: OnMenuClosed(Details(details).ptr()); break; default: NOTREACHED(); } } void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled) { if (enabled_ != enabled) { enabled_ = enabled; if (enabled_) { for (unsigned int i = 0; i < on_enabled_listeners_.size(); i++) { on_enabled_listeners_[i]->Run(); } } else { for (unsigned int i = 0; i < on_disabled_listeners_.size(); i++) { on_disabled_listeners_[i]->Run(); } } } } bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const { return enabled_; } void ExtensionAccessibilityEventRouter::AddOnEnabledListener( Callback* callback) { on_enabled_listeners_.push_back(callback); } void ExtensionAccessibilityEventRouter::AddOnDisabledListener( Callback* callback) { on_disabled_listeners_.push_back(callback); } void ExtensionAccessibilityEventRouter::OnWindowOpened( const AccessibilityWindowInfo* info) { std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnWindowOpened, json_args); } void ExtensionAccessibilityEventRouter::OnWindowClosed( const AccessibilityWindowInfo* info) { std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnWindowClosed, json_args); } void ExtensionAccessibilityEventRouter::OnControlFocused( const AccessibilityControlInfo* info) { last_focused_control_dict_.Clear(); info->SerializeToDict(&last_focused_control_dict_); std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnControlFocused, json_args); } void ExtensionAccessibilityEventRouter::OnControlAction( const AccessibilityControlInfo* info) { std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnControlAction, json_args); } void ExtensionAccessibilityEventRouter::OnTextChanged( const AccessibilityControlInfo* info) { std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnTextChanged, json_args); } void ExtensionAccessibilityEventRouter::OnMenuOpened( const AccessibilityMenuInfo* info) { std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnMenuOpened, json_args); } void ExtensionAccessibilityEventRouter::OnMenuClosed( const AccessibilityMenuInfo* info) { std::string json_args = ControlInfoToJsonString(info); DispatchEvent(info->profile(), keys::kOnMenuClosed, json_args); } void ExtensionAccessibilityEventRouter::DispatchEvent( Profile* profile, const char* event_name, const std::string& json_args) { if (enabled_ && profile && profile->GetExtensionEventRouter()) { profile->GetExtensionEventRouter()->DispatchEventToRenderers( event_name, json_args, NULL, GURL()); } } bool SetAccessibilityEnabledFunction::RunImpl() { bool enabled; EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled)); ExtensionAccessibilityEventRouter::GetInstance() ->SetAccessibilityEnabled(enabled); return true; } bool GetFocusedControlFunction::RunImpl() { // Get the serialized dict from the last focused control and return it. // However, if the dict is empty, that means we haven't seen any focus // events yet, so return null instead. ExtensionAccessibilityEventRouter *accessibility_event_router = ExtensionAccessibilityEventRouter::GetInstance(); DictionaryValue *last_focused_control_dict = accessibility_event_router->last_focused_control_dict(); if (last_focused_control_dict->size()) { result_.reset(last_focused_control_dict->DeepCopyWithoutEmptyChildren()); } else { result_.reset(Value::CreateNullValue()); } return true; }