#include "ash/shelf/home_button.h"
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <vector>
#include "ash/accessibility/accessibility_controller.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/app_list/test/app_list_test_helper.h"
#include "ash/app_list/views/app_list_view.h"
#include "ash/capture_mode/base_capture_mode_session.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/capture_mode/capture_mode_types.h"
#include "ash/capture_mode/test_capture_mode_delegate.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/public/cpp/capture_mode/capture_mode_api.h"
#include "ash/public/cpp/tablet_mode.h"
#include "ash/root_window_controller.h"
#include "ash/scanner/scanner_enterprise_policy.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/shelf.h"
#include "ash/shelf/shelf_layout_manager.h"
#include "ash/shelf/shelf_navigation_widget.h"
#include "ash/shelf/shelf_view.h"
#include "ash/shelf/shelf_view_test_api.h"
#include "ash/shelf/shelf_widget.h"
#include "ash/shell.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/ash_test_util.h"
#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chromeos/strings/grit/chromeos_strings.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/test/layer_animation_stopped_waiter.h"
#include "ui/display/test/display_manager_test_api.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "ui/gfx/scoped_animation_duration_scale_mode.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/animation/bounds_animator.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace ash {
namespace {
ui::GestureEvent CreateGestureEvent(ui::GestureEventDetails details) {
return ui::GestureEvent(0, 0, ui::EF_NONE, base::TimeTicks(), details);
}
class HomeButtonTestBase : public AshTestBase {
public:
HomeButtonTestBase() = default;
HomeButtonTestBase(const HomeButtonTestBase&) = delete;
HomeButtonTestBase& operator=(const HomeButtonTestBase&) = delete;
~HomeButtonTestBase() override = default;
void SendGestureEvent(ui::GestureEvent* event) {
ASSERT_TRUE(home_button());
home_button()->OnGestureEvent(event);
}
HomeButton* home_button() const {
return GetPrimaryShelf()
->shelf_widget()
->navigation_widget()
->GetHomeButton();
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
};
class HomeButtonTest : public HomeButtonTestBase,
public testing::WithParamInterface<bool> {
public:
void SetUp() override {
scoped_feature_list_.InitWithFeatureStates({
{features::kHideShelfControlsInTabletMode,
IsHideShelfControlsInTabletModeEnabled()},
{features::kSunfishFeature, true},
{features::kScannerUpdate, true},
{features::kScannerDogfood, true},
});
HomeButtonTestBase::SetUp();
}
void SendGestureEventToSecondaryDisplay(ui::GestureEvent* event) {
UpdateDisplay("1+1-1000x600,1002+0-600x400");
ASSERT_TRUE(Shelf::ForWindow(Shell::GetAllRootWindows()[1])
->shelf_widget()
->navigation_widget()
->GetHomeButton());
Shelf::ForWindow(Shell::GetAllRootWindows()[1])
->shelf_widget()
->navigation_widget()
->GetHomeButton()
->OnGestureEvent(event);
}
bool IsHideShelfControlsInTabletModeEnabled() const { return GetParam(); }
PrefService* prefs() {
return Shell::Get()->session_controller()->GetPrimaryUserPrefService();
}
void DisableSunfishScanner() {
auto* capture_mode_controller = CaptureModeController::Get();
auto* test_capture_mode_delegate = static_cast<TestCaptureModeDelegate*>(
capture_mode_controller->delegate_for_testing());
test_capture_mode_delegate->set_is_search_allowed_by_policy(false);
prefs()->SetInteger(prefs::kScannerEnterprisePolicyAllowed,
static_cast<int>(ScannerEnterprisePolicy::kDisallowed));
ASSERT_FALSE(CanShowSunfishOrScannerUi());
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class HomeButtonAnimationTest : public HomeButtonTestBase {
public:
HomeButtonAnimationTest() {
scoped_feature_list_.InitAndEnableFeature(
features::kHideShelfControlsInTabletMode);
}
~HomeButtonAnimationTest() override = default;
void SetUp() override {
HomeButtonTestBase::SetUp();
animation_duration_.emplace(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
}
void TearDown() override {
animation_duration_.reset();
HomeButtonTestBase::TearDown();
}
private:
std::optional<gfx::ScopedAnimationDurationScaleMode> animation_duration_;
base::test::ScopedFeatureList scoped_feature_list_;
};
class HomeButtonWithQuickAppAccess : public HomeButtonTestBase {
public:
HomeButtonWithQuickAppAccess() = default;
~HomeButtonWithQuickAppAccess() override = default;
bool IsQuickAppVisible() const {
if (!home_button()) {
return false;
}
auto* expandable_container = home_button()->expandable_container_for_test();
if (!expandable_container) {
return false;
}
return expandable_container->GetVisible() &&
expandable_container->layer()->visible() &&
home_button()->quick_app_button_for_test();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class HomeButtonNoSessionTest : public HomeButtonTest {
public:
HomeButtonNoSessionTest() { set_start_session(false); }
};
TEST_F(HomeButtonWithQuickAppAccess, Basic) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
GetPrimaryShelf()->shelf_layout_manager()->LayoutShelf();
gfx::Point quick_app_center = home_button()
->quick_app_button_for_test()
->GetBoundsInScreen()
.CenterPoint();
GetEventGenerator()->MoveMouseTo(quick_app_center);
GetEventGenerator()->ClickLeftButton();
EXPECT_EQ(1, GetTestAppListClient()->activate_item_count());
EXPECT_EQ(quick_app_id, GetTestAppListClient()->activate_item_last_id());
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, NonExistentApp) {
EXPECT_FALSE(IsQuickAppVisible());
EXPECT_FALSE(Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(
"Quick App Item"));
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, AppWithNoIconThenLoaded) {
base::HistogramTester histogram_tester;
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
AppListItem* item = new AppListItem(quick_app_id);
GetAppListTestHelper()->model()->AddItem(item);
EXPECT_TRUE(Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(
"Quick App Item"));
EXPECT_FALSE(IsQuickAppVisible());
EXPECT_EQ(std::vector<std::string>{quick_app_id},
GetTestAppListClient()->load_icon_app_ids());
item->SetDefaultIconAndColor(
CreateSolidColorTestImage(gfx::Size(32, 32), SK_ColorRED), IconColor(),
false);
EXPECT_TRUE(IsQuickAppVisible());
histogram_tester.ExpectTotalCount("Apps.QuickAppIconLoadTime", 1);
}
TEST_F(HomeButtonWithQuickAppAccess, IconUpdatesOnNewQuickAppSet) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
AppListItem* item = new AppListItem(quick_app_id);
GetAppListTestHelper()->model()->AddItem(item);
item->SetDefaultIconAndColor(
CreateSolidColorTestImage(gfx::Size(32, 32), SK_ColorRED), IconColor(),
false);
const std::string quick_app_id_two = "Quick App Item Two";
AppListItem* item_two = new AppListItem(quick_app_id_two);
GetAppListTestHelper()->model()->AddItem(item_two);
item_two->SetDefaultIconAndColor(
CreateSolidColorTestImage(gfx::Size(32, 32), SK_ColorBLUE), IconColor(),
false);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
gfx::ImageSkia image_one =
home_button()->quick_app_button_for_test()->GetImage(
views::Button::STATE_NORMAL);
EXPECT_TRUE(Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(
quick_app_id_two));
EXPECT_TRUE(IsQuickAppVisible());
gfx::ImageSkia image_two =
home_button()->quick_app_button_for_test()->GetImage(
views::Button::STATE_NORMAL);
EXPECT_FALSE(
gfx::test::AreImagesEqual(gfx::Image(image_one), gfx::Image(image_two)));
}
TEST_F(HomeButtonWithQuickAppAccess, HomeButtonPressed) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->MoveMouseTo(center);
GetEventGenerator()->ClickLeftButton();
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, AppListOpened) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
GetAppListTestHelper()->ShowAppList();
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, TwoDisplays) {
UpdateDisplay("10+10-500x400,600+10-1000x600/r");
HomeButton* second_home_button =
Shelf::ForWindow(Shell::GetAllRootWindows()[1])
->shelf_widget()
->navigation_widget()
->GetHomeButton();
EXPECT_NE(home_button(), second_home_button);
EXPECT_FALSE(second_home_button->quick_app_button_for_test());
EXPECT_FALSE(home_button()->quick_app_button_for_test());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(second_home_button->quick_app_button_for_test());
EXPECT_TRUE(home_button()->quick_app_button_for_test());
gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->MoveMouseTo(center);
GetEventGenerator()->ClickLeftButton();
EXPECT_FALSE(second_home_button->quick_app_button_for_test());
EXPECT_FALSE(home_button()->quick_app_button_for_test());
}
TEST_F(HomeButtonWithQuickAppAccess, AccessibleTooltipText) {
ui::AXNodeData data;
auto* controller = Shell::Get()->app_list_controller();
ASSERT_TRUE(controller);
EXPECT_FALSE(home_button()->IsShowingAppList());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE),
home_button()->GetRenderedTooltipText(gfx::Point()));
home_button()->GetViewAccessibility().GetAccessibleNodeData(&data);
EXPECT_EQ(data.GetString16Attribute(ax::mojom::StringAttribute::kDescription),
u"");
controller->ToggleAppList(home_button()->GetDisplayId(),
AppListShowSource::kShelfButton, base::TimeTicks());
EXPECT_TRUE(home_button()->IsShowingAppList());
EXPECT_EQ(u"", home_button()->GetRenderedTooltipText(gfx::Point()));
UpdateDisplay("10+10-500x400,600+10-1000x600/r");
HomeButton* second_home_button =
Shelf::ForWindow(Shell::GetAllRootWindows()[1])
->shelf_widget()
->navigation_widget()
->GetHomeButton();
EXPECT_NE(home_button(), second_home_button);
EXPECT_FALSE(second_home_button->IsShowingAppList());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE),
second_home_button->GetRenderedTooltipText(gfx::Point()));
controller->ToggleAppList(home_button()->GetDisplayId(),
AppListShowSource::kShelfButton, base::TimeTicks());
EXPECT_FALSE(home_button()->IsShowingAppList());
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE),
home_button()->GetRenderedTooltipText(gfx::Point()));
controller->ToggleAppList(second_home_button->GetDisplayId(),
AppListShowSource::kShelfButton, base::TimeTicks());
EXPECT_TRUE(second_home_button->IsShowingAppList());
EXPECT_EQ(u"", second_home_button->GetRenderedTooltipText(gfx::Point()));
}
TEST_F(HomeButtonWithQuickAppAccess, EmptyAppId) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_FALSE(Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(""));
EXPECT_FALSE(IsQuickAppVisible());
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
EXPECT_TRUE(Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(""));
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, QuickAppButtonAnimation) {
EXPECT_FALSE(IsQuickAppVisible());
gfx::ScopedAnimationDurationScaleMode regular_animations(
gfx::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
auto* quick_app_button = home_button()->quick_app_button_for_test();
EXPECT_EQ(0.0f, quick_app_button->layer()->opacity());
EXPECT_EQ(1.0f, quick_app_button->layer()->GetTargetOpacity());
EXPECT_TRUE(quick_app_button->layer()->GetAnimator()->is_animating());
ui::LayerAnimationStoppedWaiter quick_app_button_animation_waiter;
quick_app_button_animation_waiter.Wait(quick_app_button->layer());
EXPECT_FALSE(quick_app_button->layer()->GetAnimator()->is_animating());
const int quick_app_margin = 8;
EXPECT_EQ(ShelfConfig::Get()->control_size() + quick_app_margin,
quick_app_button->bounds().x());
EXPECT_EQ(0, quick_app_button->bounds().y());
GetAppListTestHelper()->ShowAppList();
EXPECT_TRUE(IsQuickAppVisible());
EXPECT_EQ(1.0f, quick_app_button->layer()->opacity());
EXPECT_EQ(0.0f, quick_app_button->layer()->GetTargetOpacity());
EXPECT_TRUE(quick_app_button->layer()->GetAnimator()->is_animating());
quick_app_button_animation_waiter.Wait(quick_app_button->layer());
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, LeftShelf) {
Shelf* shelf = GetPrimaryShelf();
EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
const int quick_app_margin = 8;
GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
auto* quick_app_button = home_button()->quick_app_button_for_test();
EXPECT_EQ(home_button()->width() + quick_app_margin,
quick_app_button->bounds().y());
EXPECT_EQ(0, quick_app_button->bounds().x());
GetEventGenerator()->MoveMouseTo(
quick_app_button->GetBoundsInScreen().CenterPoint());
GetEventGenerator()->ClickLeftButton();
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, RightShelf) {
Shelf* shelf = GetPrimaryShelf();
EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
const int quick_app_margin = 8;
GetPrimaryShelf()->SetAlignment(ShelfAlignment::kRight);
auto* quick_app_button = home_button()->quick_app_button_for_test();
EXPECT_EQ(home_button()->width() + quick_app_margin,
quick_app_button->bounds().y());
EXPECT_EQ(0, quick_app_button->bounds().x());
GetEventGenerator()->MoveMouseTo(
quick_app_button->GetBoundsInScreen().CenterPoint());
GetEventGenerator()->ClickLeftButton();
EXPECT_FALSE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, ModelChange) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
auto model_override = std::make_unique<test::AppListTestModel>();
auto search_model_override = std::make_unique<SearchModel>();
auto quick_app_access_model = std::make_unique<QuickAppAccessModel>();
Shell::Get()->app_list_controller()->SetActiveModel(
1, model_override.get(), search_model_override.get(),
quick_app_access_model.get());
EXPECT_FALSE(IsQuickAppVisible());
Shell::Get()->app_list_controller()->SetActiveModel(
1, GetAppListTestHelper()->model(),
GetAppListTestHelper()->search_model(),
GetAppListTestHelper()->quick_app_access_model());
EXPECT_TRUE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, SetSameQuickAppAfterActivation) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
auto* quick_app_button = home_button()->quick_app_button_for_test();
GetEventGenerator()->MoveMouseTo(
quick_app_button->GetBoundsInScreen().CenterPoint());
GetEventGenerator()->ClickLeftButton();
EXPECT_FALSE(IsQuickAppVisible());
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
}
TEST_F(HomeButtonWithQuickAppAccess, SetSameQuickAppAfterAppListShown) {
EXPECT_FALSE(IsQuickAppVisible());
const std::string quick_app_id = "Quick App Item";
GetAppListTestHelper()->model()->CreateAndAddItem(quick_app_id);
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
GetAppListTestHelper()->ShowAppList();
EXPECT_FALSE(IsQuickAppVisible());
EXPECT_TRUE(
Shell::Get()->app_list_controller()->SetHomeButtonQuickApp(quick_app_id));
EXPECT_TRUE(IsQuickAppVisible());
}
enum class TestAccessibilityFeature {
kTabletModeShelfNavigationButtons,
kSpokenFeedback,
kAutoclick,
kSwitchAccess
};
class HomeButtonVisibilityWithAccessibilityFeaturesTest
: public HomeButtonTestBase,
public ::testing::WithParamInterface<TestAccessibilityFeature> {
public:
HomeButtonVisibilityWithAccessibilityFeaturesTest() {
scoped_feature_list_.InitAndEnableFeature(
features::kHideShelfControlsInTabletMode);
}
~HomeButtonVisibilityWithAccessibilityFeaturesTest() override = default;
void SetTestA11yFeatureEnabled(bool enabled) {
switch (GetParam()) {
case TestAccessibilityFeature::kTabletModeShelfNavigationButtons:
Shell::Get()
->accessibility_controller()
->SetTabletModeShelfNavigationButtonsEnabled(enabled);
break;
case TestAccessibilityFeature::kSpokenFeedback:
Shell::Get()->accessibility_controller()->SetSpokenFeedbackEnabled(
enabled, A11Y_NOTIFICATION_NONE);
break;
case TestAccessibilityFeature::kAutoclick:
Shell::Get()->accessibility_controller()->autoclick().SetEnabled(
enabled);
break;
case TestAccessibilityFeature::kSwitchAccess:
Shell::Get()->accessibility_controller()->switch_access().SetEnabled(
enabled);
break;
}
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
}
INSTANTIATE_TEST_SUITE_P(All, HomeButtonTest, testing::Bool());
INSTANTIATE_TEST_SUITE_P(All, HomeButtonNoSessionTest, testing::Bool());
TEST_P(HomeButtonTest, ClipRectDoesNotClipHomeButtonBounds) {
ShelfNavigationWidget* const nav_widget =
GetPrimaryShelf()->navigation_widget();
ShelfNavigationWidget::TestApi test_api(nav_widget);
ASSERT_TRUE(test_api.IsHomeButtonVisible());
ASSERT_TRUE(home_button());
auto home_button_bounds = [&]() -> gfx::Rect {
return home_button()->GetBoundsInScreen();
};
auto clip_rect_bounds = [&]() -> gfx::Rect {
gfx::Rect clip_bounds = nav_widget->GetLayer()->clip_rect();
wm::ConvertRectToScreen(nav_widget->GetNativeWindow(), &clip_bounds);
return clip_bounds;
};
std::string display_configs[] = {
"1+1-1200x1000",
"1+1-1000x1200",
"1+1-800x600",
"1+1-600x800",
};
for (const auto& display_config : display_configs) {
SCOPED_TRACE(display_config);
UpdateDisplay(display_config);
EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
ash::TabletModeControllerTestApi().EnterTabletMode();
ShelfViewTestAPI shelf_test_api(
GetPrimaryShelf()->GetShelfViewForTesting());
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
if (home_button() && test_api.IsHomeButtonVisible())
EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
std::unique_ptr<views::Widget> widget =
CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
if (home_button() && test_api.IsHomeButtonVisible())
EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
widget.reset();
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
if (home_button() && test_api.IsHomeButtonVisible())
EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
ash::TabletModeControllerTestApi().LeaveTabletMode();
widget =
CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
widget.reset();
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
}
}
TEST_P(HomeButtonTest, ClickToOpenAppList) {
Shelf* shelf = GetPrimaryShelf();
EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
ShelfNavigationWidget::TestApi test_api(
GetPrimaryShelf()->navigation_widget());
ASSERT_TRUE(test_api.IsHomeButtonVisible());
ASSERT_TRUE(home_button());
gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->MoveMouseTo(center);
GetEventGenerator()->ClickLeftButton();
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
GetEventGenerator()->ClickLeftButton();
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(false);
}
TEST_P(HomeButtonTest, ClickToOpenAppListInTabletMode) {
ash::TabletModeControllerTestApi().EnterTabletMode();
Shelf* shelf = GetPrimaryShelf();
EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
ShelfNavigationWidget::TestApi test_api(shelf->navigation_widget());
const bool should_show_home_button =
!IsHideShelfControlsInTabletModeEnabled();
EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
ASSERT_EQ(should_show_home_button, static_cast<bool>(home_button()));
if (!should_show_home_button)
return;
GetAppListTestHelper()->CheckVisibility(true);
GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
GetEventGenerator()->MoveMouseTo(center);
GetEventGenerator()->ClickLeftButton();
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
GetEventGenerator()->set_flags(ui::EF_SHIFT_DOWN);
GetEventGenerator()->ClickLeftButton();
GetEventGenerator()->set_flags(0);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
}
TEST_P(HomeButtonTest, ButtonPositionInTabletMode) {
base::RunLoop().RunUntilIdle();
ash::TabletModeControllerTestApi().EnterTabletMode();
Shelf* const shelf = GetPrimaryShelf();
ShelfViewTestAPI shelf_test_api(shelf->GetShelfViewForTesting());
ShelfNavigationWidget::TestApi test_api(shelf->navigation_widget());
const bool should_show_home_button =
!IsHideShelfControlsInTabletModeEnabled();
EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
EXPECT_EQ(should_show_home_button, static_cast<bool>(home_button()));
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
ASSERT_EQ(should_show_home_button, static_cast<bool>(home_button()));
if (should_show_home_button) {
EXPECT_EQ(home_button()->bounds().x(),
ShelfConfig::Get()->control_button_edge_spacing(
true ));
}
std::unique_ptr<views::Widget> widget =
CreateTestWidget(views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET);
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
EXPECT_EQ(should_show_home_button, static_cast<bool>(home_button()));
if (should_show_home_button)
EXPECT_GT(home_button()->bounds().x(), 0);
ash::TabletModeControllerTestApi().LeaveTabletMode();
shelf_test_api.RunMessageLoopUntilAnimationsDone(
test_api.GetBoundsAnimator());
EXPECT_TRUE(test_api.IsHomeButtonVisible());
ASSERT_TRUE(home_button());
EXPECT_EQ(ShelfConfig::Get()->control_button_edge_spacing(
true ),
home_button()->bounds().x());
}
TEST_F(HomeButtonAnimationTest, VisibilityAnimation) {
views::View* const home_button_view = home_button();
ASSERT_TRUE(home_button_view);
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
ash::TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
home_button_view->layer()->GetAnimator()->StopAnimating();
EXPECT_FALSE(home_button_view->GetVisible());
ash::TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
home_button_view->layer()->GetAnimator()->StopAnimating();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
}
TEST_F(HomeButtonAnimationTest, HideWhileAnimatingToShow) {
views::View* const home_button_view = home_button();
ASSERT_TRUE(home_button_view);
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
ash::TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
home_button_view->layer()->GetAnimator()->StopAnimating();
ash::TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
ash::TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
home_button_view->layer()->GetAnimator()->StopAnimating();
EXPECT_FALSE(home_button_view->GetVisible());
}
TEST_F(HomeButtonAnimationTest, ShowWhileAnimatingToHide) {
views::View* const home_button_view = home_button();
ASSERT_TRUE(home_button_view);
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
ash::TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
ash::TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
home_button_view->layer()->GetAnimator()->StopAnimating();
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
}
TEST_F(HomeButtonAnimationTest, NonAnimatedLayoutDuringAnimation) {
views::View* const home_button_view = home_button();
ASSERT_TRUE(home_button_view);
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
ash::TabletModeControllerTestApi().EnterTabletMode();
Shelf* const shelf = GetPrimaryShelf();
ShelfViewTestAPI shelf_test_api(shelf->GetShelfViewForTesting());
ShelfNavigationWidget::TestApi test_api(shelf->navigation_widget());
EXPECT_TRUE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
shelf->navigation_widget()->UpdateLayout(false);
EXPECT_FALSE(home_button_view->GetVisible());
EXPECT_FALSE(home_button_view->layer()->GetAnimator()->is_animating());
EXPECT_FALSE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
ash::TabletModeControllerTestApi().LeaveTabletMode();
EXPECT_TRUE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
shelf->navigation_widget()->UpdateLayout(false);
EXPECT_FALSE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
EXPECT_TRUE(home_button_view->GetVisible());
EXPECT_FALSE(home_button_view->layer()->GetAnimator()->is_animating());
EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
}
inline constexpr LoginInfo k2ndRegularUserLoginInfo = {"user1@tray"};
TEST_P(HomeButtonNoSessionTest, LongPressGestureSunfishScanner) {
auto primary = SimulateUserLogin(kRegularUserLoginInfo);
SimulateUserLogin(k2ndRegularUserLoginInfo);
SwitchActiveUser(primary);
ASSERT_TRUE(CanShowSunfishOrScannerUi());
ShelfNavigationWidget::TestApi test_api(
GetPrimaryShelf()->navigation_widget());
ASSERT_TRUE(test_api.IsHomeButtonVisible());
ASSERT_TRUE(home_button());
ui::GestureEvent long_press = CreateGestureEvent(
ui::GestureEventDetails(ui::EventType::kGestureLongPress));
SendGestureEvent(&long_press);
auto* capture_mode_controller = CaptureModeController::Get();
ASSERT_TRUE(capture_mode_controller->IsActive());
EXPECT_EQ(capture_mode_controller->capture_mode_session()
->active_behavior()
->behavior_type(),
BehaviorType::kSunfish);
capture_mode_controller->Stop();
ASSERT_FALSE(capture_mode_controller->IsActive());
SendGestureEventToSecondaryDisplay(&long_press);
ASSERT_TRUE(capture_mode_controller->IsActive());
EXPECT_EQ(capture_mode_controller->capture_mode_session()
->active_behavior()
->behavior_type(),
BehaviorType::kSunfish);
}
TEST_P(HomeButtonNoSessionTest, LongPressGestureInTabletModeSunfishScanner) {
auto primary = SimulateUserLogin(kRegularUserLoginInfo);
SimulateUserLogin(k2ndRegularUserLoginInfo);
SwitchActiveUser(primary);
ASSERT_TRUE(CanShowSunfishOrScannerUi());
ash::TabletModeControllerTestApi().EnterTabletMode();
ShelfNavigationWidget::TestApi test_api(
GetPrimaryShelf()->navigation_widget());
const bool should_show_home_button =
!IsHideShelfControlsInTabletModeEnabled();
EXPECT_EQ(test_api.IsHomeButtonVisible(), should_show_home_button);
ASSERT_EQ(static_cast<bool>(home_button()), should_show_home_button);
GetAppListTestHelper()->CheckVisibility(true);
GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
if (!should_show_home_button) {
return;
}
ui::GestureEvent long_press = CreateGestureEvent(
ui::GestureEventDetails(ui::EventType::kGestureLongPress));
SendGestureEvent(&long_press);
auto* capture_mode_controller = CaptureModeController::Get();
ASSERT_TRUE(capture_mode_controller->IsActive());
EXPECT_EQ(capture_mode_controller->capture_mode_session()
->active_behavior()
->behavior_type(),
BehaviorType::kSunfish);
}
TEST_P(HomeButtonTest, InteractOutsideHomeButtonBounds) {
EXPECT_EQ(ShelfAlignment::kBottom, GetPrimaryShelf()->alignment());
gfx::Point bottom_left = GetPrimaryShelf()
->shelf_widget()
->GetWindowBoundsInScreen()
.bottom_left();
GetEventGenerator()->GestureTapAt(bottom_left);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
gfx::Point bottom_right = GetPrimaryShelf()
->shelf_widget()
->GetWindowBoundsInScreen()
.bottom_right();
GetEventGenerator()->GestureTapAt(bottom_right);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(false);
GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
gfx::Point top_left =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen().origin();
GetEventGenerator()->GestureTapAt(top_left);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
bottom_left = GetPrimaryShelf()
->shelf_widget()
->GetWindowBoundsInScreen()
.bottom_left();
GetEventGenerator()->GestureTapAt(bottom_left);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(false);
GetPrimaryShelf()->SetAlignment(ShelfAlignment::kRight);
gfx::Point top_right =
GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen().top_right();
GetEventGenerator()->GestureTapAt(top_right);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
bottom_right = GetPrimaryShelf()
->shelf_widget()
->GetWindowBoundsInScreen()
.bottom_right();
GetEventGenerator()->GestureTapAt(bottom_right);
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(false);
}
TEST_P(HomeButtonTest, ClickOnCornerPixel) {
gfx::Point corner(
0, display::Screen::Get()->GetPrimaryDisplay().bounds().height());
ShelfNavigationWidget::TestApi test_api(
GetPrimaryShelf()->navigation_widget());
ASSERT_TRUE(test_api.IsHomeButtonVisible());
GetAppListTestHelper()->CheckVisibility(false);
GetEventGenerator()->MoveMouseTo(corner);
GetEventGenerator()->ClickLeftButton();
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(true);
GetEventGenerator()->ClickLeftButton();
GetAppListTestHelper()->WaitUntilIdle();
GetAppListTestHelper()->CheckVisibility(false);
}
TEST_P(HomeButtonTest, GestureHomeButtonHitTest) {
ShelfNavigationWidget* nav_widget = GetPrimaryShelf()->navigation_widget();
ShelfNavigationWidget::TestApi test_api(nav_widget);
gfx::Rect nav_widget_bounds = nav_widget->GetRootView()->bounds();
EXPECT_TRUE(test_api.IsHomeButtonVisible());
EXPECT_FALSE(test_api.IsBackButtonVisible());
gfx::Point home_button_center(
nav_widget->GetHomeButton()->bounds().CenterPoint());
gfx::Point nav_widget_center(nav_widget_bounds.CenterPoint());
EXPECT_EQ(home_button_center, nav_widget_center);
ui::GestureEventDetails details =
ui::GestureEventDetails(ui::EventType::kGestureTap);
gfx::RectF gesture_event_rect(0, 0, .7f * nav_widget_bounds.width(),
nav_widget_bounds.height());
details.set_bounding_box(gesture_event_rect);
{
const gfx::Point event_center(gesture_event_rect.width() / 2,
gesture_event_rect.height() / 2);
ui::GestureEvent gesture(event_center.x(), event_center.y(), 0,
base::TimeTicks(), details);
ui::EventTargeter* targeter = nav_widget->GetRootView()->GetEventTargeter();
ui::EventTarget* target =
targeter->FindTargetForEvent(nav_widget->GetRootView(), &gesture);
EXPECT_TRUE(target);
EXPECT_EQ(target, nav_widget->GetHomeButton());
}
{
const gfx::Point event_center(nav_widget->GetHomeButton()->bounds().x(),
nav_widget->GetHomeButton()->bounds().y());
ui::GestureEvent gesture(event_center.x(), event_center.y(), 0,
base::TimeTicks(), details);
ui::EventTargeter* targeter = nav_widget->GetRootView()->GetEventTargeter();
ui::EventTarget* target =
targeter->FindTargetForEvent(nav_widget->GetRootView(), &gesture);
EXPECT_TRUE(target);
EXPECT_EQ(target, nav_widget->GetHomeButton());
}
{
const gfx::Point event_center(nav_widget_center.x() - 1,
nav_widget_center.y());
ui::GestureEvent gesture(event_center.x(), event_center.y(), 0,
base::TimeTicks(), details);
ui::EventTargeter* targeter = nav_widget->GetRootView()->GetEventTargeter();
ui::EventTarget* target =
targeter->FindTargetForEvent(nav_widget->GetRootView(), &gesture);
EXPECT_TRUE(target);
EXPECT_EQ(target, nav_widget->GetHomeButton());
}
}
INSTANTIATE_TEST_SUITE_P(
All,
HomeButtonVisibilityWithAccessibilityFeaturesTest,
::testing::Values(
TestAccessibilityFeature::kTabletModeShelfNavigationButtons,
TestAccessibilityFeature::kSpokenFeedback,
TestAccessibilityFeature::kAutoclick,
TestAccessibilityFeature::kSwitchAccess));
TEST_P(HomeButtonVisibilityWithAccessibilityFeaturesTest,
TabletModeSwitchWithA11yFeatureEnabled) {
SetTestA11yFeatureEnabled(true );
ShelfNavigationWidget::TestApi test_api(
GetPrimaryShelf()->navigation_widget());
EXPECT_TRUE(test_api.IsHomeButtonVisible());
ash::TabletModeControllerTestApi().EnterTabletMode();
EXPECT_TRUE(test_api.IsHomeButtonVisible());
SetTestA11yFeatureEnabled(false );
EXPECT_FALSE(test_api.IsHomeButtonVisible());
}
TEST_P(HomeButtonVisibilityWithAccessibilityFeaturesTest,
FeatureEnabledWhileInTabletMode) {
ShelfNavigationWidget::TestApi test_api(
GetPrimaryShelf()->navigation_widget());
EXPECT_TRUE(test_api.IsHomeButtonVisible());
ash::TabletModeControllerTestApi().EnterTabletMode();
EXPECT_FALSE(test_api.IsHomeButtonVisible());
SetTestA11yFeatureEnabled(true );
EXPECT_TRUE(test_api.IsHomeButtonVisible());
}
}