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