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.
5 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
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"
19 #include "base/win/windows_version.h"
24 // Update the accessibility histogram 45 seconds after initialization.
25 static const int kAccessibilityHistogramDelaySecs
= 45;
28 BrowserAccessibilityState
* BrowserAccessibilityState::GetInstance() {
29 return BrowserAccessibilityStateImpl::GetInstance();
33 BrowserAccessibilityStateImpl
* BrowserAccessibilityStateImpl::GetInstance() {
34 return Singleton
<BrowserAccessibilityStateImpl
,
35 LeakySingletonTraits
<BrowserAccessibilityStateImpl
> >::get();
38 BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
39 : BrowserAccessibilityState(),
40 accessibility_mode_(AccessibilityModeOff
) {
41 ResetAccessibilityModeValue();
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;
48 // On all other platforms, UpdateHistograms should be called on the main
50 BrowserThread::ID update_histogram_thread
= BrowserThread::UI
;
53 // We need to AddRef() the leaky singleton so that Bind doesn't
54 // delete it prematurely.
56 BrowserThread::PostDelayedTask(
57 update_histogram_thread
, FROM_HERE
,
58 base::Bind(&BrowserAccessibilityStateImpl::UpdateHistograms
, this),
59 base::TimeDelta::FromSeconds(kAccessibilityHistogramDelaySecs
));
62 BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() {
65 void BrowserAccessibilityStateImpl::OnScreenReaderDetected() {
66 if (CommandLine::ForCurrentProcess()->HasSwitch(
67 switches::kDisableRendererAccessibility
)) {
70 EnableAccessibility();
73 void BrowserAccessibilityStateImpl::EnableAccessibility() {
74 AddAccessibilityMode(AccessibilityModeComplete
);
77 void BrowserAccessibilityStateImpl::DisableAccessibility() {
78 ResetAccessibilityMode();
81 void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
82 accessibility_mode_
= AccessibilityModeOff
;
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
;
91 #endif // defined(OS_WIN)
93 if (CommandLine::ForCurrentProcess()->HasSwitch(
94 switches::kForceRendererAccessibility
)) {
95 accessibility_mode_
= AccessibilityModeComplete
;
99 void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
100 ResetAccessibilityModeValue();
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())
110 if (!widget
->IsRenderView())
113 RenderWidgetHostImpl
* rwhi
= RenderWidgetHostImpl::From(widget
);
114 rwhi
->ResetAccessibilityMode();
118 bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
119 return ((accessibility_mode_
& AccessibilityModeComplete
) ==
120 AccessibilityModeComplete
);
123 void BrowserAccessibilityStateImpl::AddHistogramCallback(
124 base::Closure callback
) {
125 histogram_callbacks_
.push_back(callback
);
128 void BrowserAccessibilityStateImpl::UpdateHistogramsForTesting() {
132 void BrowserAccessibilityStateImpl::UpdateHistograms() {
133 UpdatePlatformSpecificHistograms();
135 for (size_t i
= 0; i
< histogram_callbacks_
.size(); ++i
)
136 histogram_callbacks_
[i
].Run();
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
));
147 void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
151 void BrowserAccessibilityStateImpl::AddAccessibilityMode(
152 AccessibilityMode mode
) {
153 if (CommandLine::ForCurrentProcess()->HasSwitch(
154 switches::kDisableRendererAccessibility
)) {
158 accessibility_mode_
=
159 content::AddAccessibilityModeTo(accessibility_mode_
, mode
);
161 AddOrRemoveFromRenderWidgets(mode
, true);
164 void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
165 AccessibilityMode mode
) {
166 if (CommandLine::ForCurrentProcess()->HasSwitch(
167 switches::kForceRendererAccessibility
) &&
168 mode
== AccessibilityModeComplete
) {
172 accessibility_mode_
=
173 content::RemoveAccessibilityModeFrom(accessibility_mode_
, mode
);
175 AddOrRemoveFromRenderWidgets(mode
, false);
178 void BrowserAccessibilityStateImpl::AddOrRemoveFromRenderWidgets(
179 AccessibilityMode mode
,
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())
189 if (!widget
->IsRenderView())
192 RenderWidgetHostImpl
* rwhi
= RenderWidgetHostImpl::From(widget
);
194 rwhi
->AddAccessibilityMode(mode
);
196 rwhi
->RemoveAccessibilityMode(mode
);
200 } // namespace content