| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/accessibility/magnification_manager.h" |
| |
| #include <limits> |
| #include <memory> |
| |
| #include "ash/accessibility/magnifier/docked_magnifier_controller.h" |
| #include "ash/accessibility/magnifier/fullscreen_magnifier_controller.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/shell.h" |
| #include "base/bind.h" |
| #include "chrome/browser/ash/accessibility/accessibility_manager.h" |
| #include "chrome/browser/ash/profiles/profile_helper.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "components/prefs/pref_change_registrar.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/user_manager/user_manager.h" |
| #include "content/public/browser/focused_node_details.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_source.h" |
| #include "ui/accessibility/accessibility_features.h" |
| #include "ui/accessibility/ax_role_properties.h" |
| #include "ui/views/accessibility/ax_event_manager.h" |
| #include "ui/views/accessibility/view_accessibility.h" |
| |
| namespace ash { |
| namespace { |
| |
| MagnificationManager* g_magnification_manager = nullptr; |
| |
| } // namespace |
| |
| // static |
| void MagnificationManager::Initialize() { |
| CHECK(g_magnification_manager == nullptr); |
| g_magnification_manager = new MagnificationManager(); |
| } |
| |
| // static |
| void MagnificationManager::Shutdown() { |
| CHECK(g_magnification_manager); |
| delete g_magnification_manager; |
| g_magnification_manager = nullptr; |
| } |
| |
| // static |
| MagnificationManager* MagnificationManager::Get() { |
| return g_magnification_manager; |
| } |
| |
| bool MagnificationManager::IsMagnifierEnabled() const { |
| return fullscreen_magnifier_enabled_; |
| } |
| |
| void MagnificationManager::SetMagnifierEnabled(bool enabled) { |
| if (!profile_) |
| return; |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| prefs->SetBoolean(prefs::kAccessibilityScreenMagnifierEnabled, enabled); |
| prefs->CommitPendingWrite(); |
| } |
| |
| bool MagnificationManager::IsDockedMagnifierEnabled() const { |
| return profile_ && |
| profile_->GetPrefs()->GetBoolean(prefs::kDockedMagnifierEnabled); |
| } |
| |
| void MagnificationManager::SetDockedMagnifierEnabled(bool enabled) { |
| if (!profile_) |
| return; |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| prefs->SetBoolean(prefs::kDockedMagnifierEnabled, enabled); |
| prefs->CommitPendingWrite(); |
| } |
| |
| void MagnificationManager::SaveScreenMagnifierScale(double scale) { |
| if (!profile_) |
| return; |
| |
| profile_->GetPrefs()->SetDouble(prefs::kAccessibilityScreenMagnifierScale, |
| scale); |
| } |
| |
| double MagnificationManager::GetSavedScreenMagnifierScale() const { |
| if (!profile_) |
| return std::numeric_limits<double>::min(); |
| |
| return profile_->GetPrefs()->GetDouble( |
| prefs::kAccessibilityScreenMagnifierScale); |
| } |
| |
| void MagnificationManager::OnProfileWillBeDestroyed(Profile* profile) { |
| DCHECK_EQ(profile_, profile); |
| SetProfile(nullptr); |
| } |
| |
| void MagnificationManager::HandleMoveMagnifierToRectIfEnabled( |
| const gfx::Rect& rect) { |
| // Fullscreen magnifier and docked magnifier are mutually exclusive. |
| if (fullscreen_magnifier_enabled_) { |
| Shell::Get()->fullscreen_magnifier_controller()->HandleMoveMagnifierToRect( |
| rect); |
| return; |
| } |
| if (IsDockedMagnifierEnabled()) { |
| Shell::Get()->docked_magnifier_controller()->MoveMagnifierToRect(rect); |
| } |
| } |
| |
| void MagnificationManager::OnMouseEvent(ui::MouseEvent* event) { |
| last_mouse_event_ = base::TimeTicks::Now(); |
| } |
| |
| void MagnificationManager::OnViewEvent(views::View* view, |
| ax::mojom::Event event_type) { |
| if (!fullscreen_magnifier_enabled_ && !IsDockedMagnifierEnabled()) |
| return; |
| |
| if (event_type != ax::mojom::Event::kFocus && |
| event_type != ax::mojom::Event::kSelection) { |
| return; |
| } |
| |
| ui::AXNodeData data; |
| view->GetViewAccessibility().GetAccessibleNodeData(&data); |
| } |
| |
| void MagnificationManager::SetProfileForTest(Profile* profile) { |
| SetProfile(profile); |
| } |
| |
| MagnificationManager::MagnificationManager() { |
| registrar_.Add(this, chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, |
| content::NotificationService::AllSources()); |
| user_manager::UserManager::Get()->AddSessionStateObserver(this); |
| views::AXEventManager::Get()->AddObserver(this); |
| } |
| |
| MagnificationManager::~MagnificationManager() { |
| CHECK(this == g_magnification_manager); |
| views::AXEventManager::Get()->RemoveObserver(this); |
| user_manager::UserManager::Get()->RemoveSessionStateObserver(this); |
| } |
| |
| void MagnificationManager::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| switch (type) { |
| case chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE: { |
| // Update |profile_| when entering the login screen. |
| Profile* profile = ProfileManager::GetActiveUserProfile(); |
| if (ProfileHelper::IsSigninProfile(profile)) |
| SetProfile(profile); |
| break; |
| } |
| } |
| } |
| |
| void MagnificationManager::ActiveUserChanged(user_manager::User* active_user) { |
| if (!active_user) |
| return; |
| |
| active_user->AddProfileCreatedObserver( |
| base::BindOnce(&MagnificationManager::SetProfileByUser, |
| weak_ptr_factory_.GetWeakPtr(), active_user)); |
| } |
| |
| void MagnificationManager::SetProfileByUser(const user_manager::User* user) { |
| SetProfile(ProfileHelper::Get()->GetProfileByUser(user)); |
| } |
| |
| void MagnificationManager::SetProfile(Profile* profile) { |
| if (profile_) { |
| DCHECK(profile_observation_.IsObservingSource(profile_)); |
| profile_observation_.Reset(); |
| } |
| DCHECK(!profile_observation_.IsObserving()); |
| |
| pref_change_registrar_.reset(); |
| |
| if (profile) { |
| // TODO(yoshiki): Move following code to PrefHandler. |
| pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); |
| pref_change_registrar_->Init(profile->GetPrefs()); |
| pref_change_registrar_->Add( |
| prefs::kAccessibilityScreenMagnifierEnabled, |
| base::BindRepeating(&MagnificationManager::UpdateMagnifierFromPrefs, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| prefs::kAccessibilityScreenMagnifierCenterFocus, |
| base::BindRepeating(&MagnificationManager::UpdateMagnifierFromPrefs, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| prefs::kAccessibilityScreenMagnifierScale, |
| base::BindRepeating(&MagnificationManager::UpdateMagnifierFromPrefs, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| prefs::kAccessibilityScreenMagnifierMouseFollowingMode, |
| base::BindRepeating(&MagnificationManager::UpdateMagnifierFromPrefs, |
| base::Unretained(this))); |
| pref_change_registrar_->Add( |
| prefs::kDockedMagnifierEnabled, |
| base::BindRepeating( |
| &MagnificationManager::UpdateDockedMagnifierFromPrefs, |
| base::Unretained(this))); |
| |
| profile_observation_.Observe(profile); |
| } |
| |
| profile_ = profile; |
| UpdateMagnifierFromPrefs(); |
| UpdateDockedMagnifierFromPrefs(); |
| } |
| |
| void MagnificationManager::SetMagnifierEnabledInternal(bool enabled) { |
| // This method may be invoked even when the other magnifier settings (e.g. |
| // type or scale) are changed, so we need to call magnification controller |
| // even if |enabled| is unchanged. Only if |enabled| is false and the |
| // magnifier is already disabled, we are sure that we don't need to reflect |
| // the new settings right now because the magnifier keeps disabled. |
| if (!enabled && !fullscreen_magnifier_enabled_) |
| return; |
| |
| fullscreen_magnifier_enabled_ = enabled; |
| |
| Shell::Get()->fullscreen_magnifier_controller()->SetEnabled(enabled); |
| } |
| |
| void MagnificationManager::SetMagnifierKeepFocusCenteredInternal( |
| bool keep_focus_centered) { |
| if (keep_focus_centered_ == keep_focus_centered) |
| return; |
| |
| keep_focus_centered_ = keep_focus_centered; |
| |
| Shell::Get()->fullscreen_magnifier_controller()->SetKeepFocusCentered( |
| keep_focus_centered_); |
| } |
| |
| void MagnificationManager::SetMagnifierScaleInternal(double scale) { |
| if (scale_ == scale) |
| return; |
| |
| scale_ = scale; |
| |
| Shell::Get()->fullscreen_magnifier_controller()->SetScale( |
| scale_, false /* animate */); |
| } |
| |
| void MagnificationManager::SetMagnifierMouseFollowingModeInternal( |
| MagnifierMouseFollowingMode mouse_following_mode) { |
| Shell::Get()->fullscreen_magnifier_controller()->set_mouse_following_mode( |
| mouse_following_mode); |
| } |
| |
| void MagnificationManager::UpdateMagnifierFromPrefs() { |
| if (!profile_) |
| return; |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| const bool enabled = |
| prefs->GetBoolean(prefs::kAccessibilityScreenMagnifierEnabled); |
| const bool keep_focus_centered = |
| prefs->GetBoolean(prefs::kAccessibilityScreenMagnifierCenterFocus); |
| const double scale = |
| prefs->GetDouble(prefs::kAccessibilityScreenMagnifierScale); |
| const MagnifierMouseFollowingMode mouse_following_mode = |
| static_cast<MagnifierMouseFollowingMode>(prefs->GetInteger( |
| prefs::kAccessibilityScreenMagnifierMouseFollowingMode)); |
| |
| SetMagnifierMouseFollowingModeInternal(mouse_following_mode); |
| SetMagnifierScaleInternal(scale); |
| SetMagnifierKeepFocusCenteredInternal(keep_focus_centered); |
| SetMagnifierEnabledInternal(enabled); |
| |
| AccessibilityStatusEventDetails details( |
| AccessibilityNotificationType::kToggleScreenMagnifier, |
| fullscreen_magnifier_enabled_); |
| |
| if (!AccessibilityManager::Get()) |
| return; |
| AccessibilityManager::Get()->NotifyAccessibilityStatusChanged(details); |
| if (Shell::Get()) |
| Shell::Get()->UpdateCursorCompositingEnabled(); |
| } |
| |
| void MagnificationManager::UpdateDockedMagnifierFromPrefs() { |
| if (!profile_) |
| return; |
| |
| PrefService* prefs = profile_->GetPrefs(); |
| const bool enabled = prefs->GetBoolean(prefs::kDockedMagnifierEnabled); |
| AccessibilityStatusEventDetails details( |
| AccessibilityNotificationType::kToggleDockedMagnifier, enabled); |
| |
| if (!AccessibilityManager::Get()) |
| return; |
| AccessibilityManager::Get()->NotifyAccessibilityStatusChanged(details); |
| } |
| |
| } // namespace ash |