Commit 77bfc27f authored by Mitsuru Oshima's avatar Mitsuru Oshima Committed by Commit Bot

Launcher Animations interactive ui tests

Bug: 947154
Change-Id: If5d8ce33b7c54e0b33e89354ec81c23f92990138
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1559208
Commit-Queue: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#649710}
parent f666352f
...@@ -760,6 +760,11 @@ app_list::AppListViewState AppListControllerImpl::CalculateStateAfterShelfDrag( ...@@ -760,6 +760,11 @@ app_list::AppListViewState AppListControllerImpl::CalculateStateAfterShelfDrag(
return app_list::AppListViewState::CLOSED; return app_list::AppListViewState::CLOSED;
} }
void AppListControllerImpl::SetStateTransitionAnimationCallback(
StateTransitionAnimationCallback callback) {
state_transition_animation_callback_ = std::move(callback);
}
void AppListControllerImpl::SetAppListModelForTest( void AppListControllerImpl::SetAppListModelForTest(
std::unique_ptr<app_list::AppListModel> model) { std::unique_ptr<app_list::AppListModel> model) {
model_->RemoveObserver(this); model_->RemoveObserver(this);
...@@ -1025,6 +1030,12 @@ bool AppListControllerImpl::IsAssistantAllowedAndEnabled() const { ...@@ -1025,6 +1030,12 @@ bool AppListControllerImpl::IsAssistantAllowedAndEnabled() const {
mojom::VoiceInteractionState::NOT_READY; mojom::VoiceInteractionState::NOT_READY;
} }
void AppListControllerImpl::OnStateTransitionAnimationCompleted(
app_list::AppListViewState state) {
if (!state_transition_animation_callback_.is_null())
state_transition_animation_callback_.Run(state);
}
void AppListControllerImpl::AddObserver(AppListControllerObserver* observer) { void AppListControllerImpl::AddObserver(AppListControllerObserver* observer) {
observers_.AddObserver(observer); observers_.AddObserver(observer);
} }
......
...@@ -200,6 +200,8 @@ class ASH_EXPORT AppListControllerImpl ...@@ -200,6 +200,8 @@ class ASH_EXPORT AppListControllerImpl
void OnSearchResultVisibilityChanged(const std::string& id, void OnSearchResultVisibilityChanged(const std::string& id,
bool visibility) override; bool visibility) override;
bool IsAssistantAllowedAndEnabled() const override; bool IsAssistantAllowedAndEnabled() const override;
void OnStateTransitionAnimationCompleted(
app_list::AppListViewState state) override;
void AddObserver(AppListControllerObserver* observer); void AddObserver(AppListControllerObserver* observer);
void RemoveObserver(AppListControllerObserver* obsever); void RemoveObserver(AppListControllerObserver* obsever);
...@@ -286,6 +288,12 @@ class ASH_EXPORT AppListControllerImpl ...@@ -286,6 +288,12 @@ class ASH_EXPORT AppListControllerImpl
void SetAppListModelForTest(std::unique_ptr<app_list::AppListModel> model); void SetAppListModelForTest(std::unique_ptr<app_list::AppListModel> model);
using StateTransitionAnimationCallback =
base::RepeatingCallback<void(app_list::AppListViewState)>;
void SetStateTransitionAnimationCallback(
StateTransitionAnimationCallback callback);
private: private:
syncer::StringOrdinal GetOemFolderPos(); syncer::StringOrdinal GetOemFolderPos();
std::unique_ptr<app_list::AppListItem> CreateAppListItem( std::unique_ptr<app_list::AppListItem> CreateAppListItem(
...@@ -336,6 +344,8 @@ class ASH_EXPORT AppListControllerImpl ...@@ -336,6 +344,8 @@ class ASH_EXPORT AppListControllerImpl
// each profile has its own AppListModelUpdater to manipulate app list items. // each profile has its own AppListModelUpdater to manipulate app list items.
int profile_id_ = kAppListInvalidProfileID; int profile_id_ = kAppListInvalidProfileID;
StateTransitionAnimationCallback state_transition_animation_callback_;
base::ObserverList<AppListControllerObserver> observers_; base::ObserverList<AppListControllerObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(AppListControllerImpl); DISALLOW_COPY_AND_ASSIGN(AppListControllerImpl);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <vector> #include <vector>
#include "ash/app_list/app_list_metrics.h" #include "ash/app_list/app_list_metrics.h"
#include "ash/app_list/model/app_list_view_state.h"
#include "ash/assistant/ui/assistant_view_delegate.h" #include "ash/assistant/ui/assistant_view_delegate.h"
#include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/ash_public_export.h"
#include "ash/public/interfaces/app_list.mojom.h" #include "ash/public/interfaces/app_list.mojom.h"
...@@ -167,6 +168,9 @@ class ASH_PUBLIC_EXPORT AppListViewDelegate { ...@@ -167,6 +168,9 @@ class ASH_PUBLIC_EXPORT AppListViewDelegate {
// Returns if the Assistant feature is allowed and enabled. // Returns if the Assistant feature is allowed and enabled.
virtual bool IsAssistantAllowedAndEnabled() const = 0; virtual bool IsAssistantAllowedAndEnabled() const = 0;
// Called when the app list view animation is completed.
virtual void OnStateTransitionAnimationCompleted(AppListViewState state) = 0;
}; };
} // namespace app_list } // namespace app_list
......
...@@ -137,6 +137,9 @@ bool AppListTestViewDelegate::IsAssistantAllowedAndEnabled() const { ...@@ -137,6 +137,9 @@ bool AppListTestViewDelegate::IsAssistantAllowedAndEnabled() const {
return false; return false;
} }
void AppListTestViewDelegate::OnStateTransitionAnimationCompleted(
AppListViewState state) {}
bool AppListTestViewDelegate::IsCommandIdChecked(int command_id) const { bool AppListTestViewDelegate::IsCommandIdChecked(int command_id) const {
return true; return true;
} }
......
...@@ -101,6 +101,7 @@ class AppListTestViewDelegate : public AppListViewDelegate, ...@@ -101,6 +101,7 @@ class AppListTestViewDelegate : public AppListViewDelegate,
void OnSearchResultVisibilityChanged(const std::string& id, void OnSearchResultVisibilityChanged(const std::string& id,
bool visibility) override; bool visibility) override;
bool IsAssistantAllowedAndEnabled() const override; bool IsAssistantAllowedAndEnabled() const override;
void OnStateTransitionAnimationCompleted(AppListViewState state) override;
// Do a bulk replacement of the items in the model. // Do a bulk replacement of the items in the model.
void ReplaceTestModel(int item_count); void ReplaceTestModel(int item_count);
......
...@@ -188,7 +188,8 @@ class AppListEventTargeter : public aura::WindowTargeter { ...@@ -188,7 +188,8 @@ class AppListEventTargeter : public aura::WindowTargeter {
class AppListView::StateAnimationMetricsReporter class AppListView::StateAnimationMetricsReporter
: public ui::AnimationMetricsReporter { : public ui::AnimationMetricsReporter {
public: public:
StateAnimationMetricsReporter() = default; explicit StateAnimationMetricsReporter(AppListView* view) : view_(view) {}
~StateAnimationMetricsReporter() override = default; ~StateAnimationMetricsReporter() override = default;
void Start(bool is_in_tablet_mode) { void Start(bool is_in_tablet_mode) {
...@@ -209,6 +210,7 @@ class AppListView::StateAnimationMetricsReporter ...@@ -209,6 +210,7 @@ class AppListView::StateAnimationMetricsReporter
UMA_HISTOGRAM_PERCENTAGE( UMA_HISTOGRAM_PERCENTAGE(
"Apps.StateTransition.AnimationSmoothness.ClamshellMode", value); "Apps.StateTransition.AnimationSmoothness.ClamshellMode", value);
} }
view_->OnStateTransitionAnimationCompleted();
#if defined(DCHECK) #if defined(DCHECK)
started_ = false; started_ = false;
#endif #endif
...@@ -219,6 +221,7 @@ class AppListView::StateAnimationMetricsReporter ...@@ -219,6 +221,7 @@ class AppListView::StateAnimationMetricsReporter
bool started_ = false; bool started_ = false;
#endif #endif
bool is_in_tablet_mode_ = false; bool is_in_tablet_mode_ = false;
AppListView* view_;
DISALLOW_COPY_AND_ASSIGN(StateAnimationMetricsReporter); DISALLOW_COPY_AND_ASSIGN(StateAnimationMetricsReporter);
}; };
...@@ -323,7 +326,9 @@ class AppListBackgroundShieldView : public views::View { ...@@ -323,7 +326,9 @@ class AppListBackgroundShieldView : public views::View {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AppListView::TestApi // AppListView::TestApi
AppListView::TestApi::TestApi(AppListView* view) : view_(view) {} AppListView::TestApi::TestApi(AppListView* view) : view_(view) {
DCHECK(view_);
}
AppListView::TestApi::~TestApi() = default; AppListView::TestApi::~TestApi() = default;
...@@ -344,7 +349,7 @@ AppListView::AppListView(AppListViewDelegate* delegate) ...@@ -344,7 +349,7 @@ AppListView::AppListView(AppListViewDelegate* delegate)
transition_animation_observer_( transition_animation_observer_(
std::make_unique<TransitionAnimationObserver>(this)), std::make_unique<TransitionAnimationObserver>(this)),
state_animation_metrics_reporter_( state_animation_metrics_reporter_(
std::make_unique<StateAnimationMetricsReporter>()), std::make_unique<StateAnimationMetricsReporter>(this)),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
CHECK(delegate); CHECK(delegate);
} }
...@@ -1842,4 +1847,8 @@ void AppListView::UpdateAppListBackgroundYPosition() { ...@@ -1842,4 +1847,8 @@ void AppListView::UpdateAppListBackgroundYPosition() {
app_list_background_shield_->SetTransform(transform); app_list_background_shield_->SetTransform(transform);
} }
void AppListView::OnStateTransitionAnimationCompleted() {
delegate_->OnStateTransitionAnimationCompleted(app_list_state_);
}
} // namespace app_list } // namespace app_list
...@@ -255,6 +255,9 @@ class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView, ...@@ -255,6 +255,9 @@ class APP_LIST_EXPORT AppListView : public views::WidgetDelegateView,
const gfx::Rect& new_bounds, const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override; ui::PropertyChangeReason reason) override;
// Called when state transition animation is completed.
void OnStateTransitionAnimationCompleted();
views::Widget* get_fullscreen_widget_for_test() const { views::Widget* get_fullscreen_widget_for_test() const {
return fullscreen_widget_; return fullscreen_widget_;
} }
......
...@@ -9,6 +9,14 @@ enum OverviewAnimationState { ...@@ -9,6 +9,14 @@ enum OverviewAnimationState {
kExitAnimationComplete, kExitAnimationComplete,
}; };
enum LauncherAnimationState {
kClosed,
kPeeking,
kHalf,
kFullscreenAllApps,
kFullscreenSearch
};
interface ShellTestApi { interface ShellTestApi {
// Returns true if a system modal window is open (e.g. the Wi-Fi network // Returns true if a system modal window is open (e.g. the Wi-Fi network
// password dialog). // password dialog).
...@@ -53,4 +61,8 @@ interface ShellTestApi { ...@@ -53,4 +61,8 @@ interface ShellTestApi {
// Runs the callback when the overview state becomes |state|. // Runs the callback when the overview state becomes |state|.
WaitForOverviewAnimationState(OverviewAnimationState state) => (); WaitForOverviewAnimationState(OverviewAnimationState state) => ();
// Runs the callback when the launcher state becomes |state| after
// state transition animation.
WaitForLauncherAnimationState(LauncherAnimationState state) => ();
}; };
...@@ -105,6 +105,54 @@ class OverviewAnimationStateWaiter : public OverviewObserver { ...@@ -105,6 +105,54 @@ class OverviewAnimationStateWaiter : public OverviewObserver {
DISALLOW_COPY_AND_ASSIGN(OverviewAnimationStateWaiter); DISALLOW_COPY_AND_ASSIGN(OverviewAnimationStateWaiter);
}; };
// A waiter that waits until the animation ended with the target state, and
// execute the callback. This self destruction upon completion.
class LauncherStateWaiter {
public:
LauncherStateWaiter(
mojom::LauncherAnimationState state,
ShellTestApi::WaitForLauncherAnimationStateCallback callback)
: callback_(std::move(callback)) {
switch (state) {
case mojom::LauncherAnimationState::kClosed:
target_state_ = app_list::AppListViewState::CLOSED;
break;
case mojom::LauncherAnimationState::kPeeking:
target_state_ = app_list::AppListViewState::PEEKING;
break;
case mojom::LauncherAnimationState::kHalf:
target_state_ = app_list::AppListViewState::HALF;
break;
case mojom::LauncherAnimationState::kFullscreenAllApps:
target_state_ = app_list::AppListViewState::FULLSCREEN_ALL_APPS;
break;
case mojom::LauncherAnimationState::kFullscreenSearch:
target_state_ = app_list::AppListViewState::FULLSCREEN_SEARCH;
break;
};
Shell::Get()->app_list_controller()->SetStateTransitionAnimationCallback(
base::BindRepeating(&LauncherStateWaiter::OnStateChanged,
base::Unretained(this)));
}
~LauncherStateWaiter() {
Shell::Get()->app_list_controller()->SetStateTransitionAnimationCallback(
base::NullCallback());
}
void OnStateChanged(app_list::AppListViewState state) {
if (target_state_ == state) {
std::move(callback_).Run();
delete this;
}
}
private:
app_list::AppListViewState target_state_;
ShellTestApi::WaitForLauncherAnimationStateCallback callback_;
DISALLOW_COPY_AND_ASSIGN(LauncherStateWaiter);
};
} // namespace } // namespace
ShellTestApi::ShellTestApi() : ShellTestApi(Shell::Get()) {} ShellTestApi::ShellTestApi() : ShellTestApi(Shell::Get()) {}
...@@ -261,4 +309,10 @@ void ShellTestApi::WaitForOverviewAnimationState( ...@@ -261,4 +309,10 @@ void ShellTestApi::WaitForOverviewAnimationState(
new OverviewAnimationStateWaiter(state, std::move(callback)); new OverviewAnimationStateWaiter(state, std::move(callback));
} }
void ShellTestApi::WaitForLauncherAnimationState(
mojom::LauncherAnimationState target_state,
WaitForLauncherAnimationStateCallback callback) {
new LauncherStateWaiter(target_state, std::move(callback));
}
} // namespace ash } // namespace ash
...@@ -70,6 +70,9 @@ class ShellTestApi : public mojom::ShellTestApi { ...@@ -70,6 +70,9 @@ class ShellTestApi : public mojom::ShellTestApi {
void WaitForOverviewAnimationState( void WaitForOverviewAnimationState(
mojom::OverviewAnimationState state, mojom::OverviewAnimationState state,
WaitForOverviewAnimationStateCallback callback) override; WaitForOverviewAnimationStateCallback callback) override;
void WaitForLauncherAnimationState(
mojom::LauncherAnimationState state,
WaitForLauncherAnimationStateCallback callback) override;
private: private:
Shell* shell_; // not owned Shell* shell_; // not owned
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "chrome/browser/ui/ash/ash_test_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/base/perf/performance_test.h"
#include "content/public/test/test_utils.h"
#include "ui/base/test/ui_controls.h"
// TODO(oshima): Add tablet mode overview transition.
class LauncherAnimationsTest : public UIPerformanceTest {
public:
LauncherAnimationsTest() = default;
~LauncherAnimationsTest() override = default;
// UIPerformanceTest:
void SetUpOnMainThread() override {
UIPerformanceTest::SetUpOnMainThread();
if (base::SysInfo::IsRunningOnChromeOS()) {
base::RunLoop run_loop;
base::PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
base::TimeDelta::FromSeconds(5));
run_loop.Run();
}
}
// UIPerformanceTest:
std::vector<std::string> GetUMAHistogramNames() const override {
return {
"Apps.StateTransition.AnimationSmoothness.TabletMode",
};
}
private:
DISALLOW_COPY_AND_ASSIGN(LauncherAnimationsTest);
};
IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, Fullscreen) {
// Browser window is used to identify display, so we can use
// use the 1st browser window regardless of number of windows created.
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow();
ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi();
{
base::RunLoop waiter;
shell_test_api->WaitForLauncherAnimationState(
ash::mojom::LauncherAnimationState::kFullscreenAllApps,
waiter.QuitClosure());
ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH,
/*control=*/false,
/*shift=*/true,
/*alt=*/false,
/* command = */ false);
waiter.Run();
}
{
base::RunLoop waiter;
shell_test_api->WaitForLauncherAnimationState(
ash::mojom::LauncherAnimationState::kClosed, waiter.QuitClosure());
ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH,
/*control=*/false,
/*shift=*/true,
/*alt=*/false,
/* command = */ false);
waiter.Run();
}
}
IN_PROC_BROWSER_TEST_F(LauncherAnimationsTest, Peeking) {
// Browser window is used to identify display, so we can use
// use the 1st browser window regardless of number of windows created.
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow();
ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi();
{
base::RunLoop waiter;
shell_test_api->WaitForLauncherAnimationState(
ash::mojom::LauncherAnimationState::kPeeking, waiter.QuitClosure());
ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH,
/*control=*/false,
/*shift=*/false,
/*alt=*/false,
/* command = */ false);
waiter.Run();
}
{
base::RunLoop waiter;
shell_test_api->WaitForLauncherAnimationState(
ash::mojom::LauncherAnimationState::kClosed, waiter.QuitClosure());
ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH,
/*control=*/false,
/*shift=*/false,
/*alt=*/false,
/* command = */ false);
waiter.Run();
}
}
...@@ -5225,6 +5225,7 @@ if (!is_android) { ...@@ -5225,6 +5225,7 @@ if (!is_android) {
] ]
sources += [ sources += [
"../browser/ui/ash/drag_to_overview_interactive_uitest.cc", "../browser/ui/ash/drag_to_overview_interactive_uitest.cc",
"../browser/ui/ash/launcher_animations_interactive_uitest.cc",
"../browser/ui/ash/overview_animations_interactive_uitest.cc", "../browser/ui/ash/overview_animations_interactive_uitest.cc",
"../browser/ui/ash/split_view_interactive_uitest.cc", "../browser/ui/ash/split_view_interactive_uitest.cc",
] ]
......
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