• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/browser/chromeos/accessibility/magnification_manager.h"
6 
7 #include <limits>
8 
9 #include "ash/magnifier/magnification_controller.h"
10 #include "ash/magnifier/partial_magnification_controller.h"
11 #include "ash/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/login/user_manager.h"
22 #include "chrome/browser/chromeos/profiles/profile_helper.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/common/pref_names.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"
31 
32 namespace chromeos {
33 
34 namespace {
35 static MagnificationManager* g_magnification_manager = NULL;
36 }
37 
38 class MagnificationManagerImpl : public MagnificationManager,
39                                  public content::NotificationObserver,
40                                  public ash::SessionStateObserver {
41  public:
MagnificationManagerImpl()42   MagnificationManagerImpl()
43       : first_time_update_(true),
44         profile_(NULL),
45         magnifier_enabled_pref_handler_(prefs::kScreenMagnifierEnabled),
46         magnifier_type_pref_handler_(prefs::kScreenMagnifierType),
47         magnifier_scale_pref_handler_(prefs::kScreenMagnifierScale),
48         type_(ash::kDefaultMagnifierType),
49         enabled_(false) {
50     registrar_.Add(this,
51                    chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
52                    content::NotificationService::AllSources());
53     registrar_.Add(this,
54                    chrome::NOTIFICATION_SESSION_STARTED,
55                    content::NotificationService::AllSources());
56     registrar_.Add(this,
57                    chrome::NOTIFICATION_PROFILE_DESTROYED,
58                    content::NotificationService::AllSources());
59   }
60 
~MagnificationManagerImpl()61   virtual ~MagnificationManagerImpl() {
62     CHECK(this == g_magnification_manager);
63   }
64 
65   // MagnificationManager implimentation:
IsMagnifierEnabled() const66   virtual bool IsMagnifierEnabled() const OVERRIDE {
67     return enabled_;
68   }
69 
GetMagnifierType() const70   virtual ash::MagnifierType GetMagnifierType() const OVERRIDE {
71     return type_;
72   }
73 
SetMagnifierEnabled(bool enabled)74   virtual void SetMagnifierEnabled(bool enabled) OVERRIDE {
75     if (!profile_)
76       return;
77 
78     PrefService* prefs = profile_->GetPrefs();
79     prefs->SetBoolean(prefs::kScreenMagnifierEnabled, enabled);
80     prefs->CommitPendingWrite();
81   }
82 
SetMagnifierType(ash::MagnifierType type)83   virtual void SetMagnifierType(ash::MagnifierType type) OVERRIDE {
84     if (!profile_)
85       return;
86 
87     PrefService* prefs = profile_->GetPrefs();
88     prefs->SetInteger(prefs::kScreenMagnifierType, type);
89     prefs->CommitPendingWrite();
90   }
91 
SaveScreenMagnifierScale(double scale)92   virtual void SaveScreenMagnifierScale(double scale) OVERRIDE {
93     if (!profile_)
94       return;
95 
96     profile_->GetPrefs()->SetDouble(prefs::kScreenMagnifierScale, scale);
97   }
98 
GetSavedScreenMagnifierScale() const99   virtual double GetSavedScreenMagnifierScale() const OVERRIDE {
100     if (!profile_)
101       return std::numeric_limits<double>::min();
102 
103     return profile_->GetPrefs()->GetDouble(prefs::kScreenMagnifierScale);
104   }
105 
SetProfileForTest(Profile * profile)106   virtual void SetProfileForTest(Profile* profile) OVERRIDE {
107     SetProfile(profile);
108   }
109 
110   // SessionStateObserver overrides:
ActiveUserChanged(const std::string & user_id)111   virtual void ActiveUserChanged(const std::string& user_id) OVERRIDE {
112     SetProfile(ProfileManager::GetActiveUserProfile());
113   }
114 
115  private:
SetProfile(Profile * profile)116   void SetProfile(Profile* profile) {
117     pref_change_registrar_.reset();
118 
119     if (profile) {
120       // TODO(yoshiki): Move following code to PrefHandler.
121       pref_change_registrar_.reset(new PrefChangeRegistrar);
122       pref_change_registrar_->Init(profile->GetPrefs());
123       pref_change_registrar_->Add(
124           prefs::kScreenMagnifierEnabled,
125           base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
126                      base::Unretained(this)));
127       pref_change_registrar_->Add(
128           prefs::kScreenMagnifierType,
129           base::Bind(&MagnificationManagerImpl::UpdateMagnifierFromPrefs,
130                      base::Unretained(this)));
131     }
132 
133     magnifier_enabled_pref_handler_.HandleProfileChanged(profile_, profile);
134     magnifier_type_pref_handler_.HandleProfileChanged(profile_, profile);
135     magnifier_scale_pref_handler_.HandleProfileChanged(profile_, profile);
136 
137     profile_ = profile;
138     UpdateMagnifierFromPrefs();
139   }
140 
SetMagnifierEnabledInternal(bool enabled)141   virtual void SetMagnifierEnabledInternal(bool enabled) {
142     // This method may be invoked even when the other magnifier settings (e.g.
143     // type or scale) are changed, so we need to call magnification controller
144     // even if |enabled| is unchanged. Only if |enabled| is false and the
145     // magnifier is already disabled, we are sure that we don't need to reflect
146     // the new settings right now because the magnifier keeps disabled.
147     if (!enabled && !enabled_)
148       return;
149 
150     enabled_ = enabled;
151 
152     if (type_ == ash::MAGNIFIER_FULL) {
153       ash::Shell::GetInstance()->magnification_controller()->SetEnabled(
154           enabled_);
155     } else {
156       ash::Shell::GetInstance()->partial_magnification_controller()->SetEnabled(
157           enabled_);
158     }
159   }
160 
SetMagnifierTypeInternal(ash::MagnifierType type)161   virtual void SetMagnifierTypeInternal(ash::MagnifierType type) {
162     if (type_ == type)
163       return;
164 
165     type_ = ash::MAGNIFIER_FULL;  // (leave out for full magnifier)
166   }
167 
UpdateMagnifierFromPrefs()168   void UpdateMagnifierFromPrefs() {
169     if (!profile_)
170       return;
171 
172     const bool enabled =
173         profile_->GetPrefs()->GetBoolean(prefs::kScreenMagnifierEnabled);
174     const int type_integer =
175         profile_->GetPrefs()->GetInteger(prefs::kScreenMagnifierType);
176 
177     ash::MagnifierType type = ash::kDefaultMagnifierType;
178     if (type_integer > 0 && type_integer <= ash::kMaxMagnifierType) {
179       type = static_cast<ash::MagnifierType>(type_integer);
180     } else if (type_integer == 0) {
181       // Type 0 is used to disable the screen magnifier through policy. As the
182       // magnifier type is irrelevant in this case, it is OK to just fall back
183       // to the default.
184     } else {
185       NOTREACHED();
186     }
187 
188     if (!enabled) {
189       SetMagnifierEnabledInternal(enabled);
190       SetMagnifierTypeInternal(type);
191     } else {
192       SetMagnifierTypeInternal(type);
193       SetMagnifierEnabledInternal(enabled);
194     }
195 
196     AccessibilityStatusEventDetails details(
197         enabled_, type_, ash::A11Y_NOTIFICATION_NONE);
198     content::NotificationService::current()->Notify(
199         chrome::NOTIFICATION_CROS_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFIER,
200         content::NotificationService::AllSources(),
201         content::Details<AccessibilityStatusEventDetails>(&details));
202   }
203 
204   // content::NotificationObserver implementation:
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)205   virtual void Observe(int type,
206                        const content::NotificationSource& source,
207                        const content::NotificationDetails& details) OVERRIDE {
208     switch (type) {
209       case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: {
210         // Update |profile_| when entering the login screen.
211         Profile* profile = ProfileManager::GetDefaultProfile();
212         if (ProfileHelper::IsSigninProfile(profile))
213           SetProfile(profile);
214         break;
215       }
216       case chrome::NOTIFICATION_SESSION_STARTED:
217         // Update |profile_| when entering a session.
218         SetProfile(ProfileManager::GetDefaultProfile());
219 
220         // Add a session state observer to be able to monitor session changes.
221         if (!session_state_observer_.get() && ash::Shell::HasInstance())
222           session_state_observer_.reset(
223               new ash::ScopedSessionStateObserver(this));
224         break;
225       case chrome::NOTIFICATION_PROFILE_DESTROYED: {
226         // Update |profile_| when exiting a session or shutting down.
227         Profile* profile = content::Source<Profile>(source).ptr();
228         if (profile_ == profile)
229           SetProfile(NULL);
230         break;
231       }
232     }
233   }
234 
235   bool first_time_update_;
236   Profile* profile_;
237 
238   AccessibilityManager::PrefHandler magnifier_enabled_pref_handler_;
239   AccessibilityManager::PrefHandler magnifier_type_pref_handler_;
240   AccessibilityManager::PrefHandler magnifier_scale_pref_handler_;
241 
242   ash::MagnifierType type_;
243   bool enabled_;
244 
245   content::NotificationRegistrar registrar_;
246   scoped_ptr<PrefChangeRegistrar> pref_change_registrar_;
247   scoped_ptr<ash::ScopedSessionStateObserver> session_state_observer_;
248 
249   DISALLOW_COPY_AND_ASSIGN(MagnificationManagerImpl);
250 };
251 
252 // static
Initialize()253 void MagnificationManager::Initialize() {
254   CHECK(g_magnification_manager == NULL);
255   g_magnification_manager = new MagnificationManagerImpl();
256 }
257 
258 // static
Shutdown()259 void MagnificationManager::Shutdown() {
260   CHECK(g_magnification_manager);
261   delete g_magnification_manager;
262   g_magnification_manager = NULL;
263 }
264 
265 // static
Get()266 MagnificationManager* MagnificationManager::Get() {
267   return g_magnification_manager;
268 }
269 
270 }  // namespace chromeos
271