Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / chromeos / accessibility / magnification_manager.cc
blobfb9f43e2b21bb21da1b925bfc8bbda093db5942e
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 "chrome/browser/chromeos/accessibility/magnification_manager.h"
7 #include <limits>
9 #include "ash/magnifier/magnification_controller.h"
10 #include "ash/magnifier/partial_magnification_controller.h"
11 #include "ash/session/session_state_delegate.h"
12 #include "ash/shell.h"
13 #include "ash/shell_delegate.h"
14 #include "ash/system/tray/system_tray_notifier.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/memory/singleton.h"
17 #include "base/prefs/pref_member.h"
18 #include "base/prefs/pref_service.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
21 #include "chrome/browser/chromeos/profiles/profile_helper.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/profiles/profile_manager.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/focused_node_details.h"
26 #include "content/public/browser/notification_details.h"
27 #include "content/public/browser/notification_observer.h"
28 #include "content/public/browser/notification_registrar.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/notification_source.h"
32 namespace chromeos {
34 namespace {
35 static MagnificationManager* g_magnification_manager = NULL;
38 class MagnificationManagerImpl : public MagnificationManager,
39 public content::NotificationObserver,
40 public ash::SessionStateObserver {
41 public:
42 MagnificationManagerImpl()
43 : profile_(NULL),
44 magnifier_enabled_pref_handler_(
45 prefs::kAccessibilityScreenMagnifierEnabled),
46 magnifier_type_pref_handler_(prefs::kAccessibilityScreenMagnifierType),
47 magnifier_scale_pref_handler_(
48 prefs::kAccessibilityScreenMagnifierScale),
49 type_(ui::kDefaultMagnifierType),
50 enabled_(false),
51 keep_focus_centered_(false),
52 observing_focus_change_in_page_(false) {
53 registrar_.Add(this,
54 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
55 content::NotificationService::AllSources());
56 registrar_.Add(this,
57 chrome::NOTIFICATION_SESSION_STARTED,
58 content::NotificationService::AllSources());
59 registrar_.Add(this,
60 chrome::NOTIFICATION_PROFILE_DESTROYED,
61 content::NotificationService::AllSources());
64 ~MagnificationManagerImpl() override {
65 CHECK(this == g_magnification_manager);
68 // MagnificationManager implimentation:
69 bool IsMagnifierEnabled() const override { return enabled_; }
71 ui::MagnifierType GetMagnifierType() const override { return type_; }
73 void SetMagnifierEnabled(bool enabled) override {
74 if (!profile_)
75 return;
77 PrefService* prefs = profile_->GetPrefs();
78 prefs->SetBoolean(prefs::kAccessibilityScreenMagnifierEnabled, enabled);
79 prefs->CommitPendingWrite();
82 void SetMagnifierType(ui::MagnifierType type) override {
83 if (!profile_)
84 return;
86 PrefService* prefs = profile_->GetPrefs();
87 prefs->SetInteger(prefs::kAccessibilityScreenMagnifierType, type);
88 prefs->CommitPendingWrite();
91 void SaveScreenMagnifierScale(double scale) override {
92 if (!profile_)
93 return;
95 profile_->GetPrefs()->SetDouble(prefs::kAccessibilityScreenMagnifierScale,
96 scale);
99 double GetSavedScreenMagnifierScale() const override {
100 if (!profile_)
101 return std::numeric_limits<double>::min();
103 return profile_->GetPrefs()->GetDouble(
104 prefs::kAccessibilityScreenMagnifierScale);
107 void SetProfileForTest(Profile* profile) override { SetProfile(profile); }
109 // SessionStateObserver overrides:
110 void ActiveUserChanged(const std::string& user_id) override {
111 SetProfile(ProfileManager::GetActiveUserProfile());
114 private:
115 void SetProfile(Profile* profile) {
116 pref_change_registrar_.reset();
118 if (profile) {
119 // TODO(yoshiki): Move following code to PrefHandler.
120 pref_change_registrar_.reset(new PrefChangeRegistrar);
121 pref_change_registrar_->Init(profile->GetPrefs());
122 pref_change_registrar_->Add(
123 prefs::kAccessibilityScreenMagnifierEnabled,
124 base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
125 base::Unretained(this)));
126 pref_change_registrar_->Add(
127 prefs::kAccessibilityScreenMagnifierType,
128 base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
129 base::Unretained(this)));
130 pref_change_registrar_->Add(
131 prefs::kAccessibilityScreenMagnifierCenterFocus,
132 base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
133 base::Unretained(this)));
136 magnifier_enabled_pref_handler_.HandleProfileChanged(profile_, profile);
137 magnifier_type_pref_handler_.HandleProfileChanged(profile_, profile);
138 magnifier_scale_pref_handler_.HandleProfileChanged(profile_, profile);
140 profile_ = profile;
141 UpdateMagnifierFromPrefs();
144 virtual void SetMagnifierEnabledInternal(bool enabled) {
145 // This method may be invoked even when the other magnifier settings (e.g.
146 // type or scale) are changed, so we need to call magnification controller
147 // even if |enabled| is unchanged. Only if |enabled| is false and the
148 // magnifier is already disabled, we are sure that we don't need to reflect
149 // the new settings right now because the magnifier keeps disabled.
150 if (!enabled && !enabled_)
151 return;
153 enabled_ = enabled;
155 if (type_ == ui::MAGNIFIER_FULL) {
156 ash::Shell::GetInstance()->magnification_controller()->SetEnabled(
157 enabled_);
158 MonitorFocusInPageChange();
159 } else {
160 ash::Shell::GetInstance()->partial_magnification_controller()->SetEnabled(
161 enabled_);
165 virtual void SetMagnifierTypeInternal(ui::MagnifierType type) {
166 if (type_ == type)
167 return;
169 type_ = ui::MAGNIFIER_FULL; // (leave out for full magnifier)
172 virtual void SetMagniferKeepFocusCenteredInternal(bool keep_focus_centered) {
173 if (keep_focus_centered_ == keep_focus_centered)
174 return;
176 keep_focus_centered_ = keep_focus_centered;
178 if (type_ == ui::MAGNIFIER_FULL) {
179 ash::Shell::GetInstance()
180 ->magnification_controller()
181 ->SetKeepFocusCentered(keep_focus_centered_);
185 void UpdateMagnifierFromPrefs() {
186 if (!profile_)
187 return;
189 const bool enabled = profile_->GetPrefs()->GetBoolean(
190 prefs::kAccessibilityScreenMagnifierEnabled);
191 const int type_integer = profile_->GetPrefs()->GetInteger(
192 prefs::kAccessibilityScreenMagnifierType);
193 const bool keep_focus_centered = profile_->GetPrefs()->GetBoolean(
194 prefs::kAccessibilityScreenMagnifierCenterFocus);
196 ui::MagnifierType type = ui::kDefaultMagnifierType;
197 if (type_integer > 0 && type_integer <= ui::kMaxMagnifierType) {
198 type = static_cast<ui::MagnifierType>(type_integer);
199 } else if (type_integer == 0) {
200 // Type 0 is used to disable the screen magnifier through policy. As the
201 // magnifier type is irrelevant in this case, it is OK to just fall back
202 // to the default.
203 } else {
204 NOTREACHED();
207 if (!enabled) {
208 SetMagnifierEnabledInternal(enabled);
209 SetMagnifierTypeInternal(type);
210 SetMagniferKeepFocusCenteredInternal(keep_focus_centered);
211 } else {
212 SetMagniferKeepFocusCenteredInternal(keep_focus_centered);
213 SetMagnifierTypeInternal(type);
214 SetMagnifierEnabledInternal(enabled);
217 AccessibilityStatusEventDetails details(
218 ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER,
219 enabled_,
220 type_,
221 ui::A11Y_NOTIFICATION_NONE);
223 if (AccessibilityManager::Get()) {
224 AccessibilityManager::Get()->NotifyAccessibilityStatusChanged(details);
225 if (ash::Shell::GetInstance()) {
226 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
227 AccessibilityManager::Get()->ShouldEnableCursorCompositing());
232 void MonitorFocusInPageChange() {
233 if (enabled_ && !observing_focus_change_in_page_) {
234 registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
235 content::NotificationService::AllSources());
236 observing_focus_change_in_page_ = true;
237 } else if (!enabled_ && observing_focus_change_in_page_) {
238 registrar_.Remove(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
239 content::NotificationService::AllSources());
240 observing_focus_change_in_page_ = false;
244 // content::NotificationObserver implementation:
245 void Observe(int type,
246 const content::NotificationSource& source,
247 const content::NotificationDetails& details) override {
248 switch (type) {
249 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
250 // Update |profile_| when entering the login screen.
251 Profile* profile = ProfileManager::GetActiveUserProfile();
252 if (ProfileHelper::IsSigninProfile(profile))
253 SetProfile(profile);
254 break;
256 case chrome::NOTIFICATION_SESSION_STARTED:
257 // Update |profile_| when entering a session.
258 SetProfile(ProfileManager::GetActiveUserProfile());
260 // Add a session state observer to be able to monitor session changes.
261 if (!session_state_observer_.get() && ash::Shell::HasInstance())
262 session_state_observer_.reset(
263 new ash::ScopedSessionStateObserver(this));
264 break;
265 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
266 // Update |profile_| when exiting a session or shutting down.
267 Profile* profile = content::Source<Profile>(source).ptr();
268 if (profile_ == profile)
269 SetProfile(NULL);
270 break;
272 case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE: {
273 content::FocusedNodeDetails* node_details =
274 content::Details<content::FocusedNodeDetails>(details).ptr();
275 ash::Shell::GetInstance()
276 ->magnification_controller()
277 ->HandleFocusedNodeChanged(node_details->is_editable_node,
278 node_details->node_bounds_in_screen);
279 break;
284 Profile* profile_;
286 AccessibilityManager::PrefHandler magnifier_enabled_pref_handler_;
287 AccessibilityManager::PrefHandler magnifier_type_pref_handler_;
288 AccessibilityManager::PrefHandler magnifier_scale_pref_handler_;
290 ui::MagnifierType type_;
291 bool enabled_;
292 bool keep_focus_centered_;
293 bool observing_focus_change_in_page_;
295 content::NotificationRegistrar registrar_;
296 scoped_ptr<PrefChangeRegistrar> pref_change_registrar_;
297 scoped_ptr<ash::ScopedSessionStateObserver> session_state_observer_;
299 DISALLOW_COPY_AND_ASSIGN(MagnificationManagerImpl);
302 // static
303 void MagnificationManager::Initialize() {
304 CHECK(g_magnification_manager == NULL);
305 g_magnification_manager = new MagnificationManagerImpl();
308 // static
309 void MagnificationManager::Shutdown() {
310 CHECK(g_magnification_manager);
311 delete g_magnification_manager;
312 g_magnification_manager = NULL;
315 // static
316 MagnificationManager* MagnificationManager::Get() {
317 return g_magnification_manager;
320 } // namespace chromeos