Home | History | Annotate | Download | only in accessibility
      1 // Copyright (c) 2012 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/accessibility/accessibility_extension_api.h"
      6 
      7 #include "base/json/json_writer.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/values.h"
     10 #include "chrome/browser/accessibility/accessibility_extension_api_constants.h"
     11 #include "chrome/browser/chrome_notification_types.h"
     12 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
     13 #include "chrome/browser/extensions/event_router.h"
     14 #include "chrome/browser/extensions/extension_system.h"
     15 #include "chrome/browser/extensions/extension_tab_util.h"
     16 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
     17 #include "chrome/browser/infobars/infobar_delegate.h"
     18 #include "chrome/browser/infobars/infobar_service.h"
     19 #include "chrome/browser/profiles/profile.h"
     20 #include "content/public/browser/browser_accessibility_state.h"
     21 #include "content/public/browser/notification_service.h"
     22 #include "extensions/common/error_utils.h"
     23 
     24 namespace keys = extension_accessibility_api_constants;
     25 
     26 // Returns the AccessibilityControlInfo serialized into a JSON string,
     27 // consisting of an array of a single object of type AccessibilityObject,
     28 // as defined in the accessibility extension api's json schema.
     29 scoped_ptr<ListValue> ControlInfoToEventArguments(
     30     const AccessibilityEventInfo* info) {
     31   DictionaryValue* dict = new DictionaryValue();
     32   info->SerializeToDict(dict);
     33 
     34   scoped_ptr<ListValue> args(new ListValue());
     35   args->Append(dict);
     36   return args.Pass();
     37 }
     38 
     39 ExtensionAccessibilityEventRouter*
     40     ExtensionAccessibilityEventRouter::GetInstance() {
     41   return Singleton<ExtensionAccessibilityEventRouter>::get();
     42 }
     43 
     44 ExtensionAccessibilityEventRouter::ExtensionAccessibilityEventRouter()
     45     : enabled_(false) {
     46   registrar_.Add(this,
     47                  chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED,
     48                  content::NotificationService::AllSources());
     49   registrar_.Add(this,
     50                  chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_CLOSED,
     51                  content::NotificationService::AllSources());
     52   registrar_.Add(this,
     53                  chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED,
     54                  content::NotificationService::AllSources());
     55   registrar_.Add(this,
     56                  chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION,
     57                  content::NotificationService::AllSources());
     58   registrar_.Add(this,
     59                  chrome::NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED,
     60                  content::NotificationService::AllSources());
     61   registrar_.Add(this,
     62                  chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED,
     63                  content::NotificationService::AllSources());
     64   registrar_.Add(this,
     65                  chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED,
     66                  content::NotificationService::AllSources());
     67 }
     68 
     69 ExtensionAccessibilityEventRouter::~ExtensionAccessibilityEventRouter() {
     70 }
     71 
     72 void ExtensionAccessibilityEventRouter::Observe(
     73     int type,
     74     const content::NotificationSource& source,
     75     const content::NotificationDetails& details) {
     76   switch (type) {
     77     case chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_OPENED:
     78       OnWindowOpened(
     79           content::Details<const AccessibilityWindowInfo>(details).ptr());
     80       break;
     81     case chrome::NOTIFICATION_ACCESSIBILITY_WINDOW_CLOSED:
     82       OnWindowClosed(
     83           content::Details<const AccessibilityWindowInfo>(details).ptr());
     84       break;
     85     case chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_FOCUSED:
     86       OnControlFocused(
     87           content::Details<const AccessibilityControlInfo>(details).ptr());
     88       break;
     89     case chrome::NOTIFICATION_ACCESSIBILITY_CONTROL_ACTION:
     90       OnControlAction(
     91           content::Details<const AccessibilityControlInfo>(details).ptr());
     92       break;
     93     case chrome::NOTIFICATION_ACCESSIBILITY_TEXT_CHANGED:
     94       OnTextChanged(
     95           content::Details<const AccessibilityControlInfo>(details).ptr());
     96       break;
     97     case chrome::NOTIFICATION_ACCESSIBILITY_MENU_OPENED:
     98       OnMenuOpened(
     99           content::Details<const AccessibilityMenuInfo>(details).ptr());
    100       break;
    101     case chrome::NOTIFICATION_ACCESSIBILITY_MENU_CLOSED:
    102       OnMenuClosed(
    103           content::Details<const AccessibilityMenuInfo>(details).ptr());
    104       break;
    105     default:
    106       NOTREACHED();
    107   }
    108 }
    109 
    110 void ExtensionAccessibilityEventRouter::SetAccessibilityEnabled(bool enabled) {
    111   enabled_ = enabled;
    112 }
    113 
    114 bool ExtensionAccessibilityEventRouter::IsAccessibilityEnabled() const {
    115   return enabled_;
    116 }
    117 
    118 void ExtensionAccessibilityEventRouter::OnWindowOpened(
    119     const AccessibilityWindowInfo* info) {
    120   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    121   DispatchEvent(info->profile(), keys::kOnWindowOpened, args.Pass());
    122 }
    123 
    124 void ExtensionAccessibilityEventRouter::OnWindowClosed(
    125     const AccessibilityWindowInfo* info) {
    126   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    127   DispatchEvent(info->profile(), keys::kOnWindowClosed, args.Pass());
    128 }
    129 
    130 void ExtensionAccessibilityEventRouter::OnControlFocused(
    131     const AccessibilityControlInfo* info) {
    132   last_focused_control_dict_.Clear();
    133   info->SerializeToDict(&last_focused_control_dict_);
    134   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    135   DispatchEvent(info->profile(), keys::kOnControlFocused, args.Pass());
    136 }
    137 
    138 void ExtensionAccessibilityEventRouter::OnControlAction(
    139     const AccessibilityControlInfo* info) {
    140   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    141   DispatchEvent(info->profile(), keys::kOnControlAction, args.Pass());
    142 }
    143 
    144 void ExtensionAccessibilityEventRouter::OnTextChanged(
    145     const AccessibilityControlInfo* info) {
    146   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    147   DispatchEvent(info->profile(), keys::kOnTextChanged, args.Pass());
    148 }
    149 
    150 void ExtensionAccessibilityEventRouter::OnMenuOpened(
    151     const AccessibilityMenuInfo* info) {
    152   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    153   DispatchEvent(info->profile(), keys::kOnMenuOpened, args.Pass());
    154 }
    155 
    156 void ExtensionAccessibilityEventRouter::OnMenuClosed(
    157     const AccessibilityMenuInfo* info) {
    158   scoped_ptr<ListValue> args(ControlInfoToEventArguments(info));
    159   DispatchEvent(info->profile(), keys::kOnMenuClosed, args.Pass());
    160 }
    161 
    162 void ExtensionAccessibilityEventRouter::DispatchEvent(
    163     Profile* profile,
    164     const char* event_name,
    165     scoped_ptr<base::ListValue> event_args) {
    166   if (enabled_ && profile &&
    167       extensions::ExtensionSystem::Get(profile)->event_router()) {
    168     scoped_ptr<extensions::Event> event(new extensions::Event(
    169         event_name, event_args.Pass()));
    170     extensions::ExtensionSystem::Get(profile)->event_router()->
    171         BroadcastEvent(event.Pass());
    172   }
    173 }
    174 
    175 bool AccessibilitySetAccessibilityEnabledFunction::RunImpl() {
    176   bool enabled;
    177   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled));
    178   ExtensionAccessibilityEventRouter::GetInstance()
    179       ->SetAccessibilityEnabled(enabled);
    180   return true;
    181 }
    182 
    183 bool AccessibilitySetNativeAccessibilityEnabledFunction::RunImpl() {
    184   bool enabled;
    185   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(0, &enabled));
    186   if (enabled) {
    187     content::BrowserAccessibilityState::GetInstance()->
    188         EnableAccessibility();
    189   } else {
    190     content::BrowserAccessibilityState::GetInstance()->
    191         DisableAccessibility();
    192   }
    193   return true;
    194 }
    195 
    196 bool AccessibilityGetFocusedControlFunction::RunImpl() {
    197   // Get the serialized dict from the last focused control and return it.
    198   // However, if the dict is empty, that means we haven't seen any focus
    199   // events yet, so return null instead.
    200   ExtensionAccessibilityEventRouter *accessibility_event_router =
    201       ExtensionAccessibilityEventRouter::GetInstance();
    202   DictionaryValue *last_focused_control_dict =
    203       accessibility_event_router->last_focused_control_dict();
    204   if (last_focused_control_dict->size()) {
    205     SetResult(last_focused_control_dict->DeepCopyWithoutEmptyChildren());
    206   } else {
    207     SetResult(Value::CreateNullValue());
    208   }
    209   return true;
    210 }
    211 
    212 bool AccessibilityGetAlertsForTabFunction::RunImpl() {
    213   int tab_id;
    214   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
    215 
    216   TabStripModel* tab_strip = NULL;
    217   content::WebContents* contents = NULL;
    218   int tab_index = -1;
    219   if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
    220                                     NULL, &tab_strip, &contents, &tab_index)) {
    221     error_ = extensions::ErrorUtils::FormatErrorMessage(
    222         extensions::tabs_constants::kTabNotFoundError,
    223         base::IntToString(tab_id));
    224     return false;
    225   }
    226 
    227   ListValue* alerts_value = new ListValue;
    228 
    229   InfoBarService* infobar_service = InfoBarService::FromWebContents(contents);
    230   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
    231     // TODO(hashimoto): Make other kind of alerts available.  crosbug.com/24281
    232     ConfirmInfoBarDelegate* confirm_infobar_delegate =
    233         infobar_service->infobar_at(i)->AsConfirmInfoBarDelegate();
    234     if (confirm_infobar_delegate) {
    235       DictionaryValue* alert_value = new DictionaryValue;
    236       const string16 message_text = confirm_infobar_delegate->GetMessageText();
    237       alert_value->SetString(keys::kMessageKey, message_text);
    238       alerts_value->Append(alert_value);
    239     }
    240   }
    241 
    242   SetResult(alerts_value);
    243   return true;
    244 }
    245