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