| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include"ash/public/cpp/autotest_private_api_utils.h" |
| |
| #include<optional> |
| |
| #include"ash/app_list/app_list_controller_impl.h" |
| #include"ash/app_list/app_list_presenter_impl.h" |
| #include"ash/frame/non_client_frame_view_ash.h" |
| #include"ash/shell.h" |
| #include"ash/wm/mru_window_tracker.h" |
| #include"ash/wm/tablet_mode/scoped_skip_user_session_blocked_check.h" |
| #include"base/functional/bind.h" |
| #include"base/functional/callback_helpers.h" |
| #include"base/memory/raw_ptr.h" |
| #include"base/scoped_observation.h" |
| #include"ui/compositor/layer.h" |
| #include"ui/compositor/layer_animation_observer.h" |
| #include"ui/compositor/layer_animator.h" |
| #include"ui/display/screen.h" |
| |
| namespace ash{ |
| namespace{ |
| |
| classHomeLauncherStateWaiter{ |
| public: |
| HomeLauncherStateWaiter(bool target_shown, base::OnceClosure closure) |
| : target_shown_(target_shown), closure_(std::move(closure)){ |
| Shell::Get() |
| ->app_list_controller() |
| ->SetHomeLauncherAnimationCallbackForTesting(base::BindRepeating( |
| &HomeLauncherStateWaiter::OnHomeLauncherAnimationCompleted, |
| base::Unretained(this))); |
| } |
| |
| HomeLauncherStateWaiter(constHomeLauncherStateWaiter&)=delete; |
| HomeLauncherStateWaiter&operator=(constHomeLauncherStateWaiter&)=delete; |
| |
| ~HomeLauncherStateWaiter(){ |
| Shell::Get() |
| ->app_list_controller() |
| ->SetHomeLauncherAnimationCallbackForTesting(base::NullCallback()); |
| } |
| |
| private: |
| // Passed to AppListControllerImpl as a callback to run when home launcher |
| // transition animation is complete. |
| voidOnHomeLauncherAnimationCompleted(bool shown){ |
| if(shown== target_shown_){ |
| std::move(closure_).Run(); |
| deletethis; |
| } |
| } |
| |
| bool target_shown_; |
| base::OnceClosure closure_; |
| }; |
| |
| // A waiter that waits until the animation ended with the target state, and |
| // execute the callback. This self destruction upon completion. |
| classLauncherStateWaiter{ |
| public: |
| LauncherStateWaiter(ash::AppListViewState state, base::OnceClosure closure) |
| : target_state_(state), closure_(std::move(closure)){ |
| Shell::Get() |
| ->app_list_controller() |
| ->SetStateTransitionAnimationCallbackForTesting(base::BindRepeating( |
| &LauncherStateWaiter::OnStateChanged, base::Unretained(this))); |
| } |
| |
| LauncherStateWaiter(constLauncherStateWaiter&)=delete; |
| LauncherStateWaiter&operator=(constLauncherStateWaiter&)=delete; |
| |
| ~LauncherStateWaiter(){ |
| Shell::Get() |
| ->app_list_controller() |
| ->SetStateTransitionAnimationCallbackForTesting(base::NullCallback()); |
| } |
| |
| voidOnStateChanged(ash::AppListViewState state){ |
| if(target_state_== state){ |
| std::move(closure_).Run(); |
| deletethis; |
| } |
| } |
| |
| private: |
| ash::AppListViewState target_state_; |
| base::OnceClosure closure_; |
| }; |
| |
| classLauncherAnimationWaiter:public ui::LayerAnimationObserver{ |
| public: |
| LauncherAnimationWaiter(AppListView* view, base::OnceClosure closure) |
| : closure_(std::move(closure)){ |
| observation_.Observe(view->GetWidget()->GetLayer()->GetAnimator()); |
| } |
| ~LauncherAnimationWaiter() override=default; |
| LauncherAnimationWaiter(constLauncherAnimationWaiter&)=delete; |
| LauncherAnimationWaiter&operator=(constLauncherAnimationWaiter&)=delete; |
| |
| private: |
| // ui::LayerAnimationObserver: |
| voidOnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override{ |
| std::move(closure_).Run(); |
| deletethis; |
| } |
| voidOnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override{ |
| OnLayerAnimationEnded(sequence); |
| } |
| voidOnLayerAnimationScheduled( |
| ui::LayerAnimationSequence* sequence) override{} |
| |
| base::OnceClosure closure_; |
| base::ScopedObservation<ui::LayerAnimator, ui::LayerAnimationObserver> |
| observation_{this}; |
| }; |
| |
| boolWaitForHomeLauncherState(bool target_visible, base::OnceClosure closure){ |
| if(Shell::Get()->app_list_controller()->IsVisible( |
| /*display_id=*/std::nullopt)== target_visible){ |
| std::move(closure).Run(); |
| returntrue; |
| } |
| |
| newHomeLauncherStateWaiter(target_visible, std::move(closure)); |
| returnfalse; |
| } |
| |
| boolWaitForLauncherAnimation(base::OnceClosure closure){ |
| auto* app_list_view= |
| Shell::Get()->app_list_controller()->fullscreen_presenter()->GetView(); |
| if(!app_list_view){ |
| std::move(closure).Run(); |
| returntrue; |
| } |
| bool animating= |
| app_list_view->GetWidget()->GetLayer()->GetAnimator()->is_animating(); |
| if(!animating){ |
| std::move(closure).Run(); |
| returntrue; |
| } |
| newLauncherAnimationWaiter(app_list_view, std::move(closure)); |
| returnfalse; |
| } |
| |
| }// namespace |
| |
| std::vector<raw_ptr<aura::Window,VectorExperimental>>GetAppWindowList(){ |
| ScopedSkipUserSessionBlockedCheck skip_session_blocked; |
| returnShell::Get()->mru_window_tracker()->BuildAppWindowList(kAllDesks); |
| } |
| |
| boolWaitForLauncherState(AppListViewState target_state, |
| base::OnceClosure closure){ |
| constbool in_tablet_mode= display::Screen::GetScreen()->InTabletMode(); |
| if(in_tablet_mode){ |
| // App-list can't enter kPeeking or kHalf state in tablet mode. Thus |
| // |target_state| should be either kClosed, kFullscreenAllApps or |
| // kFullscreenSearch. |
| DCHECK(target_state==AppListViewState::kClosed|| |
| target_state==AppListViewState::kFullscreenAllApps|| |
| target_state==AppListViewState::kFullscreenSearch); |
| } |
| |
| // In the tablet mode, home launcher visibility state needs special handling, |
| // as app list view visibility does not match home launcher visibility. The |
| // app list view is always visible, but the home launcher may be obscured by |
| // app windows. The waiter interprets waits for kClosed state as waits |
| // "home launcher not visible" state - note that the app list view |
| // is actually expected to be in a visible state. |
| AppListViewState effective_target_state= |
| in_tablet_mode&& target_state==AppListViewState::kClosed |
| ?AppListViewState::kFullscreenAllApps |
| : target_state; |
| |
| std::optional<bool> target_home_launcher_visibility; |
| if(in_tablet_mode) |
| target_home_launcher_visibility= target_state!=AppListViewState::kClosed; |
| |
| // Don't wait if the launcher is already in the target state and not |
| // animating. |
| auto* app_list_view= |
| Shell::Get()->app_list_controller()->fullscreen_presenter()->GetView(); |
| bool animating= |
| app_list_view&& |
| app_list_view->GetWidget()->GetLayer()->GetAnimator()->is_animating(); |
| bool at_target_state= |
| (!app_list_view&& effective_target_state==AppListViewState::kClosed)|| |
| (app_list_view&& |
| app_list_view->app_list_state()== effective_target_state); |
| |
| if(at_target_state&&!animating){ |
| // In tablet mode, ensure that the home launcher is in the expected state. |
| if(target_home_launcher_visibility.has_value()){ |
| returnWaitForHomeLauncherState(*target_home_launcher_visibility, |
| std::move(closure)); |
| } |
| std::move(closure).Run(); |
| returntrue; |
| } |
| |
| // In tablet mode, ensure that the home launcher is in the expected state. |
| base::OnceClosure callback= |
| target_home_launcher_visibility.has_value() |
| ? base::BindOnce(base::IgnoreResult(&WaitForHomeLauncherState), |
| *target_home_launcher_visibility, std::move(closure)) |
| : std::move(closure); |
| if(at_target_state) |
| returnWaitForLauncherAnimation(std::move(callback)); |
| newLauncherStateWaiter( |
| target_state, |
| base::BindOnce(base::IgnoreResult(&WaitForLauncherAnimation), |
| std::move(callback))); |
| returnfalse; |
| } |
| |
| }// namespace ash |