Commit c2eb607b authored by Sammie Quon's avatar Sammie Quon Committed by Commit Bot

desks: Add autotest api for activating multiple adjacent desks.

This will used for a perf test. Adds an api and a supporting animation
observing class which waits until the animation has been scheduled,
which means the desk ending screenshot has been taken. The observing
class then activates the adjacent desk. This repeats until we have
reached the target desk, then we wait for the whole animation to finish
and run the given callback.

Test: added test
Bug: 1111445
Change-Id: I9f859a2ae31da958c0d539f7e00a1a9944c3bb3d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2437151
Commit-Queue: Sammie Quon <sammiequon@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815409}
parent 6740cd70
......@@ -15,10 +15,9 @@ namespace ash {
class ASH_EXPORT AutotestDesksApi {
public:
AutotestDesksApi();
~AutotestDesksApi();
AutotestDesksApi(const AutotestDesksApi& other) = delete;
AutotestDesksApi& operator=(const AutotestDesksApi& rhs) = delete;
~AutotestDesksApi();
// Creates a new desk if the maximum number of desks has not been reached, and
// returns true if succeeded, false otherwise.
......@@ -34,6 +33,15 @@ class ASH_EXPORT AutotestDesksApi {
// Returns false if the active desk is the last available desk which cannot be
// removed; true otherwise.
bool RemoveActiveDesk(base::OnceClosure on_complete);
// Activates the desk at the given |index| by activating all the desks between
// the current desk and the desk at |index| in succession. This mimics
// pressing the activate adjacent desk accelerator rapidly. |on_complete| will
// be invoked when the the final animation to |index| completes. Returns false
// if |index| is invalid, or the desk at |index| is already the active desk;
// true otherwise.
bool ActivateAdjacentDesksToTargetIndex(int index,
base::OnceClosure on_complete);
};
} // namespace ash
......
......@@ -4,10 +4,19 @@
#include "ash/public/cpp/autotest_desks_api.h"
#include "ash/shell.h"
#include "ash/wm/desks/desk.h"
#include "ash/wm/desks/desk_animation_base.h"
#include "ash/wm/desks/desks_controller.h"
#include "ash/wm/desks/desks_histogram_enums.h"
#include "ash/wm/desks/root_window_desk_switch_animator.h"
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/check.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"
namespace ash {
......@@ -42,6 +51,84 @@ class DeskAnimationObserver : public DesksController::Observer {
base::OnceClosure on_desk_animation_complete_;
};
// Self deleting desk animation observer which takes a target index and then
// waits until the animation layer has scheduled a new animation (ending
// screenshot will have been taken at this point). If the next desk is not the
// target desk, activate the adjacent desk (replacing the current animation). If
// the next desk is the target desk, wait until the animation is finished, then
// run the given callback.
class ChainedDeskAnimationObserver : public ui::LayerAnimationObserver,
public DesksController::Observer {
public:
ChainedDeskAnimationObserver(bool going_left,
int target_index,
base::OnceClosure on_desk_animation_complete)
: going_left_(going_left),
target_index_(target_index),
on_desk_animation_complete_(std::move(on_desk_animation_complete)) {
DesksController::Get()->AddObserver(this);
}
ChainedDeskAnimationObserver(const ChainedDeskAnimationObserver& other) =
delete;
ChainedDeskAnimationObserver& operator=(
const ChainedDeskAnimationObserver& rhs) = delete;
~ChainedDeskAnimationObserver() override {
DesksController::Get()->RemoveObserver(this);
}
// ui::LayerAnimationObserver:
void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) override {}
void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) override {}
void OnLayerAnimationScheduled(
ui::LayerAnimationSequence* sequence) override {
if ((sequence->properties() & ui::LayerAnimationElement::TRANSFORM) == 0)
return;
auto* controller = DesksController::Get();
const bool activated = controller->ActivateAdjacentDesk(
going_left_, DesksSwitchSource::kDeskSwitchShortcut);
DCHECK(activated);
// If the animation goes to the last expected desk, remove the observer so
// that the next scheduled animation does not try activating another desk.
// We will then wait for the entire desk switch animation to finish and then
// run |on_desk_animation_complete_|.
if (controller->GetDeskIndex(controller->GetTargetActiveDesk()) ==
target_index_) {
animation_layer_->GetAnimator()->RemoveObserver(this);
}
}
// DesksController::Observer:
void OnDeskAdded(const Desk* desk) override {}
void OnDeskRemoved(const Desk* desk) override {}
void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override {
// The first activation changed happens when the initial ending screenshot
// is being taken. This is the first point when the animation layer we want
// to observe is guaranteed to be set as a child to the root window layer.
if (animation_layer_)
return;
animation_layer_ = DesksController::Get()
->GetAnimationForTesting()
->GetFirstDeskSwitchAnimatorForTesting()
->GetAnimationLayerForTesting();
animation_layer_->GetAnimator()->AddObserver(this);
}
void OnDeskSwitchAnimationLaunching() override {}
void OnDeskSwitchAnimationFinished() override {
std::move(on_desk_animation_complete_).Run();
delete this;
}
private:
const bool going_left_;
const int target_index_;
base::OnceClosure on_desk_animation_complete_;
ui::Layer* animation_layer_ = nullptr;
};
} // namespace
AutotestDesksApi::AutotestDesksApi() = default;
......@@ -89,4 +176,29 @@ bool AutotestDesksApi::RemoveActiveDesk(base::OnceClosure on_complete) {
return true;
}
bool AutotestDesksApi::ActivateAdjacentDesksToTargetIndex(
int index,
base::OnceClosure on_complete) {
DCHECK(!on_complete.is_null());
if (index < 0)
return false;
auto* controller = DesksController::Get();
if (index >= int{controller->desks().size()})
return false;
const Desk* target_desk = controller->desks()[index].get();
if (target_desk == controller->active_desk())
return false;
int active_index = controller->GetDeskIndex(controller->active_desk());
const bool going_left = index < active_index;
new ChainedDeskAnimationObserver(going_left, index, std::move(on_complete));
const bool activated = controller->ActivateAdjacentDesk(
going_left, DesksSwitchSource::kDeskSwitchShortcut);
DCHECK(activated);
return true;
}
} // namespace ash
......@@ -10,9 +10,41 @@
#include "base/bind_helpers.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
namespace ash {
namespace {
class TestDesksActivationObserver : public DesksController::Observer {
public:
TestDesksActivationObserver() { DesksController::Get()->AddObserver(this); }
TestDesksActivationObserver(const TestDesksActivationObserver&) = delete;
TestDesksActivationObserver& operator=(const TestDesksActivationObserver&) =
delete;
~TestDesksActivationObserver() override {
DesksController::Get()->RemoveObserver(this);
}
int activation_changes() const { return activation_changes_; }
void set_activation_changes(int val) { activation_changes_ = val; }
// DesksController::Observer:
void OnDeskAdded(const Desk* desk) override {}
void OnDeskRemoved(const Desk* desk) override {}
void OnDeskActivationChanged(const Desk* activated,
const Desk* deactivated) override {
++activation_changes_;
}
void OnDeskSwitchAnimationLaunching() override {}
void OnDeskSwitchAnimationFinished() override {}
private:
int activation_changes_ = 0;
};
} // namespace
using AutotestDesksApiTest = AshTestBase;
TEST_F(AutotestDesksApiTest, CreateNewDesk) {
......@@ -74,4 +106,72 @@ TEST_F(AutotestDesksApiTest, RemoveActiveDesk) {
EXPECT_FALSE(test_api.RemoveActiveDesk(base::DoNothing()));
}
class EnhancedDeskAnimationsAutotestDesksApiTest : public AutotestDesksApiTest {
public:
EnhancedDeskAnimationsAutotestDesksApiTest() = default;
EnhancedDeskAnimationsAutotestDesksApiTest(
const EnhancedDeskAnimationsAutotestDesksApiTest&) = delete;
EnhancedDeskAnimationsAutotestDesksApiTest& operator=(
const EnhancedDeskAnimationsAutotestDesksApiTest&) = delete;
~EnhancedDeskAnimationsAutotestDesksApiTest() override = default;
// AutotestDesksApiTest:
void SetUp() override {
features_.InitAndEnableFeature(features::kEnhancedDeskAnimations);
AutotestDesksApiTest::SetUp();
}
private:
base::test::ScopedFeatureList features_;
};
TEST_F(EnhancedDeskAnimationsAutotestDesksApiTest,
ActivateAdjacentDesksToTargetIndex) {
// Create all desks possible.
AutotestDesksApi test_api;
auto* controller = DesksController::Get();
while (controller->CanCreateDesks())
EXPECT_TRUE(test_api.CreateNewDesk());
EXPECT_FALSE(
test_api.ActivateAdjacentDesksToTargetIndex(-1, base::DoNothing()));
EXPECT_FALSE(
test_api.ActivateAdjacentDesksToTargetIndex(4, base::DoNothing()));
// Activating already active desk does nothing.
EXPECT_FALSE(
test_api.ActivateAdjacentDesksToTargetIndex(0, base::DoNothing()));
EXPECT_EQ(4u, controller->desks().size());
// Replacing needs to be done while a current animation is underway, otherwise
// it will have no effect.
ui::ScopedAnimationDurationScaleMode non_zero(
ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
// Activate the rightmost desk. Test that we end on that desk and that we
// observed 3 activation changes.
TestDesksActivationObserver desk_activation_observer;
{
base::RunLoop run_loop;
EXPECT_TRUE(
test_api.ActivateAdjacentDesksToTargetIndex(3, run_loop.QuitClosure()));
run_loop.Run();
}
EXPECT_EQ(controller->active_desk(), controller->desks().back().get());
EXPECT_EQ(3, desk_activation_observer.activation_changes());
// Activate the leftmost desk. Test that we end on that desk and that we
// observed 3 activation changes.
desk_activation_observer.set_activation_changes(0);
{
base::RunLoop run_loop;
EXPECT_TRUE(
test_api.ActivateAdjacentDesksToTargetIndex(0, run_loop.QuitClosure()));
run_loop.Run();
}
EXPECT_EQ(controller->active_desk(), controller->desks().front().get());
EXPECT_EQ(3, desk_activation_observer.activation_changes());
}
} // namespace ash
......@@ -132,4 +132,10 @@ void DeskAnimationBase::OnDeskSwitchAnimationFinished() {
// `this` is now deleted.
}
RootWindowDeskSwitchAnimator*
DeskAnimationBase::GetFirstDeskSwitchAnimatorForTesting() const {
DCHECK(!desk_switch_animators_.empty());
return desk_switch_animators_.front().get();
}
} // namespace ash
......@@ -54,6 +54,8 @@ class DeskAnimationBase : public RootWindowDeskSwitchAnimator::Delegate {
void OnEndingDeskScreenshotTaken() override;
void OnDeskSwitchAnimationFinished() override;
RootWindowDeskSwitchAnimator* GetFirstDeskSwitchAnimatorForTesting() const;
protected:
// Abstract functions that can be overridden by child classes to do different
// things when phase (1), and phase (3) completes. Note that
......
......@@ -432,6 +432,16 @@ void DesksController::OnRootWindowClosing(aura::Window* root_window) {
desk->OnRootWindowClosing(root_window);
}
int DesksController::GetDeskIndex(const Desk* desk) const {
for (size_t i = 0; i < desks_.size(); ++i) {
if (desk == desks_[i].get())
return i;
}
NOTREACHED();
return -1;
}
bool DesksController::BelongsToActiveDesk(aura::Window* window) {
return desks_util::BelongsToActiveDesk(window);
}
......@@ -493,6 +503,11 @@ void DesksController::OnFirstSessionStarted() {
desks_restore_util::RestorePrimaryUserDesks();
}
DeskAnimationBase* DesksController::GetAnimationForTesting() const {
DCHECK(animation_);
return animation_.get();
}
void DesksController::OnAnimationFinished(DeskAnimationBase* animation) {
DCHECK_EQ(animation_.get(), animation);
animation_.reset();
......@@ -505,16 +520,6 @@ bool DesksController::HasDesk(const Desk* desk) const {
return iter != desks_.end();
}
int DesksController::GetDeskIndex(const Desk* desk) const {
for (size_t i = 0; i < desks_.size(); ++i) {
if (desk == desks_[i].get())
return i;
}
NOTREACHED();
return -1;
}
void DesksController::ActivateDeskInternal(const Desk* desk,
bool update_window_activation) {
DCHECK(HasDesk(desk));
......
......@@ -10,6 +10,7 @@
#include <vector>
#include "ash/ash_export.h"
#include "ash/public/cpp/autotest_desks_api.h"
#include "ash/public/cpp/desks_helper.h"
#include "ash/public/cpp/session/session_observer.h"
#include "ash/wm/desks/desks_histogram_enums.h"
......@@ -160,6 +161,8 @@ class ASH_EXPORT DesksController : public DesksHelper,
void OnRootWindowAdded(aura::Window* root_window);
void OnRootWindowClosing(aura::Window* root_window);
int GetDeskIndex(const Desk* desk) const;
// DesksHelper:
bool BelongsToActiveDesk(aura::Window* window) override;
......@@ -175,6 +178,8 @@ class ASH_EXPORT DesksController : public DesksHelper,
void OnActiveUserSessionChanged(const AccountId& account_id) override;
void OnFirstSessionStarted() override;
DeskAnimationBase* GetAnimationForTesting() const;
private:
friend class DeskAnimationBase;
friend class DeskActivationAnimation;
......@@ -184,8 +189,6 @@ class ASH_EXPORT DesksController : public DesksHelper,
bool HasDesk(const Desk* desk) const;
int GetDeskIndex(const Desk* desk) const;
// Activates the given |desk| and deactivates the currently active one. |desk|
// has to be an existing desk. If |update_window_activation| is true,
// the active desk on the deactivated desk will be deactivated, and the most-
......
......@@ -339,6 +339,10 @@ void RootWindowDeskSwitchAnimator::OnImplicitAnimationsCompleted() {
delegate_->OnDeskSwitchAnimationFinished();
}
ui::Layer* RootWindowDeskSwitchAnimator::GetAnimationLayerForTesting() const {
return animation_layer_owner_->root();
}
void RootWindowDeskSwitchAnimator::CompleteAnimationPhase1WithLayer(
std::unique_ptr<ui::Layer> layer) {
DCHECK(layer);
......
......@@ -249,6 +249,8 @@ class ASH_EXPORT RootWindowDeskSwitchAnimator
// ui::ImplicitAnimationObserver:
void OnImplicitAnimationsCompleted() override;
ui::Layer* GetAnimationLayerForTesting() const;
private:
friend class RootWindowDeskSwitchAnimatorTestApi;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment