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/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