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/browser/web_contents/web_contents_impl.h"
13#include "content/public/browser/browser_thread.h"
14#include "content/public/common/content_switches.h"
15#include "ui/gfx/sys_color_change_listener.h"
16
17namespace content {
18
19// Update the accessibility histogram 45 seconds after initialization.
20static const int kAccessibilityHistogramDelaySecs = 45;
21
22// static
23BrowserAccessibilityState* BrowserAccessibilityState::GetInstance() {
24  return BrowserAccessibilityStateImpl::GetInstance();
25}
26
27// static
28BrowserAccessibilityStateImpl* BrowserAccessibilityStateImpl::GetInstance() {
29  return Singleton<BrowserAccessibilityStateImpl,
30                   LeakySingletonTraits<BrowserAccessibilityStateImpl> >::get();
31}
32
33BrowserAccessibilityStateImpl::BrowserAccessibilityStateImpl()
34    : BrowserAccessibilityState(),
35      accessibility_mode_(AccessibilityModeOff) {
36  ResetAccessibilityModeValue();
37#if defined(OS_WIN)
38  // On Windows, UpdateHistograms calls some system functions with unknown
39  // runtime, so call it on the file thread to ensure there's no jank.
40  // Everything in that method must be safe to call on another thread.
41  BrowserThread::ID update_histogram_thread = BrowserThread::FILE;
42#else
43  // On all other platforms, UpdateHistograms should be called on the main
44  // thread.
45  BrowserThread::ID update_histogram_thread = BrowserThread::UI;
46#endif
47
48  // We need to AddRef() the leaky singleton so that Bind doesn't
49  // delete it prematurely.
50  AddRef();
51  BrowserThread::PostDelayedTask(
52      update_histogram_thread, FROM_HERE,
53      base::Bind(&BrowserAccessibilityStateImpl::UpdateHistograms, this),
54      base::TimeDelta::FromSeconds(kAccessibilityHistogramDelaySecs));
55}
56
57BrowserAccessibilityStateImpl::~BrowserAccessibilityStateImpl() {
58}
59
60void BrowserAccessibilityStateImpl::OnScreenReaderDetected() {
61  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
62          switches::kDisableRendererAccessibility)) {
63    return;
64  }
65  EnableAccessibility();
66}
67
68void BrowserAccessibilityStateImpl::EnableAccessibility() {
69  AddAccessibilityMode(AccessibilityModeComplete);
70}
71
72void BrowserAccessibilityStateImpl::DisableAccessibility() {
73  ResetAccessibilityMode();
74}
75
76void BrowserAccessibilityStateImpl::ResetAccessibilityModeValue() {
77  accessibility_mode_ = AccessibilityModeOff;
78  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
79          switches::kForceRendererAccessibility)) {
80    accessibility_mode_ = AccessibilityModeComplete;
81  }
82}
83
84void BrowserAccessibilityStateImpl::ResetAccessibilityMode() {
85  ResetAccessibilityModeValue();
86
87  std::vector<WebContentsImpl*> web_contents_vector =
88      WebContentsImpl::GetAllWebContents();
89  for (size_t i = 0; i < web_contents_vector.size(); ++i)
90    web_contents_vector[i]->SetAccessibilityMode(accessibility_mode());
91}
92
93bool BrowserAccessibilityStateImpl::IsAccessibleBrowser() {
94  return ((accessibility_mode_ & AccessibilityModeComplete) ==
95          AccessibilityModeComplete);
96}
97
98void BrowserAccessibilityStateImpl::AddHistogramCallback(
99    base::Closure callback) {
100  histogram_callbacks_.push_back(callback);
101}
102
103void BrowserAccessibilityStateImpl::UpdateHistogramsForTesting() {
104  UpdateHistograms();
105}
106
107void BrowserAccessibilityStateImpl::UpdateHistograms() {
108  UpdatePlatformSpecificHistograms();
109
110  for (size_t i = 0; i < histogram_callbacks_.size(); ++i)
111    histogram_callbacks_[i].Run();
112
113  UMA_HISTOGRAM_BOOLEAN("Accessibility.State", IsAccessibleBrowser());
114  UMA_HISTOGRAM_BOOLEAN("Accessibility.InvertedColors",
115                        gfx::IsInvertedColorScheme());
116  UMA_HISTOGRAM_BOOLEAN("Accessibility.ManuallyEnabled",
117                        base::CommandLine::ForCurrentProcess()->HasSwitch(
118                            switches::kForceRendererAccessibility));
119}
120
121#if !defined(OS_WIN)
122void BrowserAccessibilityStateImpl::UpdatePlatformSpecificHistograms() {
123}
124#endif
125
126void BrowserAccessibilityStateImpl::AddAccessibilityMode(
127    AccessibilityMode mode) {
128  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
129          switches::kDisableRendererAccessibility)) {
130    return;
131  }
132
133  accessibility_mode_ =
134      content::AddAccessibilityModeTo(accessibility_mode_, mode);
135
136  AddOrRemoveFromAllWebContents(mode, true);
137}
138
139void BrowserAccessibilityStateImpl::RemoveAccessibilityMode(
140    AccessibilityMode mode) {
141  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
142          switches::kForceRendererAccessibility) &&
143      mode == AccessibilityModeComplete) {
144    return;
145  }
146
147  accessibility_mode_ =
148      content::RemoveAccessibilityModeFrom(accessibility_mode_, mode);
149
150  AddOrRemoveFromAllWebContents(mode, false);
151}
152
153void BrowserAccessibilityStateImpl::AddOrRemoveFromAllWebContents(
154    AccessibilityMode mode,
155    bool add) {
156  std::vector<WebContentsImpl*> web_contents_vector =
157      WebContentsImpl::GetAllWebContents();
158  for (size_t i = 0; i < web_contents_vector.size(); ++i) {
159    if (add)
160      web_contents_vector[i]->AddAccessibilityMode(mode);
161    else
162      web_contents_vector[i]->RemoveAccessibilityMode(mode);
163  }
164}
165
166}  // namespace content
167