#include "ash/wm/overview/overview_item_view_scheduler.h"
#include <utility>
#include "ash/wm/overview/overview_ui_task_pool.h"
#include "ash/wm/window_util.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chromeos/constants/chromeos_features.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace ash {
namespace {
class OverviewItemViewScheduler : public aura::WindowObserver,
public ui::LayerAnimationObserver,
public views::WidgetObserver {
public:
using CompletionCallback = base::OnceCallback<void(bool should_init_view)>;
OverviewItemViewScheduler() = default;
OverviewItemViewScheduler(const OverviewItemViewScheduler&) = delete;
OverviewItemViewScheduler& operator=(const OverviewItemViewScheduler&) =
delete;
~OverviewItemViewScheduler() override = default;
void Init(aura::Window& overview_item_window,
views::Widget& overview_item_widget,
OverviewUiTaskPool& enter_animation_task_pool,
CompletionCallback completion_cb) {
completion_cb_ = std::move(completion_cb);
CHECK(completion_cb_);
enter_animation_task_pool.AddTask(
base::BindOnce(&OverviewItemViewScheduler::RunCompletionCallback,
weak_ptr_factory_.GetWeakPtr(), true));
window_observation_.Observe(overview_item_widget.GetNativeWindow());
layer_animation_observation_.Observe(
overview_item_widget.GetLayer()->GetAnimator());
widget_observation_.Observe(&overview_item_widget);
}
private:
void OnWindowOpacitySet(aura::Window* window,
ui::PropertyChangeReason reason) override {
if (window->layer()->GetTargetOpacity() > 0.f) {
RunCompletionCallback(true);
}
}
void OnWindowDestroying(aura::Window* window) override {
RunCompletionCallback(false);
}
void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) override {
if (sequence->properties() & ui::LayerAnimationElement::OPACITY) {
RunCompletionCallback(true);
}
}
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {}
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {}
void OnWidgetDestroying(views::Widget* widget) override {
RunCompletionCallback(false);
}
void RunCompletionCallback(bool should_init_view) {
if (completion_cb_) {
std::move(completion_cb_).Run(should_init_view);
}
}
CompletionCallback completion_cb_;
base::ScopedObservation<aura::Window, aura::WindowObserver>
window_observation_{this};
base::ScopedObservation<ui::LayerAnimator, ui::LayerAnimationObserver>
layer_animation_observation_{this};
base::ScopedObservation<views::Widget, views::WidgetObserver>
widget_observation_{this};
base::WeakPtrFactory<OverviewItemViewScheduler> weak_ptr_factory_{this};
};
void ForwardInitSignalToCaller(
base::OnceClosure original_initialize_item_view_cb,
std::unique_ptr<OverviewItemViewScheduler> scheduler,
bool should_initialize_item_view) {
if (should_initialize_item_view) {
CHECK(original_initialize_item_view_cb);
std::move(original_initialize_item_view_cb).Run();
}
}
}
void ScheduleOverviewItemViewInitialization(
aura::Window& overview_item_window,
views::Widget& overview_item_widget,
OverviewUiTaskPool& enter_animation_task_pool,
bool should_enter_without_animations,
base::OnceClosure initialize_item_view_cb) {
CHECK(initialize_item_view_cb);
const bool should_immediately_init_view =
window_util::IsMinimizedOrTucked(&overview_item_window) ||
should_enter_without_animations;
if (should_immediately_init_view) {
std::move(initialize_item_view_cb).Run();
return;
}
auto scheduler = std::make_unique<OverviewItemViewScheduler>();
OverviewItemViewScheduler& scheduler_ref = *scheduler.get();
scheduler_ref.Init(
overview_item_window, overview_item_widget, enter_animation_task_pool,
base::BindOnce(&ForwardInitSignalToCaller,
std::move(initialize_item_view_cb), std::move(scheduler)));
}
}