1 // Copyright 2020 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 "ash/session/fullscreen_controller.h" 6 7 #include <limits> 8 9 #include "ash/public/cpp/ash_features.h" 10 #include "ash/public/cpp/ash_pref_names.h" 11 #include "ash/session/fullscreen_alert_bubble.h" 12 #include "ash/session/session_controller_impl.h" 13 #include "ash/shelf/shelf.h" 14 #include "ash/shell.h" 15 #include "ash/wm/window_state.h" 16 #include "ash/wm/wm_event.h" 17 #include "chromeos/dbus/power_manager/backlight.pb.h" 18 #include "chromeos/dbus/power_manager/idle.pb.h" 19 #include "components/prefs/pref_registry_simple.h" 20 #include "components/prefs/pref_service.h" 21 22 namespace ash { 23 FullscreenController(SessionControllerImpl * session_controller)24FullscreenController::FullscreenController( 25 SessionControllerImpl* session_controller) 26 : session_controller_(session_controller) { 27 auto* power_manager = chromeos::PowerManagerClient::Get(); 28 // Might be nullptr in tests. 29 if (power_manager) { 30 power_manager->AddObserver(this); 31 } 32 } 33 ~FullscreenController()34FullscreenController::~FullscreenController() { 35 auto* power_manager = chromeos::PowerManagerClient::Get(); 36 if (power_manager) { 37 power_manager->RemoveObserver(this); 38 } 39 } 40 41 // static MaybeExitFullscreen()42void FullscreenController::MaybeExitFullscreen() { 43 // If the active window is fullscreen, exit fullscreen to avoid the web page 44 // or app mimicking the lock screen. Do not exit fullscreen if the shelf is 45 // visible while in fullscreen because the shelf makes it harder for a web 46 // page or app to mimic the lock screen. 47 WindowState* active_window_state = WindowState::ForActiveWindow(); 48 if (!active_window_state || !active_window_state->IsFullscreen()) 49 return; 50 51 Shelf* shelf = Shelf::ForWindow(active_window_state->window()); 52 const bool shelf_visible = 53 shelf->GetVisibilityState() == ShelfVisibilityState::SHELF_VISIBLE; 54 55 if (shelf_visible && !active_window_state->GetHideShelfWhenFullscreen()) 56 return; 57 58 const WMEvent event(WM_EVENT_TOGGLE_FULLSCREEN); 59 active_window_state->OnWMEvent(&event); 60 } 61 MaybeShowAlert()62void FullscreenController::MaybeShowAlert() { 63 if (!features::IsFullscreenAlertBubbleEnabled()) 64 return; 65 66 auto* session_controler = Shell::Get()->session_controller(); 67 68 // Check if a user session is active to exclude OOBE process. 69 if (session_controler->GetSessionState() != 70 session_manager::SessionState::ACTIVE) { 71 return; 72 } 73 74 auto* prefs = session_controler->GetPrimaryUserPrefService(); 75 76 if (!prefs->GetBoolean(prefs::kFullscreenAlertEnabled)) 77 return; 78 79 // Check if the activate window is fullscreen. 80 WindowState* active_window_state = WindowState::ForActiveWindow(); 81 if (!active_window_state || !active_window_state->IsFullscreen()) 82 return; 83 84 // Check if the shelf is visible. 85 Shelf* shelf = Shelf::ForWindow(active_window_state->window()); 86 const bool shelf_visible = 87 shelf->GetVisibilityState() == ShelfVisibilityState::SHELF_VISIBLE; 88 89 if (shelf_visible && !active_window_state->GetHideShelfWhenFullscreen()) 90 return; 91 92 if (!bubble_) 93 bubble_ = std::make_unique<FullscreenAlertBubble>(); 94 95 bubble_->Show(); 96 } 97 98 // static RegisterProfilePrefs(PrefRegistrySimple * registry)99void FullscreenController::RegisterProfilePrefs(PrefRegistrySimple* registry) { 100 registry->RegisterBooleanPref(prefs::kFullscreenAlertEnabled, true, 101 PrefRegistry::PUBLIC); 102 } 103 SuspendImminent(power_manager::SuspendImminent::Reason reason)104void FullscreenController::SuspendImminent( 105 power_manager::SuspendImminent::Reason reason) { 106 if (session_controller_->login_status() != LoginStatus::GUEST) 107 return; 108 109 MaybeExitFullscreen(); 110 } 111 ScreenIdleStateChanged(const power_manager::ScreenIdleState & proto)112void FullscreenController::ScreenIdleStateChanged( 113 const power_manager::ScreenIdleState& proto) { 114 if (session_controller_->login_status() != LoginStatus::GUEST) 115 return; 116 117 if (proto.off() || proto.dimmed()) 118 MaybeExitFullscreen(); 119 } 120 ScreenBrightnessChanged(const power_manager::BacklightBrightnessChange & change)121void FullscreenController::ScreenBrightnessChanged( 122 const power_manager::BacklightBrightnessChange& change) { 123 // Show alert when the device returns from low (epsilon) brightness which 124 // covers three cases. 125 // 1. The device returns from sleep. 126 // 2. The device lid is opended (with sleep on). 127 // 3. The device returns from low display brightness. 128 double epsilon = std::numeric_limits<double>::epsilon(); 129 if (change.percent() <= epsilon) { 130 device_in_dark_ = true; 131 } else { 132 if (device_in_dark_) 133 MaybeShowAlert(); 134 device_in_dark_ = false; 135 } 136 } 137 LidEventReceived(chromeos::PowerManagerClient::LidState state,const base::TimeTicks & timestamp)138void FullscreenController::LidEventReceived( 139 chromeos::PowerManagerClient::LidState state, 140 const base::TimeTicks& timestamp) { 141 // Show alert when the lid is opened. This also covers the case when the user 142 // turn off "Sleep when cover is closed". 143 if (state == chromeos::PowerManagerClient::LidState::OPEN) 144 MaybeShowAlert(); 145 } 146 147 } // namespace ash 148