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 22namespace content { 23 24// Update the accessibility histogram 45 seconds after initialization. 25static const int kAccessibilityHistogramDelaySecs = 45; 26 27// static 28BrowserAccessibilityState* BrowserAccessibilityState::GetInstance() { 29 return BrowserAccessibilityStateImpl::GetInstance(); 30} 31 32// static 33BrowserAccessibilityStateImpl* BrowserAccessibilityStateImpl::GetInstance() { 34 return Singleton<BrowserAccessibilityStateImpl, 35 LeakySingletonTraits<BrowserAccessibilityStateImpl> >::get(); 36} 37 38BrowserAccessibilityStateImpl::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 62BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() { 63} 64 65void BrowserAccessibilityStateImpl::OnScreenReaderDetected() { 66 if (CommandLine::ForCurrentProcess()->HasSwitch( 67 switches::kDisableRendererAccessibility)) { 68 return; 69 } 70 EnableAccessibility(); 71} 72 73void BrowserAccessibilityStateImpl::EnableAccessibility() { 74 AddAccessibilityMode(AccessibilityModeComplete); 75} 76 77void BrowserAccessibilityStateImpl::DisableAccessibility() { 78 ResetAccessibilityMode(); 79} 80 81void 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 99void 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 118bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() { 119 return ((accessibility_mode_ & AccessibilityModeComplete) == 120 AccessibilityModeComplete); 121} 122 123void BrowserAccessibilityStateImpl::AddHistogramCallback( 124 base::Closure callback) { 125 histogram_callbacks_.push_back(callback); 126} 127 128void BrowserAccessibilityStateImpl::UpdateHistogramsForTesting() { 129 UpdateHistograms(); 130} 131 132void 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) 147void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() { 148} 149#endif 150 151void 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 164void 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 178void 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