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