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 "ash/public/cpp/test/shell_test_api.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "ash/accelerators/accelerator_commands.h"
11 #include "ash/accelerometer/accelerometer_reader.h"
12 #include "ash/app_list/app_list_controller_impl.h"
13 #include "ash/app_list/views/app_list_view.h"
14 #include "ash/keyboard/keyboard_controller_impl.h"
15 #include "ash/public/cpp/autotest_private_api_utils.h"
16 #include "ash/public/cpp/tablet_mode_observer.h"
17 #include "ash/root_window_controller.h"
18 #include "ash/shell.h"
19 #include "ash/system/power/backlights_forced_off_setter.h"
20 #include "ash/system/power/power_button_controller.h"
21 #include "ash/wm/overview/overview_animation_state_waiter.h"
22 #include "ash/wm/overview/overview_controller.h"
23 #include "ash/wm/splitview/split_view_controller.h"
24 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
25 #include "ash/wm/workspace_controller.h"
26 #include "base/run_loop.h"
27 #include "components/prefs/testing_pref_service.h"
28 #include "ui/aura/window_tree_host.h"
29 #include "ui/compositor/compositor.h"
30 #include "ui/compositor/compositor_observer.h"
31 #include "ui/compositor/layer_animation_observer.h"
32 #include "ui/display/manager/display_manager.h"
33 #include "ui/events/devices/device_data_manager_test_api.h"
34 #include "ui/events/gesture_detection/gesture_configuration.h"
35
36 namespace ash {
37 namespace {
38
39 // Wait for a WindowTreeHost to no longer be holding pointer events.
40 class PointerMoveLoopWaiter : public ui::CompositorObserver {
41 public:
PointerMoveLoopWaiter(aura::WindowTreeHost * window_tree_host)42 explicit PointerMoveLoopWaiter(aura::WindowTreeHost* window_tree_host)
43 : window_tree_host_(window_tree_host) {
44 window_tree_host_->compositor()->AddObserver(this);
45 }
46
~PointerMoveLoopWaiter()47 ~PointerMoveLoopWaiter() override {
48 window_tree_host_->compositor()->RemoveObserver(this);
49 }
50
Wait()51 void Wait() {
52 // Use a while loop as it's possible for releasing the lock to trigger
53 // processing events, which again grabs the lock.
54 while (window_tree_host_->holding_pointer_moves()) {
55 run_loop_ = std::make_unique<base::RunLoop>(
56 base::RunLoop::Type::kNestableTasksAllowed);
57 run_loop_->Run();
58 run_loop_.reset();
59 }
60 }
61
62 // ui::CompositorObserver:
OnCompositingEnded(ui::Compositor * compositor)63 void OnCompositingEnded(ui::Compositor* compositor) override {
64 if (run_loop_)
65 run_loop_->Quit();
66 }
67
68 private:
69 aura::WindowTreeHost* window_tree_host_;
70 std::unique_ptr<base::RunLoop> run_loop_;
71
72 DISALLOW_COPY_AND_ASSIGN(PointerMoveLoopWaiter);
73 };
74
75 class WindowAnimationWaiter : public ui::LayerAnimationObserver {
76 public:
WindowAnimationWaiter(aura::Window * window)77 explicit WindowAnimationWaiter(aura::Window* window)
78 : animator_(window->layer()->GetAnimator()) {
79 animator_->AddObserver(this);
80 }
81 ~WindowAnimationWaiter() override = default;
82
83 WindowAnimationWaiter(const WindowAnimationWaiter& other) = delete;
84 WindowAnimationWaiter& operator=(const WindowAnimationWaiter& rhs) = delete;
85
86 // ui::LayerAnimationObserver:
OnLayerAnimationEnded(ui::LayerAnimationSequence * sequence)87 void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
88 if (!animator_->is_animating()) {
89 animator_->RemoveObserver(this);
90 run_loop_.Quit();
91 }
92 }
OnLayerAnimationAborted(ui::LayerAnimationSequence * sequence)93 void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {}
OnLayerAnimationScheduled(ui::LayerAnimationSequence * sequence)94 void OnLayerAnimationScheduled(
95 ui::LayerAnimationSequence* sequence) override {}
96
Wait()97 void Wait() {
98 run_loop_.Run();
99 }
100
101 private:
102 ui::LayerAnimator* animator_;
103 base::RunLoop run_loop_;
104 };
105
106 } // namespace
107
ShellTestApi()108 ShellTestApi::ShellTestApi() : shell_(Shell::Get()) {}
109 ShellTestApi::~ShellTestApi() = default;
110
111 // static
SetTabletControllerUseScreenshotForTest(bool use_screenshot)112 void ShellTestApi::SetTabletControllerUseScreenshotForTest(
113 bool use_screenshot) {
114 TabletModeController::SetUseScreenshotForTest(use_screenshot);
115 }
116
message_center_controller()117 MessageCenterController* ShellTestApi::message_center_controller() {
118 return shell_->message_center_controller_.get();
119 }
120
system_gesture_event_filter()121 SystemGestureEventFilter* ShellTestApi::system_gesture_event_filter() {
122 return shell_->system_gesture_filter_.get();
123 }
124
workspace_controller()125 WorkspaceController* ShellTestApi::workspace_controller() {
126 // TODO(afakhry): Split this into two, one for root, and one for context.
127 return GetActiveWorkspaceController(shell_->GetPrimaryRootWindow());
128 }
129
screen_position_controller()130 ScreenPositionController* ShellTestApi::screen_position_controller() {
131 return shell_->screen_position_controller_.get();
132 }
133
native_cursor_manager_ash()134 NativeCursorManagerAsh* ShellTestApi::native_cursor_manager_ash() {
135 return shell_->native_cursor_manager_;
136 }
137
drag_drop_controller()138 DragDropController* ShellTestApi::drag_drop_controller() {
139 return shell_->drag_drop_controller_.get();
140 }
141
power_prefs()142 PowerPrefs* ShellTestApi::power_prefs() {
143 return shell_->power_prefs_.get();
144 }
145
display_manager()146 display::DisplayManager* ShellTestApi::display_manager() {
147 return shell_->display_manager();
148 }
149
ResetPowerButtonControllerForTest()150 void ShellTestApi::ResetPowerButtonControllerForTest() {
151 shell_->backlights_forced_off_setter_->ResetForTest();
152 shell_->power_button_controller_ = std::make_unique<PowerButtonController>(
153 shell_->backlights_forced_off_setter_.get());
154 }
155
SimulateModalWindowOpenForTest(bool modal_window_open)156 void ShellTestApi::SimulateModalWindowOpenForTest(bool modal_window_open) {
157 shell_->simulate_modal_window_open_for_test_ = modal_window_open;
158 }
159
IsSystemModalWindowOpen()160 bool ShellTestApi::IsSystemModalWindowOpen() {
161 return Shell::IsSystemModalWindowOpen();
162 }
163
SetTabletModeEnabledForTest(bool enable,bool wait_for_completion)164 void ShellTestApi::SetTabletModeEnabledForTest(bool enable,
165 bool wait_for_completion) {
166 // Detach mouse devices, so we can enter tablet mode.
167 // Calling RunUntilIdle() here is necessary before setting the mouse devices
168 // to prevent the callback from evdev thread from overwriting whatever we set
169 // here below. See `InputDeviceFactoryEvdevProxy::OnStartupScanComplete()`.
170 base::RunLoop().RunUntilIdle();
171 ui::DeviceDataManagerTestApi().OnDeviceListsComplete();
172 ui::DeviceDataManagerTestApi().SetMouseDevices({});
173
174 TabletMode::Waiter waiter(enable);
175 shell_->tablet_mode_controller()->SetEnabledForTest(enable);
176 waiter.Wait();
177 }
178
EnableVirtualKeyboard()179 void ShellTestApi::EnableVirtualKeyboard() {
180 shell_->keyboard_controller()->SetEnableFlag(
181 keyboard::KeyboardEnableFlag::kCommandLineEnabled);
182 }
183
ToggleFullscreen()184 void ShellTestApi::ToggleFullscreen() {
185 accelerators::ToggleFullscreen();
186 }
187
IsOverviewSelecting()188 bool ShellTestApi::IsOverviewSelecting() {
189 return shell_->overview_controller()->InOverviewSession();
190 }
191
AddRemoveDisplay()192 void ShellTestApi::AddRemoveDisplay() {
193 shell_->display_manager()->AddRemoveDisplay();
194 }
195
WaitForNoPointerHoldLock()196 void ShellTestApi::WaitForNoPointerHoldLock() {
197 aura::WindowTreeHost* primary_host =
198 Shell::GetPrimaryRootWindowController()->GetHost();
199 if (primary_host->holding_pointer_moves())
200 PointerMoveLoopWaiter(primary_host).Wait();
201 }
202
WaitForNextFrame(base::OnceClosure closure)203 void ShellTestApi::WaitForNextFrame(base::OnceClosure closure) {
204 Shell::GetPrimaryRootWindowController()
205 ->GetHost()
206 ->compositor()
207 ->RequestPresentationTimeForNextFrame(base::BindOnce(
208 [](base::OnceClosure closure,
209 const gfx::PresentationFeedback& feedback) {
210 std::move(closure).Run();
211 },
212 std::move(closure)));
213 }
214
WaitForOverviewAnimationState(OverviewAnimationState state)215 void ShellTestApi::WaitForOverviewAnimationState(OverviewAnimationState state) {
216 auto* overview_controller = shell_->overview_controller();
217 if (state == OverviewAnimationState::kEnterAnimationComplete &&
218 overview_controller->InOverviewSession() &&
219 !overview_controller->IsInStartAnimation()) {
220 // If there is no animation applied, call the callback immediately.
221 return;
222 }
223 if (state == OverviewAnimationState::kExitAnimationComplete &&
224 !overview_controller->InOverviewSession() &&
225 !overview_controller->IsCompletingShutdownAnimations()) {
226 // If there is no animation applied, call the callback immediately.
227 return;
228 }
229 base::RunLoop run_loop;
230 new OverviewAnimationStateWaiter(
231 state, base::BindOnce([](base::RunLoop* run_loop,
232 bool finished) { run_loop->QuitWhenIdle(); },
233 base::Unretained(&run_loop)));
234 run_loop.Run();
235 }
236
WaitForLauncherAnimationState(AppListViewState target_state)237 void ShellTestApi::WaitForLauncherAnimationState(
238 AppListViewState target_state) {
239 base::RunLoop run_loop;
240 WaitForLauncherState(target_state, run_loop.QuitWhenIdleClosure());
241 run_loop.Run();
242 }
243
WaitForWindowFinishAnimating(aura::Window * window)244 void ShellTestApi::WaitForWindowFinishAnimating(aura::Window* window) {
245 WindowAnimationWaiter waiter(window);
246 waiter.Wait();
247 }
248
CreateWaiterForFinishingWindowAnimation(aura::Window * window)249 base::OnceClosure ShellTestApi::CreateWaiterForFinishingWindowAnimation(
250 aura::Window* window) {
251 auto waiter = std::make_unique<WindowAnimationWaiter>(window);
252 return base::BindOnce(&WindowAnimationWaiter::Wait, std::move(waiter));
253 }
254
GetAppListPaginationModel()255 PaginationModel* ShellTestApi::GetAppListPaginationModel() {
256 AppListView* view =
257 Shell::Get()->app_list_controller()->presenter()->GetView();
258 if (!view)
259 return nullptr;
260 return view->GetAppsPaginationModel();
261 }
262
GetItemWindowListInOverviewGrids()263 std::vector<aura::Window*> ShellTestApi::GetItemWindowListInOverviewGrids() {
264 return Shell::Get()
265 ->overview_controller()
266 ->GetItemWindowListInOverviewGridsForTest();
267 }
268
269 } // namespace ash
270