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"
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"
35 static MagnificationManager
* g_magnification_manager
= NULL
;
38 class MagnificationManagerImpl
: public MagnificationManager
,
39 public content::NotificationObserver
,
40 public ash::SessionStateObserver
{
42 MagnificationManagerImpl()
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
),
51 observing_focus_change_in_page_(false) {
53 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
,
54 content::NotificationService::AllSources());
56 chrome::NOTIFICATION_SESSION_STARTED
,
57 content::NotificationService::AllSources());
59 chrome::NOTIFICATION_PROFILE_DESTROYED
,
60 content::NotificationService::AllSources());
63 ~MagnificationManagerImpl() override
{
64 CHECK(this == g_magnification_manager
);
67 // MagnificationManager implimentation:
68 bool IsMagnifierEnabled() const override
{ return enabled_
; }
70 ui::MagnifierType
GetMagnifierType() const override
{ return type_
; }
72 void SetMagnifierEnabled(bool enabled
) override
{
76 PrefService
* prefs
= profile_
->GetPrefs();
77 prefs
->SetBoolean(prefs::kAccessibilityScreenMagnifierEnabled
, enabled
);
78 prefs
->CommitPendingWrite();
81 void SetMagnifierType(ui::MagnifierType type
) override
{
85 PrefService
* prefs
= profile_
->GetPrefs();
86 prefs
->SetInteger(prefs::kAccessibilityScreenMagnifierType
, type
);
87 prefs
->CommitPendingWrite();
90 void SaveScreenMagnifierScale(double scale
) override
{
94 profile_
->GetPrefs()->SetDouble(prefs::kAccessibilityScreenMagnifierScale
,
98 double GetSavedScreenMagnifierScale() const override
{
100 return std::numeric_limits
<double>::min();
102 return profile_
->GetPrefs()->GetDouble(
103 prefs::kAccessibilityScreenMagnifierScale
);
106 void SetProfileForTest(Profile
* profile
) override
{ SetProfile(profile
); }
108 // SessionStateObserver overrides:
109 void ActiveUserChanged(const std::string
& user_id
) override
{
110 SetProfile(ProfileManager::GetActiveUserProfile());
114 void SetProfile(Profile
* profile
) {
115 pref_change_registrar_
.reset();
118 // TODO(yoshiki): Move following code to PrefHandler.
119 pref_change_registrar_
.reset(new PrefChangeRegistrar
);
120 pref_change_registrar_
->Init(profile
->GetPrefs());
121 pref_change_registrar_
->Add(
122 prefs::kAccessibilityScreenMagnifierEnabled
,
123 base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs
,
124 base::Unretained(this)));
125 pref_change_registrar_
->Add(
126 prefs::kAccessibilityScreenMagnifierType
,
127 base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs
,
128 base::Unretained(this)));
131 magnifier_enabled_pref_handler_
.HandleProfileChanged(profile_
, profile
);
132 magnifier_type_pref_handler_
.HandleProfileChanged(profile_
, profile
);
133 magnifier_scale_pref_handler_
.HandleProfileChanged(profile_
, profile
);
136 UpdateMagnifierFromPrefs();
139 virtual void SetMagnifierEnabledInternal(bool enabled
) {
140 // This method may be invoked even when the other magnifier settings (e.g.
141 // type or scale) are changed, so we need to call magnification controller
142 // even if |enabled| is unchanged. Only if |enabled| is false and the
143 // magnifier is already disabled, we are sure that we don't need to reflect
144 // the new settings right now because the magnifier keeps disabled.
145 if (!enabled
&& !enabled_
)
150 if (type_
== ui::MAGNIFIER_FULL
) {
151 ash::Shell::GetInstance()->magnification_controller()->SetEnabled(
153 MonitorFocusInPageChange();
155 ash::Shell::GetInstance()->partial_magnification_controller()->SetEnabled(
160 virtual void SetMagnifierTypeInternal(ui::MagnifierType type
) {
164 type_
= ui::MAGNIFIER_FULL
; // (leave out for full magnifier)
167 void UpdateMagnifierFromPrefs() {
171 const bool enabled
= profile_
->GetPrefs()->GetBoolean(
172 prefs::kAccessibilityScreenMagnifierEnabled
);
173 const int type_integer
= profile_
->GetPrefs()->GetInteger(
174 prefs::kAccessibilityScreenMagnifierType
);
176 ui::MagnifierType type
= ui::kDefaultMagnifierType
;
177 if (type_integer
> 0 && type_integer
<= ui::kMaxMagnifierType
) {
178 type
= static_cast<ui::MagnifierType
>(type_integer
);
179 } else if (type_integer
== 0) {
180 // Type 0 is used to disable the screen magnifier through policy. As the
181 // magnifier type is irrelevant in this case, it is OK to just fall back
188 SetMagnifierEnabledInternal(enabled
);
189 SetMagnifierTypeInternal(type
);
191 SetMagnifierTypeInternal(type
);
192 SetMagnifierEnabledInternal(enabled
);
195 AccessibilityStatusEventDetails
details(
196 ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER
,
199 ui::A11Y_NOTIFICATION_NONE
);
201 if (AccessibilityManager::Get()) {
202 AccessibilityManager::Get()->NotifyAccessibilityStatusChanged(details
);
203 if (ash::Shell::GetInstance()) {
204 ash::Shell::GetInstance()->SetCursorCompositingEnabled(
205 AccessibilityManager::Get()->ShouldEnableCursorCompositing());
210 void MonitorFocusInPageChange() {
211 if (enabled_
&& !observing_focus_change_in_page_
) {
212 registrar_
.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE
,
213 content::NotificationService::AllSources());
214 observing_focus_change_in_page_
= true;
215 } else if (!enabled_
&& observing_focus_change_in_page_
) {
216 registrar_
.Remove(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE
,
217 content::NotificationService::AllSources());
218 observing_focus_change_in_page_
= false;
222 // content::NotificationObserver implementation:
223 void Observe(int type
,
224 const content::NotificationSource
& source
,
225 const content::NotificationDetails
& details
) override
{
227 case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
: {
228 // Update |profile_| when entering the login screen.
229 Profile
* profile
= ProfileManager::GetActiveUserProfile();
230 if (ProfileHelper::IsSigninProfile(profile
))
234 case chrome::NOTIFICATION_SESSION_STARTED
:
235 // Update |profile_| when entering a session.
236 SetProfile(ProfileManager::GetActiveUserProfile());
238 // Add a session state observer to be able to monitor session changes.
239 if (!session_state_observer_
.get() && ash::Shell::HasInstance())
240 session_state_observer_
.reset(
241 new ash::ScopedSessionStateObserver(this));
243 case chrome::NOTIFICATION_PROFILE_DESTROYED
: {
244 // Update |profile_| when exiting a session or shutting down.
245 Profile
* profile
= content::Source
<Profile
>(source
).ptr();
246 if (profile_
== profile
)
250 case content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE
: {
251 content::FocusedNodeDetails
* node_details
=
252 content::Details
<content::FocusedNodeDetails
>(details
).ptr();
253 ash::Shell::GetInstance()
254 ->magnification_controller()
255 ->HandleFocusedNodeChanged(node_details
->is_editable_node
,
256 node_details
->node_bounds_in_screen
);
264 AccessibilityManager::PrefHandler magnifier_enabled_pref_handler_
;
265 AccessibilityManager::PrefHandler magnifier_type_pref_handler_
;
266 AccessibilityManager::PrefHandler magnifier_scale_pref_handler_
;
268 ui::MagnifierType type_
;
270 bool observing_focus_change_in_page_
;
272 content::NotificationRegistrar registrar_
;
273 scoped_ptr
<PrefChangeRegistrar
> pref_change_registrar_
;
274 scoped_ptr
<ash::ScopedSessionStateObserver
> session_state_observer_
;
276 DISALLOW_COPY_AND_ASSIGN(MagnificationManagerImpl
);
280 void MagnificationManager::Initialize() {
281 CHECK(g_magnification_manager
== NULL
);
282 g_magnification_manager
= new MagnificationManagerImpl();
286 void MagnificationManager::Shutdown() {
287 CHECK(g_magnification_manager
);
288 delete g_magnification_manager
;
289 g_magnification_manager
= NULL
;
293 MagnificationManager
* MagnificationManager::Get() {
294 return g_magnification_manager
;
297 } // namespace chromeos