1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/public/cpp/autotest_private_api_utils.h"
7 #include "ash/app_list/app_list_controller_impl.h"
8 #include "ash/app_list/app_list_presenter_impl.h"
9 #include "ash/frame/non_client_frame_view_ash.h"
10 #include "ash/shell.h"
11 #include "ash/wm/mru_window_tracker.h"
12 #include "ash/wm/tablet_mode/scoped_skip_user_session_blocked_check.h"
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/scoped_observation.h"
16 #include "third_party/abseil-cpp/absl/types/optional.h"
17 #include "ui/compositor/layer.h"
18 #include "ui/compositor/layer_animation_observer.h"
19 #include "ui/compositor/layer_animator.h"
24 class HomeLauncherStateWaiter {
26 HomeLauncherStateWaiter(bool target_shown, base::OnceClosure closure)
27 : target_shown_(target_shown), closure_(std::move(closure)) {
29 ->app_list_controller()
30 ->SetHomeLauncherAnimationCallbackForTesting(base::BindRepeating(
31 &HomeLauncherStateWaiter::OnHomeLauncherAnimationCompleted,
32 base::Unretained(this)));
35 HomeLauncherStateWaiter(const HomeLauncherStateWaiter&) = delete;
36 HomeLauncherStateWaiter& operator=(const HomeLauncherStateWaiter&) = delete;
38 ~HomeLauncherStateWaiter() {
40 ->app_list_controller()
41 ->SetHomeLauncherAnimationCallbackForTesting(base::NullCallback());
45 // Passed to AppListControllerImpl as a callback to run when home launcher
46 // transition animation is complete.
47 void OnHomeLauncherAnimationCompleted(bool shown) {
48 if (shown == target_shown_) {
49 std::move(closure_).Run();
55 base::OnceClosure closure_;
58 // A waiter that waits until the animation ended with the target state, and
59 // execute the callback. This self destruction upon completion.
60 class LauncherStateWaiter {
62 LauncherStateWaiter(ash::AppListViewState state, base::OnceClosure closure)
63 : target_state_(state), closure_(std::move(closure)) {
65 ->app_list_controller()
66 ->SetStateTransitionAnimationCallbackForTesting(base::BindRepeating(
67 &LauncherStateWaiter::OnStateChanged, base::Unretained(this)));
70 LauncherStateWaiter(const LauncherStateWaiter&) = delete;
71 LauncherStateWaiter& operator=(const LauncherStateWaiter&) = delete;
73 ~LauncherStateWaiter() {
75 ->app_list_controller()
76 ->SetStateTransitionAnimationCallbackForTesting(base::NullCallback());
79 void OnStateChanged(ash::AppListViewState state) {
80 if (target_state_ == state) {
81 std::move(closure_).Run();
87 ash::AppListViewState target_state_;
88 base::OnceClosure closure_;
91 class LauncherAnimationWaiter : public ui::LayerAnimationObserver {
93 LauncherAnimationWaiter(AppListView* view, base::OnceClosure closure)
94 : closure_(std::move(closure)) {
95 observation_.Observe(view->GetWidget()->GetLayer()->GetAnimator());
97 ~LauncherAnimationWaiter() override = default;
98 LauncherAnimationWaiter(const LauncherAnimationWaiter&) = delete;
99 LauncherAnimationWaiter& operator=(const LauncherAnimationWaiter&) = delete;
102 // ui::LayerAnimationObserver:
103 void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {
104 std::move(closure_).Run();
107 void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {
108 OnLayerAnimationEnded(sequence);
110 void OnLayerAnimationScheduled(
111 ui::LayerAnimationSequence* sequence) override {}
113 base::OnceClosure closure_;
114 base::ScopedObservation<ui::LayerAnimator, ui::LayerAnimationObserver>
118 bool WaitForHomeLauncherState(bool target_visible, base::OnceClosure closure) {
119 if (Shell::Get()->app_list_controller()->IsVisible(
120 /*display_id=*/absl::nullopt) == target_visible) {
121 std::move(closure).Run();
125 new HomeLauncherStateWaiter(target_visible, std::move(closure));
129 bool WaitForLauncherAnimation(base::OnceClosure closure) {
130 auto* app_list_view =
131 Shell::Get()->app_list_controller()->fullscreen_presenter()->GetView();
132 if (!app_list_view) {
133 std::move(closure).Run();
137 app_list_view->GetWidget()->GetLayer()->GetAnimator()->is_animating();
139 std::move(closure).Run();
142 new LauncherAnimationWaiter(app_list_view, std::move(closure));
148 std::vector<aura::Window*> GetAppWindowList() {
149 ScopedSkipUserSessionBlockedCheck skip_session_blocked;
150 return Shell::Get()->mru_window_tracker()->BuildAppWindowList(kAllDesks);
153 bool WaitForLauncherState(AppListViewState target_state,
154 base::OnceClosure closure) {
155 const bool in_tablet_mode =
156 Shell::Get()->tablet_mode_controller()->InTabletMode();
157 if (in_tablet_mode) {
158 // App-list can't enter kPeeking or kHalf state in tablet mode. Thus
159 // |target_state| should be either kClosed, kFullscreenAllApps or
160 // kFullscreenSearch.
161 DCHECK(target_state == AppListViewState::kClosed ||
162 target_state == AppListViewState::kFullscreenAllApps ||
163 target_state == AppListViewState::kFullscreenSearch);
166 // In the tablet mode, home launcher visibility state needs special handling,
167 // as app list view visibility does not match home launcher visibility. The
168 // app list view is always visible, but the home launcher may be obscured by
169 // app windows. The waiter interprets waits for kClosed state as waits
170 // "home launcher not visible" state - note that the app list view
171 // is actually expected to be in a visible state.
172 AppListViewState effective_target_state =
173 in_tablet_mode && target_state == AppListViewState::kClosed
174 ? AppListViewState::kFullscreenAllApps
177 absl::optional<bool> target_home_launcher_visibility;
179 target_home_launcher_visibility = target_state != AppListViewState::kClosed;
181 // Don't wait if the launcher is already in the target state and not
183 auto* app_list_view =
184 Shell::Get()->app_list_controller()->fullscreen_presenter()->GetView();
187 app_list_view->GetWidget()->GetLayer()->GetAnimator()->is_animating();
188 bool at_target_state =
189 (!app_list_view && effective_target_state == AppListViewState::kClosed) ||
191 app_list_view->app_list_state() == effective_target_state);
193 if (at_target_state && !animating) {
194 // In tablet mode, ensure that the home launcher is in the expected state.
195 if (target_home_launcher_visibility.has_value()) {
196 return WaitForHomeLauncherState(*target_home_launcher_visibility,
199 std::move(closure).Run();
203 // In tablet mode, ensure that the home launcher is in the expected state.
204 base::OnceClosure callback =
205 target_home_launcher_visibility.has_value()
206 ? base::BindOnce(base::IgnoreResult(&WaitForHomeLauncherState),
207 *target_home_launcher_visibility, std::move(closure))
208 : std::move(closure);
210 return WaitForLauncherAnimation(std::move(callback));
211 new LauncherStateWaiter(
213 base::BindOnce(base::IgnoreResult(&WaitForLauncherAnimation),
214 std::move(callback)));