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 32namespace chromeos { 33 34namespace { 35static MagnificationManager* g_magnification_manager = NULL; 36} 37 38class MagnificationManagerImpl : public MagnificationManager, 39 public content::NotificationObserver, 40 public ash::SessionStateObserver { 41 public: 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 61 virtual ~MagnificationManagerImpl() { 62 CHECK(this == g_magnification_manager); 63 } 64 65 // MagnificationManager implimentation: 66 virtual bool IsMagnifierEnabled() const OVERRIDE { 67 return enabled_; 68 } 69 70 virtual ash::MagnifierType GetMagnifierType() const OVERRIDE { 71 return type_; 72 } 73 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 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 92 virtual void SaveScreenMagnifierScale(double scale) OVERRIDE { 93 if (!profile_) 94 return; 95 96 profile_->GetPrefs()->SetDouble(prefs::kScreenMagnifierScale, scale); 97 } 98 99 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 106 virtual void SetProfileForTest(Profile* profile) OVERRIDE { 107 SetProfile(profile); 108 } 109 110 // SessionStateObserver overrides: 111 virtual void ActiveUserChanged(const std::string& user_id) OVERRIDE { 112 SetProfile(ProfileManager::GetActiveUserProfile()); 113 } 114 115 private: 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 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 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 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: 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 253void MagnificationManager::Initialize() { 254 CHECK(g_magnification_manager == NULL); 255 g_magnification_manager = new MagnificationManagerImpl(); 256} 257 258// static 259void MagnificationManager::Shutdown() { 260 CHECK(g_magnification_manager); 261 delete g_magnification_manager; 262 g_magnification_manager = NULL; 263} 264 265// static 266MagnificationManager* MagnificationManager::Get() { 267 return g_magnification_manager; 268} 269 270} // namespace chromeos 271