// Copyright 2018 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/app_list/test/app_list_test_helper.h"
#include <string>
#include <utility>
#include "ash/app_list/app_list_bubble_presenter.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/app_list/app_list_model_provider.h"
#include "ash/app_list/app_list_presenter_impl.h"
#include "ash/app_list/model/app_list_item.h"
#include "ash/app_list/model/app_list_test_model.h"
#include "ash/app_list/model/search/test_search_result.h"
#include "ash/app_list/views/app_list_bubble_apps_collections_page.h"
#include "ash/app_list/views/app_list_bubble_apps_page.h"
#include "ash/app_list/views/app_list_bubble_search_page.h"
#include "ash/app_list/views/app_list_bubble_view.h"
#include "ash/app_list/views/app_list_folder_view.h"
#include "ash/app_list/views/app_list_main_view.h"
#include "ash/app_list/views/app_list_search_view.h"
#include "ash/app_list/views/app_list_toast_container_view.h"
#include "ash/app_list/views/app_list_view.h"
#include "ash/app_list/views/apps_container_view.h"
#include "ash/app_list/views/contents_view.h"
#include "ash/app_list/views/continue_section_view.h"
#include "ash/app_list/views/search_result_page_dialog_controller.h"
#include "ash/app_list/views/search_result_page_view.h"
#include "ash/constants/ash_features.h"
#include "ash/shell.h"
#include "ash/test/ash_test_util.h"
#include "base/run_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/animation/tween.h"
#include "ui/views/widget/root_view.h"
namespace ash {
namespace {
// The size of the app list item solid-colored icons.
constexpr gfx::Size kIconImageSize(56, 56);
// An app list should be either a bubble app list or a fullscreen app list.
// Returns true if a bubble app list should be used under the current mode.
bool ShouldUseBubbleAppList() {
// A bubble app list should be used only when ot is in clamshell mode.
return !Shell::Get()->IsInTabletMode();
}
} // namespace
AppListTestHelper::AppListTestHelper() {
// The app list controller is ready after Shell is created.
app_list_controller_ = Shell::Get()->app_list_controller();
DCHECK(app_list_controller_);
// Use a new app list client for each test
app_list_client_ = std::make_unique<TestAppListClient>();
app_list_controller_->SetClient(app_list_client_.get());
app_list_controller_->SetActiveModel(
/*profile_id=*/1, &model_, &search_model_, &quick_app_access_model_);
// Disable app list nudge as default.
DisableAppListNudge(true);
AppListNudgeController::SetPrivacyNoticeAcceptedForTest(true);
}
AppListTestHelper::~AppListTestHelper() {
app_list_controller_->ClearActiveModel();
app_list_controller_->SetClient(nullptr);
}
void AppListTestHelper::WaitUntilIdle() {
base::RunLoop().RunUntilIdle();
}
void AppListTestHelper::WaitForFolderAnimation() {
AppListFolderView* folder_view = nullptr;
if (ShouldUseBubbleAppList()) {
folder_view = GetBubbleFolderView();
} else {
folder_view = GetFullscreenFolderView();
}
if (!folder_view || !folder_view->IsAnimationRunning())
return;
base::RunLoop run_loop;
folder_view->SetAnimationDoneTestCallback(run_loop.QuitClosure());
run_loop.Run();
}
void AppListTestHelper::ShowAppList() {
app_list_controller_->ShowAppList(AppListShowSource::kSearchKey);
}
void AppListTestHelper::ShowAndRunLoop(uint64_t display_id) {
ShowAndRunLoop(display_id, AppListShowSource::kSearchKey);
}
void AppListTestHelper::Show(uint64_t display_id) {
ShowAndRunLoop(display_id, AppListShowSource::kSearchKey);
}
void AppListTestHelper::ShowAndRunLoop(uint64_t display_id,
AppListShowSource show_source) {
app_list_controller_->Show(display_id, show_source, base::TimeTicks(), true);
WaitUntilIdle();
}
void AppListTestHelper::DismissAndRunLoop() {
app_list_controller_->DismissAppList();
WaitUntilIdle();
}
void AppListTestHelper::Dismiss() {
app_list_controller_->DismissAppList();
}
void AppListTestHelper::ToggleAndRunLoop(uint64_t display_id) {
ToggleAndRunLoop(display_id, AppListShowSource::kSearchKey);
}
void AppListTestHelper::ToggleAndRunLoop(uint64_t display_id,
AppListShowSource show_source) {
app_list_controller_->ToggleAppList(display_id, show_source,
base::TimeTicks());
WaitUntilIdle();
}
void AppListTestHelper::StartSlideAnimationOnBubbleAppsPage(
views::View* view,
int vertical_offset,
base::TimeDelta duration,
gfx::Tween::Type tween_type) {
GetBubbleAppsPage()->SlideViewIntoPosition(view, vertical_offset, duration,
tween_type);
}
void AppListTestHelper::CheckVisibility(bool visible) {
EXPECT_EQ(visible, app_list_controller_->IsVisible());
EXPECT_EQ(visible, app_list_controller_->GetTargetVisibility(std::nullopt));
}
void AppListTestHelper::CheckState(AppListViewState state) {
EXPECT_EQ(state, app_list_controller_->GetAppListViewState());
}
void AppListTestHelper::AddAppItems(int num_apps) {
AddAppItemsWithColorAndName(num_apps, IconColorType::kNotSet,
/*set_name=*/true);
}
void AppListTestHelper::AddAppItemsWithColorAndName(int num_apps,
IconColorType color_type,
bool set_name) {
AppListModel* const model = AppListModelProvider::Get()->model();
const int num_apps_already_added = model->top_level_item_list()->item_count();
for (int i = 0; i < num_apps; i++) {
const std::string id(
test::AppListTestModel::GetItemName(i + num_apps_already_added));
auto item = std::make_unique<AppListItem>(id);
std::optional<SkColor> solid_color;
switch (color_type) {
case IconColorType::kDefaultColor:
solid_color = icon_color_generator_.default_color();
break;
case IconColorType::kAlternativeColor:
solid_color = icon_color_generator_.GetAlternativeColor();
break;
case IconColorType::kNotSet:
break;
}
if (solid_color) {
// Skip the calculation of the icon color from the generated solid-colored
// icon to save some time.
item->SetDefaultIconAndColor(
CreateSolidColorTestImage(kIconImageSize, *solid_color), IconColor(),
/*is_placeholder_icon=*/false);
}
auto* item_ptr = item.get();
model->AddItem(std::move(item));
if (set_name)
model->SetItemName(item_ptr, id);
}
}
void AppListTestHelper::AddContinueSuggestionResults(int num_results) {
for (int i = 0; i < num_results; i++) {
auto result = std::make_unique<TestSearchResult>();
result->set_result_id(base::NumberToString(i));
result->set_result_type(AppListSearchResultType::kZeroStateFile);
result->set_display_type(SearchResultDisplayType::kContinue);
GetSearchResults()->Add(std::move(result));
}
}
void AppListTestHelper::AddRecentApps(int num_apps) {
for (int i = 0; i < num_apps; i++) {
auto result = std::make_unique<TestSearchResult>();
// Use the same "Item #" convention as AppListTestModel uses. The search
// result IDs must match app item IDs in the app list data model.
result->set_result_id(test::AppListTestModel::GetItemName(i));
result->set_result_type(AppListSearchResultType::kInstalledApp);
result->set_display_type(SearchResultDisplayType::kRecentApps);
GetSearchResults()->Add(std::move(result));
}
}
void AppListTestHelper::AddAppListItemsWithCollection(
AppCollection collection_id,
int num_apps) {
AppListModel* model = AppListModelProvider::Get()->model();
for (int i = 0; i < num_apps; i++) {
const std::string id(test::AppListTestModel::GetItemName(i));
auto item = std::make_unique<AppListItem>(id);
item->SetAppCollectionId(collection_id);
AppListItem* item_ptr = model->AddItem(std::move(item));
// Give each item a name so that the accessibility paint checks pass.
// (Focusable items should have accessible names.)
model->SetItemName(item_ptr, item_ptr->id());
}
}
bool AppListTestHelper::IsInFolderView() {
if (ShouldUseBubbleAppList())
return GetBubbleView()->showing_folder_for_test();
return GetAppListView()
->app_list_main_view()
->contents_view()
->apps_container_view()
->IsInFolderView();
}
void AppListTestHelper::DisableAppListNudge(bool disable) {
AppListNudgeController::SetReorderNudgeDisabledForTest(disable);
}
views::View* AppListTestHelper::GetAccessibilityAnnounceView() {
views::Widget* widget = ShouldUseBubbleAppList()
? GetBubbleView()->GetWidget()
: GetAppListView()->GetWidget();
DCHECK(widget);
return static_cast<views::internal::RootView*>(widget->GetRootView())
->GetAnnounceViewForTesting();
}
AppListView* AppListTestHelper::GetAppListView() {
return app_list_controller_->fullscreen_presenter()->GetView();
}
SearchBoxView* AppListTestHelper::GetSearchBoxView() {
if (ShouldUseBubbleAppList())
return GetBubbleView()->search_box_view_for_test();
return GetAppListView()->search_box_view();
}
AppsContainerView* AppListTestHelper::GetAppsContainerView() {
return GetAppListView()
->app_list_main_view()
->contents_view()
->apps_container_view();
}
AppListFolderView* AppListTestHelper::GetFullscreenFolderView() {
return GetAppsContainerView()->app_list_folder_view();
}
RecentAppsView* AppListTestHelper::GetFullscreenRecentAppsView() {
return GetAppsContainerView()->GetRecentAppsView();
}
ContinueSectionView* AppListTestHelper::GetFullscreenContinueSectionView() {
return GetAppsContainerView()->GetContinueSectionView();
}
PagedAppsGridView* AppListTestHelper::GetRootPagedAppsGridView() {
return GetAppsContainerView()->apps_grid_view();
}
views::View* AppListTestHelper::GetFullscreenLauncherAppsSeparatorView() {
return GetAppsContainerView()->separator();
}
SearchResultPageView* AppListTestHelper::GetFullscreenSearchResultPageView() {
return GetAppListView()
->app_list_main_view()
->contents_view()
->search_result_page_view();
}
bool AppListTestHelper::IsShowingFullscreenSearchResults() {
return GetAppListView()
->app_list_main_view()
->contents_view()
->IsShowingSearchResults();
}
SearchResultPageAnchoredDialog*
AppListTestHelper::GetFullscreenSearchPageDialog() {
if (IsShowingFullscreenSearchResults())
return GetFullscreenSearchResultPageView()->dialog_for_test();
return GetAppsContainerView()->dialog_for_test();
}
AppListBubbleView* AppListTestHelper::GetBubbleView() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test();
}
SearchBoxView* AppListTestHelper::GetBubbleSearchBoxView() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->search_box_view_;
}
AppListFolderView* AppListTestHelper::GetBubbleFolderView() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->folder_view_;
}
AppListBubbleAppsPage* AppListTestHelper::GetBubbleAppsPage() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->apps_page_;
}
AppListBubbleAppsCollectionsPage*
AppListTestHelper::GetBubbleAppsCollectionsPage() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->apps_collections_page_;
}
ContinueSectionView* AppListTestHelper::GetBubbleContinueSectionView() {
return GetBubbleAppsPage()->continue_section_;
}
RecentAppsView* AppListTestHelper::GetBubbleRecentAppsView() {
return GetBubbleAppsPage()->recent_apps_;
}
ScrollableAppsGridView* AppListTestHelper::GetScrollableAppsGridView() {
return GetBubbleAppsPage()->scrollable_apps_grid_view_;
}
views::View* AppListTestHelper::GetAppCollectionsSectionsContainer() {
return GetBubbleAppsCollectionsPage()->sections_container_;
}
AppListBubbleSearchPage* AppListTestHelper::GetBubbleSearchPage() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->search_page_;
}
SearchResultPageAnchoredDialog* AppListTestHelper::GetBubbleSearchPageDialog() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->search_page_dialog_controller_->dialog();
}
AppListBubbleAssistantPage* AppListTestHelper::GetBubbleAssistantPage() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->assistant_page_;
}
SearchModel::SearchResults* AppListTestHelper::GetSearchResults() {
return AppListModelProvider::Get()->search_model()->results();
}
std::vector<ash::AppListSearchResultCategory>*
AppListTestHelper::GetOrderedResultCategories() {
return AppListModelProvider::Get()->search_model()->ordered_categories();
}
AppListSearchView* AppListTestHelper::GetBubbleAppListSearchView() {
return app_list_controller_->bubble_presenter_for_test()
->bubble_view_for_test()
->search_page_->search_view();
}
views::View* AppListTestHelper::GetBubbleLauncherAppsSeparatorView() {
return GetBubbleAppsPage()->separator_for_test();
}
} // namespace ash