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 "content/browser/accessibility/browser_accessibility_state_impl.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/timer/timer.h"
     10 #include "content/browser/accessibility/accessibility_mode_helper.h"
     11 #include "content/browser/renderer_host/render_widget_host_impl.h"
     12 #include "content/public/browser/browser_thread.h"
     13 #include "content/public/browser/render_process_host.h"
     14 #include "content/public/browser/render_widget_host_iterator.h"
     15 #include "content/public/common/content_switches.h"
     16 #include "ui/gfx/sys_color_change_listener.h"
     17 
     18 #if defined(OS_WIN)
     19 #include "base/win/windows_version.h"
     20 #endif
     21 
     22 namespace content {
     23 
     24 // Update the accessibility histogram 45 seconds after initialization.
     25 static const int kAccessibilityHistogramDelaySecs = 45;
     26 
     27 // static
     28 BrowserAccessibilityState* BrowserAccessibilityState::GetInstance() {
     29   return BrowserAccessibilityStateImpl::GetInstance();
     30 }
     31 
     32 // static
     33 BrowserAccessibilityStateImpl* BrowserAccessibilityStateImpl::GetInstance() {
     34   return Singleton<BrowserAccessibilityStateImpl,
     35                    LeakySingletonTraits<BrowserAccessibilityStateImpl> >::get();
     36 }
     37 
     38 BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
     39     : BrowserAccessibilityState(),
     40       accessibility_mode_(AccessibilityModeOff) {
     41   ResetAccessibilityModeValue();
     42 #if defined(OS_WIN)
     43   // On Windows, UpdateHistograms calls some system functions with unknown
     44   // runtime, so call it on the file thread to ensure there's no jank.
     45   // Everything in that method must be safe to call on another thread.
     46   BrowserThread::ID update_histogram_thread = BrowserThread::FILE;
     47 #else
     48   // On all other platforms, UpdateHistograms should be called on the main
     49   // thread.
     50   BrowserThread::ID update_histogram_thread = BrowserThread::UI;
     51 #endif
     52 
     53   // We need to AddRef() the leaky singleton so that Bind doesn't
     54   // delete it prematurely.
     55   AddRef();
     56   BrowserThread::PostDelayedTask(
     57       update_histogram_thread, FROM_HERE,
     58       base::Bind(&BrowserAccessibilityStateImpl::UpdateHistograms, this),
     59       base::TimeDelta::FromSeconds(kAccessibilityHistogramDelaySecs));
     60 }
     61 
     62 BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() {
     63 }
     64 
     65 void BrowserAccessibilityStateImpl::OnScreenReaderDetected() {
     66   if (CommandLine::ForCurrentProcess()->HasSwitch(
     67           switches::kDisableRendererAccessibility)) {
     68     return;
     69   }
     70   EnableAccessibility();
     71 }
     72 
     73 void BrowserAccessibilityStateImpl::EnableAccessibility() {
     74   AddAccessibilityMode(AccessibilityModeComplete);
     75 }
     76 
     77 void BrowserAccessibilityStateImpl::DisableAccessibility() {
     78   ResetAccessibilityMode();
     79 }
     80 
     81 void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
     82   accessibility_mode_ = AccessibilityModeOff;
     83 #if defined(OS_WIN)
     84   // On Windows 8, always enable accessibility for editable text controls
     85   // so we can show the virtual keyboard when one is enabled.
     86   if (base::win::GetVersion() >= base::win::VERSION_WIN8 &&
     87       !CommandLine::ForCurrentProcess()->HasSwitch(
     88           switches::kDisableRendererAccessibility)) {
     89     accessibility_mode_ = AccessibilityModeEditableTextOnly;
     90   }
     91 #endif  // defined(OS_WIN)
     92 
     93   if (CommandLine::ForCurrentProcess()->HasSwitch(
     94           switches::kForceRendererAccessibility)) {
     95     accessibility_mode_ = AccessibilityModeComplete;
     96   }
     97 }
     98 
     99 void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
    100   ResetAccessibilityModeValue();
    101 
    102   // Iterate over all RenderWidgetHosts, even swapped out ones in case
    103   // they become active again.
    104   scoped_ptr<RenderWidgetHostIterator> widgets(
    105       RenderWidgetHostImpl::GetAllRenderWidgetHosts());
    106   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
    107     // Ignore processes that don't have a connection, such as crashed tabs.
    108     if (!widget->GetProcess()->HasConnection())
    109       continue;
    110     if (!widget->IsRenderView())
    111       continue;
    112 
    113     RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
    114     rwhi->ResetAccessibilityMode();
    115   }
    116 }
    117 
    118 bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
    119   return ((accessibility_mode_ & AccessibilityModeComplete) ==
    120           AccessibilityModeComplete);
    121 }
    122 
    123 void BrowserAccessibilityStateImpl::AddHistogramCallback(
    124     base::Closure callback) {
    125   histogram_callbacks_.push_back(callback);
    126 }
    127 
    128 void BrowserAccessibilityStateImpl::UpdateHistogramsForTesting() {
    129   UpdateHistograms();
    130 }
    131 
    132 void BrowserAccessibilityStateImpl::UpdateHistograms() {
    133   UpdatePlatformSpecificHistograms();
    134 
    135   for (size_t i = 0; i < histogram_callbacks_.size(); ++i)
    136     histogram_callbacks_[i].Run();
    137 
    138   UMA_HISTOGRAM_BOOLEAN("Accessibility.State", IsAccessibleBrowser());
    139   UMA_HISTOGRAM_BOOLEAN("Accessibility.InvertedColors",
    140                         gfx::IsInvertedColorScheme());
    141   UMA_HISTOGRAM_BOOLEAN("Accessibility.ManuallyEnabled",
    142                         CommandLine::ForCurrentProcess()->HasSwitch(
    143                             switches::kForceRendererAccessibility));
    144 }
    145 
    146 #if !defined(OS_WIN)
    147 void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
    148 }
    149 #endif
    150 
    151 void BrowserAccessibilityStateImpl::AddAccessibilityMode(
    152     AccessibilityMode mode) {
    153   if (CommandLine::ForCurrentProcess()->HasSwitch(
    154           switches::kDisableRendererAccessibility)) {
    155     return;
    156   }
    157 
    158   accessibility_mode_ =
    159       content::AddAccessibilityModeTo(accessibility_mode_, mode);
    160 
    161   AddOrRemoveFromRenderWidgets(mode, true);
    162 }
    163 
    164 void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
    165     AccessibilityMode mode) {
    166   if (CommandLine::ForCurrentProcess()->HasSwitch(
    167           switches::kForceRendererAccessibility) &&
    168       mode == AccessibilityModeComplete) {
    169     return;
    170   }
    171 
    172   accessibility_mode_ =
    173       content::RemoveAccessibilityModeFrom(accessibility_mode_, mode);
    174 
    175   AddOrRemoveFromRenderWidgets(mode, false);
    176 }
    177 
    178 void BrowserAccessibilityStateImpl::AddOrRemoveFromRenderWidgets(
    179     AccessibilityMode mode,
    180     bool add) {
    181   // Iterate over all RenderWidgetHosts, even swapped out ones in case
    182   // they become active again.
    183   scoped_ptr<RenderWidgetHostIterator> widgets(
    184       RenderWidgetHostImpl::GetAllRenderWidgetHosts());
    185   while (RenderWidgetHost* widget = widgets->GetNextHost()) {
    186     // Ignore processes that don't have a connection, such as crashed tabs.
    187     if (!widget->GetProcess()->HasConnection())
    188       continue;
    189     if (!widget->IsRenderView())
    190       continue;
    191 
    192     RenderWidgetHostImpl* rwhi = RenderWidgetHostImpl::From(widget);
    193     if (add)
    194       rwhi->AddAccessibilityMode(mode);
    195     else
    196       rwhi->RemoveAccessibilityMode(mode);
    197   }
    198 }
    199 
    200 }  // namespace content
    201