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)24 FullscreenController::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()34 FullscreenController::~FullscreenController() {
35   auto* power_manager = chromeos::PowerManagerClient::Get();
36   if (power_manager) {
37     power_manager->RemoveObserver(this);
38   }
39 }
40 
41 // static
MaybeExitFullscreen()42 void 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()62 void 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)99 void FullscreenController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
100   registry->RegisterBooleanPref(prefs::kFullscreenAlertEnabled, true,
101                                 PrefRegistry::PUBLIC);
102 }
103 
SuspendImminent(power_manager::SuspendImminent::Reason reason)104 void 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)112 void 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)121 void 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)138 void 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