| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <memory> |
| #include <tuple> |
| #include <vector> |
| |
| #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/assistant/assistant_controller_impl.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/focus_cycler.h" |
| #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h" |
| #include "ash/public/cpp/test/assistant_test_api.h" |
| #include "ash/public/cpp/test/shell_test_api.h" |
| #include "ash/shelf/drag_window_from_shelf_controller_test_api.h" |
| #include "ash/shelf/home_button.h" |
| #include "ash/shelf/hotseat_widget.h" |
| #include "ash/shelf/scrollable_shelf_view.h" |
| #include "ash/shelf/shelf.h" |
| #include "ash/shelf/shelf_app_button.h" |
| #include "ash/shelf/shelf_controller.h" |
| #include "ash/shelf/shelf_focus_cycler.h" |
| #include "ash/shelf/shelf_layout_manager.h" |
| #include "ash/shelf/shelf_metrics.h" |
| #include "ash/shelf/shelf_navigation_widget.h" |
| #include "ash/shelf/shelf_test_util.h" |
| #include "ash/shelf/shelf_view.h" |
| #include "ash/shelf/shelf_view_test_api.h" |
| #include "ash/shelf/test/hotseat_state_watcher.h" |
| #include "ash/shelf/test/shelf_layout_manager_test_base.h" |
| #include "ash/shelf/test/widget_animation_smoothness_inspector.h" |
| #include "ash/shell.h" |
| #include "ash/system/ime_menu/ime_menu_tray.h" |
| #include "ash/system/overview/overview_button_tray.h" |
| #include "ash/system/status_area_widget.h" |
| #include "ash/system/unified/unified_system_tray.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/layer_animation_verifier.h" |
| #include "ash/wm/overview/overview_controller.h" |
| #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" |
| #include "ash/wm/window_state.h" |
| #include "ash/wm/wm_event.h" |
| #include "ash/wm/work_area_insets.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/icu_test_util.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "chromeos/ash/services/assistant/public/cpp/assistant_service.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/compositor/presentation_time_recorder.h" |
| #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| #include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/gesture_detection/gesture_configuration.h" |
| #include "ui/events/test/event_generator.h" |
| #include "ui/views/test/widget_animation_waiter.h" |
| #include "ui/wm/core/window_util.h" |
| |
| namespace ash { |
| |
| namespace { |
| ShelfWidget* GetShelfWidget() { |
| return AshTestBase::GetPrimaryShelf()->shelf_widget(); |
| } |
| |
| ShelfLayoutManager* GetShelfLayoutManager() { |
| return AshTestBase::GetPrimaryShelf()->shelf_layout_manager(); |
| } |
| } // namespace |
| |
| class HotseatWidgetTest |
| : public ShelfLayoutManagerTestBase, |
| public testing::WithParamInterface< |
| std::tuple<ShelfAutoHideBehavior, |
| /*is_assistant_enabled*/ bool, |
| /*navigation_buttons_shown_in_tablet_mode*/ bool>> { |
| public: |
| HotseatWidgetTest() |
| : ShelfLayoutManagerTestBase( |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME), |
| shelf_auto_hide_behavior_(std::get<0>(GetParam())), |
| is_assistant_enabled_(std::get<1>(GetParam())), |
| navigation_buttons_shown_in_tablet_mode_(std::get<2>(GetParam())) { |
| if (is_assistant_enabled_) |
| assistant_test_api_ = AssistantTestApi::Create(); |
| } |
| |
| // testing::Test: |
| void SetUp() override { |
| SetupFeatureLists(); |
| ShelfLayoutManagerTestBase::SetUp(); |
| |
| if (is_assistant_enabled_) { |
| assistant_test_api_->SetAssistantEnabled(true); |
| assistant_test_api_->GetAssistantState()->NotifyFeatureAllowed( |
| assistant::AssistantAllowedState::ALLOWED); |
| assistant_test_api_->GetAssistantState()->NotifyStatusChanged( |
| assistant::AssistantStatus::READY); |
| |
| assistant_test_api_->WaitUntilIdle(); |
| } |
| } |
| |
| virtual void SetupFeatureLists() { |
| scoped_feature_list_.InitWithFeatureStates( |
| {{features::kHideShelfControlsInTabletMode, |
| !navigation_buttons_shown_in_tablet_mode()}, |
| {features::kShelfPalmRejectionSwipeOffset, true}}); |
| } |
| |
| void TearDown() override { |
| // Some tests may override this value, make sure it's reset. |
| ui::PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest( |
| false); |
| ShelfLayoutManagerTestBase::TearDown(); |
| } |
| |
| ShelfAutoHideBehavior shelf_auto_hide_behavior() const { |
| return shelf_auto_hide_behavior_; |
| } |
| bool is_assistant_enabled() const { return is_assistant_enabled_; } |
| bool navigation_buttons_shown_in_tablet_mode() const { |
| return navigation_buttons_shown_in_tablet_mode_; |
| } |
| AssistantTestApi* assistant_test_api() { return assistant_test_api_.get(); } |
| |
| void ShowShelfAndActivateAssistant() { |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| SwipeUpOnShelf(); |
| |
| // If the launcher button is not expected to be shown, show the assistant UI |
| // directly; otherwise, simulate the long press on the home button, |
| if (!navigation_buttons_shown_in_tablet_mode_ && |
| display::Screen::GetScreen()->InTabletMode()) { |
| AssistantUiController::Get()->ShowUi( |
| assistant::AssistantEntryPoint::kLongPressLauncher); |
| return; |
| } |
| |
| views::View* home_button = |
| GetPrimaryShelf()->navigation_widget()->GetHomeButton(); |
| auto center_point = home_button->GetBoundsInScreen().CenterPoint(); |
| |
| GetEventGenerator()->set_current_screen_location(center_point); |
| GetEventGenerator()->PressTouch(); |
| GetAppListTestHelper()->WaitUntilIdle(); |
| |
| // Advance clock to make sure long press gesture is triggered. |
| task_environment()->AdvanceClock(base::Seconds(5)); |
| GetAppListTestHelper()->WaitUntilIdle(); |
| |
| GetEventGenerator()->ReleaseTouch(); |
| GetAppListTestHelper()->WaitUntilIdle(); |
| } |
| |
| void ShowShelfAndGoHome() { |
| // If the launcher button is not expected to be shown, go home directly; |
| // otherwise, simulate tap on the home button, |
| if (!navigation_buttons_shown_in_tablet_mode_ && |
| display::Screen::GetScreen()->InTabletMode()) { |
| Shell::Get()->app_list_controller()->GoHome(GetPrimaryDisplay().id()); |
| return; |
| } |
| |
| // Ensure the shelf, and the home button, are visible. |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| SwipeUpOnShelf(); |
| views::View* home_button = |
| GetPrimaryShelf()->navigation_widget()->GetHomeButton(); |
| GetEventGenerator()->GestureTapAt( |
| home_button->GetBoundsInScreen().CenterPoint()); |
| } |
| |
| void StartOverview() { |
| ASSERT_FALSE(OverviewController::Get()->InOverviewSession()); |
| |
| // If the overview button is not expected to be shown, start overview |
| // directly; otherwise, simulate tap on the overview button, which should |
| // toggle overview. |
| if (!navigation_buttons_shown_in_tablet_mode_ && |
| display::Screen::GetScreen()->InTabletMode()) { |
| EnterOverview(); |
| return; |
| } |
| |
| const gfx::Point overview_button_center = GetPrimaryShelf() |
| ->status_area_widget() |
| ->overview_button_tray() |
| ->GetBoundsInScreen() |
| .CenterPoint(); |
| GetEventGenerator()->GestureTapAt(overview_button_center); |
| } |
| |
| void EndOverview() { |
| ASSERT_TRUE(OverviewController::Get()->InOverviewSession()); |
| |
| // If the overview button is not expected to be shown, end overview |
| // directly; otherwise, simulate tap on the overview button, which should |
| // toggle overview. |
| if (!navigation_buttons_shown_in_tablet_mode_ && |
| display::Screen::GetScreen()->InTabletMode()) { |
| ExitOverview(); |
| return; |
| } |
| |
| const gfx::Point overview_button_center = GetPrimaryShelf() |
| ->status_area_widget() |
| ->overview_button_tray() |
| ->GetBoundsInScreen() |
| .CenterPoint(); |
| GetEventGenerator()->GestureTapAt(overview_button_center); |
| } |
| |
| private: |
| friend class StackedHotseatWidgetTest; |
| const ShelfAutoHideBehavior shelf_auto_hide_behavior_; |
| const bool is_assistant_enabled_; |
| const bool navigation_buttons_shown_in_tablet_mode_; |
| std::unique_ptr<AssistantTestApi> assistant_test_api_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| class StackedHotseatWidgetTest : public HotseatWidgetTest { |
| public: |
| void SetupFeatureLists() override { |
| scoped_feature_list_.InitWithFeatureStates( |
| {{features::kHideShelfControlsInTabletMode, |
| !navigation_buttons_shown_in_tablet_mode()}, |
| {features::kShelfPalmRejectionSwipeOffset, true}, |
| {features::kShelfStackedHotseat, true}}); |
| } |
| }; |
| |
| // Counts the number of times the work area changes. |
| class DisplayWorkAreaChangeCounter : public display::DisplayObserver { |
| public: |
| DisplayWorkAreaChangeCounter() { |
| Shell::Get()->display_manager()->AddObserver(this); |
| } |
| |
| DisplayWorkAreaChangeCounter(const DisplayWorkAreaChangeCounter&) = delete; |
| DisplayWorkAreaChangeCounter& operator=(const DisplayWorkAreaChangeCounter&) = |
| delete; |
| |
| ~DisplayWorkAreaChangeCounter() override { |
| Shell::Get()->display_manager()->RemoveObserver(this); |
| } |
| |
| void OnDisplayMetricsChanged(const display::Display& display, |
| uint32_t metrics) override { |
| if (metrics & display::DisplayObserver::DISPLAY_METRIC_WORK_AREA) |
| work_area_change_count_++; |
| } |
| |
| int count() const { return work_area_change_count_; } |
| |
| private: |
| int work_area_change_count_ = 0; |
| }; |
| |
| // Watches the shelf for state changes. |
| class ShelfStateWatcher : public ShelfObserver { |
| public: |
| ShelfStateWatcher() { AshTestBase::GetPrimaryShelf()->AddObserver(this); } |
| ~ShelfStateWatcher() override { |
| AshTestBase::GetPrimaryShelf()->RemoveObserver(this); |
| } |
| void OnShelfVisibilityStateChanged(ShelfVisibilityState new_state) override { |
| state_change_count_++; |
| } |
| int state_change_count() const { return state_change_count_; } |
| |
| private: |
| int state_change_count_ = 0; |
| }; |
| |
| // Watches the Hotseat transition animation states. |
| class HotseatTransitionAnimationObserver |
| : public HotseatTransitionAnimator::Observer { |
| public: |
| explicit HotseatTransitionAnimationObserver( |
| HotseatTransitionAnimator* hotseat_transition_animator) |
| : hotseat_transition_animator_(hotseat_transition_animator) { |
| hotseat_transition_animator_->AddObserver(this); |
| } |
| ~HotseatTransitionAnimationObserver() override { |
| hotseat_transition_animator_->RemoveObserver(this); |
| } |
| |
| // HotseatTransitionAnimtor::Observer: |
| void OnHotseatTransitionAnimationWillStart(HotseatState from_state, |
| HotseatState to_start) override { |
| ++observer_counts_.started; |
| } |
| void OnHotseatTransitionAnimationEnded(HotseatState from_state, |
| HotseatState to_start) override { |
| ++observer_counts_.ended; |
| if (run_loop_) |
| run_loop_->Quit(); |
| } |
| void OnHotseatTransitionAnimationAborted() override { |
| ++observer_counts_.aborted; |
| } |
| |
| void Wait() { |
| run_loop_ = std::make_unique<base::RunLoop>(); |
| run_loop_->Run(); |
| } |
| |
| void Reset() { |
| if (run_loop_) |
| run_loop_->Quit(); |
| observer_counts_ = {0}; |
| } |
| |
| // Checks that the started and ending/aborting methods have fired the same |
| // amount of times. |
| bool ObserverCountsEqual() const { |
| return observer_counts_.started == |
| (observer_counts_.ended + observer_counts_.aborted); |
| } |
| |
| int AnimationAbortedCalls() const { return observer_counts_.aborted; } |
| |
| private: |
| // Struct which keeps track of the counts of the Observer method has fired. |
| // These are used to verify that started calls = ended calls + aborted calls. |
| struct ObserverCounts { |
| int started; |
| int ended; |
| int aborted; |
| } observer_counts_ = {0}; |
| std::unique_ptr<base::RunLoop> run_loop_; |
| raw_ptr<HotseatTransitionAnimator, ExperimentalAsh> |
| hotseat_transition_animator_; |
| }; |
| |
| // Used to test the Hotseat, ScrollableShelf, and DenseShelf features. |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| HotseatWidgetTest, |
| testing::Combine( |
| testing::Values(ShelfAutoHideBehavior::kNever, |
| ShelfAutoHideBehavior::kAlways), |
| /*is_assistant_enabled*/ testing::Bool(), |
| /*navigation_buttons_shown_in_tablet_mode*/ testing::Bool())); |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| StackedHotseatWidgetTest, |
| testing::Combine( |
| testing::Values(ShelfAutoHideBehavior::kNever, |
| ShelfAutoHideBehavior::kAlways), |
| /*is_assistant_enabled*/ testing::Bool(), |
| /*navigation_buttons_shown_in_tablet_mode*/ testing::Bool())); |
| |
| // TODO(b:270757104) Set status are widget sizes. |
| TEST_P(StackedHotseatWidgetTest, StackedHotseatShownOnSmallScreens) { |
| UpdateDisplay("475x350"); |
| base::HistogramTester histogram_tester; |
| // Nothing logged before entering the tablet mode. |
| histogram_tester.ExpectTotalCount("Ash.Shelf.ShowStackedHotseat", 0); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| GetAppListTestHelper()->CheckVisibility(true); |
| const gfx::Rect hotseat_bounds = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen(); |
| ASSERT_EQ(hotseat_bounds.bottom(), |
| 350 - ShelfConfig::Get()->hotseat_bottom_padding() * 2 - |
| ShelfConfig::Get()->shelf_size()); |
| |
| // Showed stacked hostseat. |
| histogram_tester.ExpectBucketCount("Ash.Shelf.ShowStackedHotseat", true, 1); |
| histogram_tester.ExpectBucketCount("Ash.Shelf.ShowStackedHotseat", false, 0); |
| } |
| |
| // TODO(b:270757104) Set status are widget sizes. |
| TEST_P(StackedHotseatWidgetTest, StackedHotseatNotShownOnLargeScreens) { |
| UpdateDisplay("800x600"); |
| |
| base::HistogramTester histogram_tester; |
| // Nothing logged before entering the tablet mode. |
| histogram_tester.ExpectTotalCount("Ash.Shelf.ShowStackedHotseat", 0); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| GetAppListTestHelper()->CheckVisibility(true); |
| const gfx::Rect hotseat_bounds = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen(); |
| ASSERT_EQ(hotseat_bounds.bottom(), |
| 600 - ShelfConfig::Get()->hotseat_bottom_padding()); |
| |
| // Showed regular hotseat. |
| histogram_tester.ExpectBucketCount("Ash.Shelf.ShowStackedHotseat", true, 0); |
| histogram_tester.ExpectBucketCount("Ash.Shelf.ShowStackedHotseat", false, 1); |
| } |
| |
| TEST_P(HotseatWidgetTest, LongPressHomeWithoutAppWindow) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| GetAppListTestHelper()->CheckVisibility(true); |
| |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| |
| ShowShelfAndActivateAssistant(); |
| GetAppListTestHelper()->CheckVisibility(true); |
| |
| EXPECT_EQ( |
| is_assistant_enabled(), |
| GetAppListTestHelper()->GetAppListView()->IsShowingEmbeddedAssistantUI()); |
| |
| // Hotseat should not change when showing Assistant. |
| watcher.CheckEqual({}); |
| } |
| |
| TEST_P(HotseatWidgetTest, LongPressHomeWithAppWindow) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| GetAppListTestHelper()->CheckVisibility(true); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| |
| ShowShelfAndActivateAssistant(); |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| EXPECT_EQ( |
| is_assistant_enabled(), |
| GetAppListTestHelper()->GetAppListView()->IsShowingEmbeddedAssistantUI()); |
| |
| std::vector<HotseatState> expected_state; |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| // |ShowShelfAndActivateAssistant()| will bring up shelf so it will trigger |
| // one hotseat state change. |
| expected_state.push_back(HotseatState::kExtended); |
| // Launching the assistant from a shelf button on an autohidden shelf will |
| // hide the shelf at the end of the operation. |
| if (is_assistant_enabled() && navigation_buttons_shown_in_tablet_mode()) |
| expected_state.push_back(HotseatState::kHidden); |
| } |
| watcher.CheckEqual(expected_state); |
| } |
| |
| // Tests that closing a window which was opened prior to entering tablet mode |
| // results in a kShownHomeLauncher hotseat. |
| TEST_P(HotseatWidgetTest, ClosingLastWindowInTabletMode) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| // Activate the window and go to tablet mode. |
| wm::ActivateWindow(window.get()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| // Close the window, the AppListView should be shown, and the hotseat should |
| // be kShownHomeLauncher. |
| window->Hide(); |
| |
| EXPECT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| GetAppListTestHelper()->CheckVisibility(true); |
| } |
| |
| // Tests that the hotseat is kShownHomeLauncher when entering tablet mode with |
| // no windows. |
| TEST_P(HotseatWidgetTest, GoingToTabletModeNoWindows) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| GetAppListTestHelper()->CheckVisibility(true); |
| EXPECT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that the hotseat is kHidden when entering tablet mode with a window. |
| TEST_P(HotseatWidgetTest, GoingToTabletModeWithWindows) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| // Activate the window and go to tablet mode. |
| wm::ActivateWindow(window.get()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| } |
| |
| // The in-app Hotseat should not be hidden automatically when the shelf context |
| // menu shows (https://crbug.com/1020388). |
| TEST_P(HotseatWidgetTest, InAppShelfShowingContextMenu) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible( |
| display::Screen::GetScreen()->GetPrimaryDisplay().id())); |
| |
| ShelfTestUtil::AddAppShortcut("app_id", TYPE_PINNED_APP); |
| |
| // Swipe up on the shelf to show the hotseat. |
| SwipeUpOnShelf(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| ShelfViewTestAPI shelf_view_test_api( |
| GetPrimaryShelf()->shelf_widget()->shelf_view_for_testing()); |
| ShelfAppButton* app_icon = shelf_view_test_api.GetButton(0); |
| |
| // Accelerate the generation of the long press event. |
| ui::GestureConfiguration::GetInstance()->set_show_press_delay_in_ms(1); |
| ui::GestureConfiguration::GetInstance()->set_short_press_time( |
| base::Milliseconds(1)); |
| ui::GestureConfiguration::GetInstance()->set_long_press_time_in_ms(1); |
| |
| // Press the icon enough long time to generate the long press event. |
| GetEventGenerator()->MoveTouch(app_icon->GetBoundsInScreen().CenterPoint()); |
| GetEventGenerator()->PressTouch(); |
| ui::GestureConfiguration* gesture_config = |
| ui::GestureConfiguration::GetInstance(); |
| const int long_press_delay_ms = gesture_config->long_press_time_in_ms() + |
| gesture_config->show_press_delay_in_ms(); |
| base::RunLoop run_loop; |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, run_loop.QuitClosure(), |
| base::Milliseconds(long_press_delay_ms)); |
| run_loop.Run(); |
| GetEventGenerator()->ReleaseTouch(); |
| |
| // Expects that the hotseat's state is kExntended. |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Ensures that the ink drop state is InkDropState::ACTIVATED before closing |
| // the menu. |
| app_icon->FireRippleActivationTimerForTest(); |
| } |
| |
| // Tests that a window that is created after going to tablet mode, then closed, |
| // results in a kShownHomeLauncher hotseat. |
| TEST_P(HotseatWidgetTest, CloseLastWindowOpenedInTabletMode) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| // Activate the window after entering tablet mode. |
| wm::ActivateWindow(window.get()); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| // Hide the window, the hotseat should be kShownHomeLauncher, and the home |
| // launcher should be visible. |
| window->Hide(); |
| |
| EXPECT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| GetAppListTestHelper()->CheckVisibility(true); |
| } |
| |
| // Verifies removing a shelf item by dragging it off the extended hotseat. |
| TEST_P(HotseatWidgetTest, DragItemOffExtendedHotseat) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| ShelfTestUtil::AddAppShortcut("app_id_1", TYPE_PINNED_APP); |
| ShelfTestUtil::AddAppShortcut("app_id_2", TYPE_PINNED_APP); |
| |
| ShelfView* shelf_view = GetPrimaryShelf() |
| ->hotseat_widget() |
| ->scrollable_shelf_view() |
| ->shelf_view(); |
| EXPECT_EQ(2u, shelf_view->view_model_for_test()->view_size()); |
| |
| // Show the in-app shelf. |
| SwipeUpOnShelf(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Start mouse drag on a shelf item. |
| ShelfAppButton* dragged_button = |
| ShelfViewTestAPI(shelf_view).GetButton(/*index=*/0); |
| GetEventGenerator()->MoveMouseTo( |
| dragged_button->GetBoundsInScreen().CenterPoint()); |
| GetEventGenerator()->PressLeftButton(); |
| EXPECT_TRUE(dragged_button->FireDragTimerForTest()); |
| EXPECT_TRUE(shelf_view->drag_view()); |
| |
| // Move mouse. Verify that the hotseat is still extended. |
| GetEventGenerator()->MoveMouseBy(/*x=*/0, /*y=*/-80); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Release the mouse press. Verify that: |
| // 1. Shelf item count decreases by one; and |
| // 2. Hotseat is still extended. |
| GetEventGenerator()->ReleaseLeftButton(); |
| EXPECT_EQ(1u, shelf_view->view_model_for_test()->view_size()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that swiping up on an autohidden shelf shows the hotseat, and swiping |
| // down hides it. |
| TEST_P(HotseatWidgetTest, ShowingAndHidingAutohiddenShelf) { |
| if (shelf_auto_hide_behavior() != ShelfAutoHideBehavior::kAlways) |
| return; |
| |
| GetPrimaryShelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| SwipeDownOnShelf(); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| // Swipe down again, nothing should change. |
| SwipeDownOnShelf(); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); |
| } |
| |
| // Tests that swiping up on several places in the in-app shelf shows the |
| // hotseat (crbug.com/1016931). |
| TEST_P(HotseatWidgetTest, SwipeUpInAppShelfShowsHotseat) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| // Swipe up from the center of the shelf. |
| SwipeUpOnShelf(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| |
| // Swipe down from the hotseat to hide it. |
| gfx::Rect hotseat_bounds = |
| GetPrimaryShelf()->hotseat_widget()->GetWindowBoundsInScreen(); |
| gfx::Point start = hotseat_bounds.top_center(); |
| gfx::Point end = start + gfx::Vector2d(0, 80); |
| const base::TimeDelta kTimeDelta = base::Milliseconds(100); |
| const int kNumScrollSteps = 4; |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 1); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| |
| // Swipe up from the right part of the shelf (the system tray). |
| start = GetShelfWidget() |
| ->status_area_widget() |
| ->GetWindowBoundsInScreen() |
| .CenterPoint(); |
| end = start + gfx::Vector2d(0, -80); |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 1); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 2); |
| |
| // Swipe down from the hotseat to hide it. |
| start = hotseat_bounds.top_center(); |
| end = start + gfx::Vector2d(0, 80); |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 2); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 2); |
| |
| // Swipe up from the left part of the shelf (the home/back button). |
| start = GetShelfWidget() |
| ->navigation_widget() |
| ->GetWindowBoundsInScreen() |
| .CenterPoint(); |
| end = start + gfx::Vector2d(0, -80); |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 2); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 3); |
| } |
| |
| // Tests that swiping up on the hotseat does nothing. |
| TEST_P(HotseatWidgetTest, SwipeUpOnHotseatBackgroundDoesNothing) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| // Swipe up on the shelf to show the hotseat. |
| EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible( |
| display::Screen::GetScreen()->GetPrimaryDisplay().id())); |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| // Swipe up on the Hotseat (parent of ShelfView) does nothing. |
| gfx::Point start(GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen() |
| .top_center()); |
| const gfx::Point end(start + gfx::Vector2d(0, -300)); |
| const base::TimeDelta kTimeDelta = base::Milliseconds(100); |
| const int kNumScrollSteps = 4; |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible( |
| display::Screen::GetScreen()->GetPrimaryDisplay().id())); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| } |
| |
| // Tests that tapping an active window with an extended hotseat results in a |
| // hidden hotseat. |
| TEST_P(HotseatWidgetTest, TappingActiveWindowHidesHotseat) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| histogram_tester.ExpectBucketCount( |
| kHotseatGestureHistogramName, |
| InAppShelfGestures::kHotseatHiddenDueToInteractionOutsideOfShelf, 0); |
| |
| // Swipe up on the shelf to show the hotseat. |
| SwipeUpOnShelf(); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| histogram_tester.ExpectBucketCount( |
| kHotseatGestureHistogramName, |
| InAppShelfGestures::kHotseatHiddenDueToInteractionOutsideOfShelf, 0); |
| |
| // Tap the shelf background, nothing should happen. |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| gfx::Point tap_point = display_bounds.bottom_center(); |
| GetEventGenerator()->GestureTapAt(tap_point); |
| |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| // Tap the active window, the hotseat should hide. |
| tap_point.Offset(0, -200); |
| GetEventGenerator()->GestureTapAt(tap_point); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| histogram_tester.ExpectBucketCount( |
| kHotseatGestureHistogramName, |
| InAppShelfGestures::kHotseatHiddenDueToInteractionOutsideOfShelf, 1); |
| } |
| |
| // Tests that gesture dragging an active window hides the hotseat. |
| TEST_P(HotseatWidgetTest, GestureDraggingActiveWindowHidesHotseat) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| // Swipe up on the shelf to show the hotseat. |
| SwipeUpOnShelf(); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| // Gesture drag on the active window, the hotseat should hide. |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| gfx::Point start = display_bounds.bottom_center(); |
| start.Offset(0, -200); |
| gfx::Point end = start; |
| end.Offset(0, -200); |
| GetEventGenerator()->GestureScrollSequence(start, end, base::Milliseconds(10), |
| 4); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| } |
| |
| // Tests that a swipe up on the shelf shows the hotseat while in split view. |
| TEST_P(HotseatWidgetTest, SwipeUpOnShelfShowsHotseatInSplitView) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| std::unique_ptr<aura::Window> window2 = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| // Go into split view mode by first going into overview, and then snapping |
| // the open window on one side. |
| EnterOverview(); |
| SplitViewController* split_view_controller = |
| SplitViewController::Get(Shell::GetPrimaryRootWindow()); |
| split_view_controller->SnapWindow( |
| window.get(), SplitViewController::SnapPosition::kPrimary); |
| split_view_controller->SnapWindow( |
| window2.get(), SplitViewController::SnapPosition::kSecondary); |
| EXPECT_TRUE(split_view_controller->BothSnapped()); |
| |
| // We should still be able to drag up the hotseat. |
| SwipeUpOnShelf(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| } |
| |
| // Tests that HotseatTransitionAimationObserver starting and ending calls have a |
| // 1:1 relation. This test verifies that behavior. |
| TEST_P(HotseatWidgetTest, ObserverCallsMatch) { |
| ui::ScopedAnimationDurationScaleMode non_zero( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| // Enter tablet mode to show the home launcher. Hotseat state should be |
| // kShownHomeLauncher. |
| TabletModeControllerTestApi().EnterTabletMode(); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| |
| // Create a window to transition to the in-app shelf. Hotseat state should be |
| // kHidden. |
| HotseatTransitionAnimationObserver observer( |
| GetPrimaryShelf()->shelf_widget()->hotseat_transition_animator()); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800)); |
| observer.Wait(); |
| EXPECT_TRUE(observer.ObserverCountsEqual()); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| observer.Reset(); |
| // Go to home launcher again. Hotseat state should be kShownHomeLauncher. |
| ShowShelfAndGoHome(); |
| observer.Wait(); |
| EXPECT_TRUE(observer.ObserverCountsEqual()); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| |
| observer.Reset(); |
| // Go to overview and cancel immediately. Hotseat state should be |
| // kShownHomeLauncher. |
| StartOverview(); |
| EXPECT_TRUE(OverviewController::Get()->IsInStartAnimation()); |
| // No animations should have been started so no animations are in progress |
| // or aborted. |
| EXPECT_TRUE(observer.ObserverCountsEqual()); |
| EXPECT_EQ(0, observer.AnimationAbortedCalls()); |
| |
| EndOverview(); |
| |
| // No animations should have been started or aborted. |
| EXPECT_EQ(0, observer.AnimationAbortedCalls()); |
| EXPECT_TRUE(observer.ObserverCountsEqual()); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| |
| observer.Reset(); |
| // Go to overview. Hotseat state should be kExtended. |
| StartOverview(); |
| |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(observer.ObserverCountsEqual()); |
| } |
| |
| // Tests that a swipe up on the shelf shows the hotseat while in split view. |
| TEST_P(HotseatWidgetTest, DisableBlurDuringOverviewMode) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| ASSERT_EQ( |
| ShelfConfig::Get()->shelf_blur_radius(), |
| GetShelfWidget()->hotseat_widget()->GetHotseatBackgroundBlurForTest()); |
| |
| // Go into overview and check that at the end of the animation, background |
| // blur is disabled. |
| StartOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| EXPECT_EQ( |
| 0, GetShelfWidget()->hotseat_widget()->GetHotseatBackgroundBlurForTest()); |
| |
| // Exit overview and check that at the end of the animation, background |
| // blur is enabled again. |
| EndOverview(); |
| WaitForOverviewAnimation(/*enter=*/false); |
| EXPECT_EQ( |
| ShelfConfig::Get()->shelf_blur_radius(), |
| GetShelfWidget()->hotseat_widget()->GetHotseatBackgroundBlurForTest()); |
| } |
| |
| // Tests that releasing the hotseat gesture below the threshold results in a |
| // kHidden hotseat when the shelf is shown. |
| TEST_P(HotseatWidgetTest, ReleasingSlowDragBelowThreshold) { |
| GetPrimaryShelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| const gfx::Point start(display_bounds.bottom_center()); |
| const int hotseat_size = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen() |
| .height(); |
| const gfx::Point end(start + gfx::Vector2d(0, -hotseat_size / 2 + 1)); |
| const base::TimeDelta kTimeDelta = base::Milliseconds(1000); |
| const int kNumScrollSteps = 4; |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| } |
| |
| // Tests that releasing the hotseat gesture above the threshold results in a |
| // kExtended hotseat. |
| TEST_P(HotseatWidgetTest, ReleasingSlowDragAboveThreshold) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| const gfx::Point start(display_bounds.bottom_center()); |
| const int hotseat_size = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen() |
| .height(); |
| const gfx::Point end(start + gfx::Vector2d(0, -hotseat_size * 3.0f / 2.0f)); |
| const base::TimeDelta kTimeDelta = base::Milliseconds(1000); |
| const int kNumScrollSteps = 4; |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| } |
| |
| // Tests that releasing the hotseat gesture when a stylus app is active has a |
| // bigger thresehold than normal apps. |
| TEST_P(HotseatWidgetTest, HotseatDragGestureForStylusApp) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| // Taken from ShelfLayoutManager. |
| const int kShelfPalmRejectionSwipeOffset = 80; |
| const std::string stylus_app = "fhapgmpiiiigioilnjmkiohjhlegnceb"; |
| |
| ShelfModel* model = Shell::Get()->shelf_controller()->model(); |
| const ShelfID test_stylus_app_id(stylus_app); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| window->SetProperty(kShelfIDKey, test_stylus_app_id.Serialize()); |
| wm::ActivateWindow(window.get()); |
| |
| EXPECT_EQ(test_stylus_app_id, model->active_shelf_id()); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| const gfx::Point start(display_bounds.bottom_center()); |
| const int hotseat_size = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen() |
| .height(); |
| const gfx::Point normal_thereshold( |
| start + gfx::Vector2d(0, -hotseat_size * 3.0f / 2.0f)); |
| const base::TimeDelta kTimeDelta = base::Milliseconds(1000); |
| const int kNumScrollSteps = 4; |
| GetEventGenerator()->GestureScrollSequence(start, normal_thereshold, |
| kTimeDelta, kNumScrollSteps); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| const gfx::Point offset_thereshold( |
| normal_thereshold + gfx::Vector2d(0, -kShelfPalmRejectionSwipeOffset)); |
| GetEventGenerator()->GestureScrollSequence(start, offset_thereshold, |
| kTimeDelta, kNumScrollSteps); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, GetPrimaryShelf()->GetAutoHideState()); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeDownToHide, 0); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| } |
| |
| // Tests that showing overview after showing the hotseat results in only one |
| // animation, to |kExtended|. |
| TEST_P(HotseatWidgetTest, ShowingOverviewFromShownAnimatesOnce) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| std::unique_ptr<HotseatStateWatcher> state_watcher_ = |
| std::make_unique<HotseatStateWatcher>(GetShelfLayoutManager()); |
| SwipeUpOnShelf(); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| StartOverview(); |
| state_watcher_->CheckEqual({HotseatState::kExtended}); |
| } |
| |
| // Tests that the hotseat is not flush with the bottom of the screen when home |
| // launcher is showing. |
| TEST_P(HotseatWidgetTest, HotseatNotFlushWhenHomeLauncherShowing) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| const int display_height = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height(); |
| const int hotseat_bottom = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen() |
| .bottom(); |
| EXPECT_LT(hotseat_bottom, display_height); |
| } |
| |
| // Tests that home -> overview results in only one hotseat state change. |
| TEST_P(HotseatWidgetTest, HomeToOverviewChangesStateOnce) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| // First, try with no windows open. |
| { |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| StartOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| watcher.CheckEqual({/* shelf state should not change*/}); |
| } |
| |
| // Open a window, then open the home launcher. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| ShowShelfAndGoHome(); |
| GetAppListTestHelper()->CheckVisibility(true); |
| |
| // Activate overview and expect the hotseat only changes state to extended. |
| { |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| StartOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| |
| watcher.CheckEqual({/* shelf state should not change*/}); |
| } |
| } |
| |
| // Verifies that the hotseat widget and the status area widget are animated to |
| // the target location when entering overview mode in home launcher |
| // (https://crbug.com/1079347). |
| TEST_P(HotseatWidgetTest, VerifyShelfAnimationWhenEnteringOverview) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| ui::ScopedAnimationDurationScaleMode non_zero_duration_mode( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| |
| HotseatWidget* hotseat_widget = GetPrimaryShelf()->hotseat_widget(); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, hotseat_widget->state()); |
| |
| ui::LayerAnimator* hotseat_layer_animator = |
| hotseat_widget->GetNativeView()->layer()->GetAnimator(); |
| ui::LayerAnimator* status_area_layer_animator = GetShelfWidget() |
| ->status_area_widget() |
| ->GetNativeView() |
| ->layer() |
| ->GetAnimator(); |
| ASSERT_FALSE(hotseat_layer_animator->is_animating()); |
| ASSERT_FALSE(status_area_layer_animator->is_animating()); |
| |
| StartOverview(); |
| EXPECT_FALSE(hotseat_layer_animator->is_animating()); |
| EXPECT_FALSE(status_area_layer_animator->is_animating()); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, hotseat_widget->state()); |
| } |
| |
| // Tests that home -> in-app results in only one state change. |
| TEST_P(HotseatWidgetTest, HomeToInAppChangesStateOnce) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| // Go to in-app, the hotseat should hide. |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| watcher.CheckEqual({HotseatState::kHidden}); |
| } |
| |
| // Tests that in-app -> home via closing the only window, swiping from the |
| // bottom of the shelf, and tapping the home launcher button results in only one |
| // state change. |
| TEST_P(HotseatWidgetTest, InAppToHomeChangesStateOnce) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| // Go to in-app with an extended hotseat. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| SwipeUpOnShelf(); |
| |
| // Press the home button, the hotseat should transition directly to |
| // kShownHomeLauncher. |
| { |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| ShowShelfAndGoHome(); |
| watcher.CheckEqual({HotseatState::kShownHomeLauncher}); |
| } |
| // Go to in-app. |
| window->Show(); |
| wm::ActivateWindow(window.get()); |
| |
| // Extend the hotseat, then Swipe up to go home, the hotseat should transition |
| // directly to kShownHomeLauncher. |
| SwipeUpOnShelf(); |
| { |
| ui::ScopedAnimationDurationScaleMode regular_animations( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| FlingUpOnShelf(); |
| watcher.CheckEqual({HotseatState::kShownHomeLauncher}); |
| |
| // Wait for the window animation to complete, and verify the hotseat state |
| // remained kShownHomeLauncher. |
| ShellTestApi().WaitForWindowFinishAnimating(window.get()); |
| watcher.CheckEqual({HotseatState::kShownHomeLauncher}); |
| } |
| |
| // Nothing left to test for autohidden shelf. |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| return; |
| |
| // Go to in-app and do not extend the hotseat. |
| window->Show(); |
| wm::ActivateWindow(window.get()); |
| |
| // TODO(manucornet): This is flaky when the shelf is always auto-hidden. |
| // Investigate and fix (sometimes fails when the assistant is enabled, |
| // sometimes not). |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kNever) |
| return; |
| |
| // Press the home button, the hotseat should transition directly to |
| // kShownHomeLauncher. |
| { |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| ShowShelfAndGoHome(); |
| watcher.CheckEqual({HotseatState::kShownHomeLauncher}); |
| } |
| } |
| |
| // Tests that transitioning from overview to home while a transition from home |
| // to overview is still in progress ends up with hotseat in kShownHomeLauncher |
| // state (and in app shelf not visible). |
| TEST_P(HotseatWidgetTest, HomeToOverviewAndBack) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| WindowState::Get(window.get())->Minimize(); |
| |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| |
| // Start going to overview. |
| { |
| ui::ScopedAnimationDurationScaleMode regular_animations( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| StartOverview(); |
| |
| watcher.CheckEqual({/*Hotseat state should not change*/}); |
| } |
| |
| OverviewController* overview_controller = OverviewController::Get(); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| |
| ShowShelfAndGoHome(); |
| |
| GetAppListTestHelper()->CheckVisibility(true); |
| EXPECT_FALSE(overview_controller->InOverviewSession()); |
| EXPECT_FALSE(ShelfConfig::Get()->is_in_app()); |
| |
| watcher.CheckEqual({/*Hotseat state should not change*/}); |
| } |
| |
| TEST_P(HotseatWidgetTest, InAppToOverviewAndBack) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // Start watching hotseat state before swipping up the shelf, so hotseat |
| // change expectation match for both auto-hidden and always-shown shelf. |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| |
| // Make sure shelf (and overview button) are visible - this is moves the |
| // hotseat into kExtended state. |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| SwipeUpOnShelf(); |
| |
| // Start going to overview - use non zero animation so transition is not |
| // immediate. |
| { |
| ui::ScopedAnimationDurationScaleMode regular_animations( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| StartOverview(); |
| } |
| |
| OverviewController* overview_controller = OverviewController::Get(); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| // Hotseat should be extended as overview is starting. |
| watcher.CheckEqual({HotseatState::kExtended}); |
| |
| // Exit overview to go back to the app window. |
| EndOverview(); |
| EXPECT_FALSE(overview_controller->InOverviewSession()); |
| EXPECT_TRUE(ShelfConfig::Get()->is_in_app()); |
| |
| // The hotseat is expected to be hidden. |
| watcher.CheckEqual({HotseatState::kExtended, HotseatState::kHidden}); |
| } |
| |
| // Tests transition to home screen initiated while transition from app window to |
| // overview is in progress. |
| TEST_P(HotseatWidgetTest, ShowShelfAndGoHomeDuringInAppToOverviewTransition) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // Start watching hotseat state before swipping up the shelf, so hotseat |
| // change expectation match for both auto-hidden and always-shown shelf. |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| |
| // Make sure shelf (and overview button) are visible - this is moves the |
| // hotseat into kExtended state. |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) |
| SwipeUpOnShelf(); |
| |
| // Start going to overview - use non zero animation so transition is not |
| // immediate. |
| { |
| ui::ScopedAnimationDurationScaleMode regular_animations( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| StartOverview(); |
| } |
| |
| OverviewController* overview_controller = OverviewController::Get(); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| // Hotseat should be extended as overview is starting. |
| watcher.CheckEqual({HotseatState::kExtended}); |
| |
| // Go home - expect transition to home (with hotseat in kShownHomeLauncher |
| // state, and in app shelf hidden). |
| ShowShelfAndGoHome(); |
| |
| GetAppListTestHelper()->CheckVisibility(true); |
| EXPECT_FALSE(overview_controller->InOverviewSession()); |
| EXPECT_FALSE(ShelfConfig::Get()->is_in_app()); |
| |
| watcher.CheckEqual( |
| {HotseatState::kExtended, HotseatState::kShownHomeLauncher}); |
| } |
| |
| // Tests that in-app -> overview results in only one state change with an |
| // autohidden shelf. |
| TEST_P(HotseatWidgetTest, InAppToOverviewChangesStateOnceAutohiddenShelf) { |
| GetPrimaryShelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| // Test going to overview mode using the controller from an autohide hidden |
| // shelf. Go to in-app. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| { |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| // Enter overview by using the controller. |
| EnterOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| |
| watcher.CheckEqual({HotseatState::kExtended}); |
| } |
| |
| ExitOverview(); |
| WaitForOverviewAnimation(/*enter=*/false); |
| |
| // Test in-app -> overview again with the autohide shown shelf. |
| EXPECT_TRUE(ShelfConfig::Get()->is_in_app()); |
| EXPECT_EQ(ShelfAutoHideState::SHELF_AUTO_HIDE_HIDDEN, |
| GetShelfLayoutManager()->auto_hide_state()); |
| SwipeUpOnShelf(); |
| { |
| HotseatStateWatcher watcher(GetShelfLayoutManager()); |
| // Enter overview by using the controller. |
| EnterOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| |
| watcher.CheckEqual({}); |
| EXPECT_EQ(HotseatState::kExtended, |
| GetShelfLayoutManager()->hotseat_state()); |
| } |
| } |
| |
| // Tests that going between Applist and overview in tablet mode with no windows |
| // results in no work area change. |
| TEST_P(HotseatWidgetTest, |
| WorkAreaDoesNotUpdateAppListToFromOverviewWithNoWindow) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| DisplayWorkAreaChangeCounter counter; |
| |
| EnterOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| EXPECT_EQ(0, counter.count()); |
| |
| EnterOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| EXPECT_EQ(0, counter.count()); |
| } |
| |
| // Tests that switching between AppList and overview with a window results in no |
| // work area change. |
| TEST_P(HotseatWidgetTest, |
| WorkAreaDoesNotUpdateAppListToFromOverviewWithWindow) { |
| DisplayWorkAreaChangeCounter counter; |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| ASSERT_EQ(1, counter.count()); |
| ShowShelfAndGoHome(); |
| |
| StartOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| EXPECT_EQ(1, counter.count()); |
| |
| EndOverview(); |
| WaitForOverviewAnimation(/*enter=*/false); |
| EXPECT_EQ(1, counter.count()); |
| } |
| |
| // Tests that switching between AppList and an active window does not update the |
| // work area. |
| TEST_P(HotseatWidgetTest, WorkAreaDoesNotUpdateOpenWindowToFromAppList) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| ASSERT_TRUE(ShelfConfig::Get()->is_in_app()); |
| |
| // Go to the home launcher, work area should not update. |
| DisplayWorkAreaChangeCounter counter; |
| ShowShelfAndGoHome(); |
| |
| GetAppListTestHelper()->CheckVisibility(true); |
| EXPECT_EQ(0, counter.count()); |
| |
| // Go back to the window, work area should not update. |
| wm::ActivateWindow(window.get()); |
| |
| EXPECT_TRUE(ShelfConfig::Get()->is_in_app()); |
| EXPECT_EQ(0, counter.count()); |
| } |
| |
| // Tests that switching between overview and an active window does not update |
| // the work area. |
| TEST_P(HotseatWidgetTest, WorkAreaDoesNotUpdateOpenWindowToFromOverview) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| ASSERT_TRUE(ShelfConfig::Get()->is_in_app()); |
| |
| // Go to overview, there should not be a work area update. |
| DisplayWorkAreaChangeCounter counter; |
| StartOverview(); |
| WaitForOverviewAnimation(/*enter=*/true); |
| EXPECT_EQ(0, counter.count()); |
| |
| // Go back to the app, there should not be a work area update. |
| wm::ActivateWindow(window.get()); |
| |
| EXPECT_TRUE(ShelfConfig::Get()->is_in_app()); |
| EXPECT_EQ(0, counter.count()); |
| } |
| |
| // Tests that the shelf opaque background is properly updated after a tablet |
| // mode transition with no apps. |
| TEST_P(HotseatWidgetTest, ShelfBackgroundNotVisibleInTabletModeNoApps) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| EXPECT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible()); |
| } |
| |
| // Tests that the shelf opaque background is properly updated after a tablet |
| // mode transition with no apps with dense shelf. |
| TEST_P(HotseatWidgetTest, DenseShelfBackgroundNotVisibleInTabletModeNoApps) { |
| UpdateDisplay("300x1000"); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| EXPECT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible()); |
| } |
| |
| // Tests that the hotseat is extended if focused with a keyboard. |
| TEST_P(HotseatWidgetTest, ExtendHotseatIfFocusedWithKeyboard) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Focus the shelf. Hotseat should now show extended. |
| GetPrimaryShelf()->shelf_focus_cycler()->FocusShelf(false /* last_element */); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Focus the status area. Hotseat should now hide, as it was |
| // automatically extended by focusing it. |
| GetPrimaryShelf()->shelf_focus_cycler()->FocusStatusArea( |
| false /* last_element */); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Now swipe up to show the shelf and then focus it with the keyboard. Hotseat |
| // should keep extended. |
| SwipeUpOnShelf(); |
| GetPrimaryShelf()->shelf_focus_cycler()->FocusShelf(false /* last_element */); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Now focus the status area widget again. Hotseat should remain shown, as it |
| // was manually extended. |
| GetPrimaryShelf()->shelf_focus_cycler()->FocusStatusArea( |
| false /* last_element */); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that if the hotseat was hidden while being focused, doing a traversal |
| // focus on the next element brings it up again. |
| TEST_P(HotseatWidgetTest, SwipeDownOnFocusedHotseat) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| ShelfTestUtil::AddAppShortcut("app_id_1", TYPE_APP); |
| ShelfTestUtil::AddAppShortcut("app_id_2", TYPE_APP); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Focus the shelf, then swipe down on the shelf to hide it. Hotseat should be |
| // hidden. |
| GetPrimaryShelf()->shelf_focus_cycler()->FocusShelf(false /* last_element */); |
| gfx::Rect hotseat_bounds = |
| GetPrimaryShelf()->hotseat_widget()->GetWindowBoundsInScreen(); |
| gfx::Point start = hotseat_bounds.top_center(); |
| gfx::Point end = start + gfx::Vector2d(0, 80); |
| GetEventGenerator()->GestureScrollSequence( |
| start, end, base::Milliseconds(100), 4 /*scroll_steps*/); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Focus to the next element in the hotseat. The hotseat should show again. |
| PressAndReleaseKey(ui::VKEY_TAB); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that in overview, we can still exit by clicking on the hotseat if the |
| // point is not on the visible area. |
| TEST_P(HotseatWidgetTest, ExitOverviewWithClickOnHotseat) { |
| std::unique_ptr<aura::Window> window1 = AshTestBase::CreateTestWindow(); |
| ShelfTestUtil::AddAppShortcut("app_id_1", TYPE_APP); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| ASSERT_TRUE(TabletModeControllerTestApi().IsTabletModeStarted()); |
| ASSERT_FALSE(WindowState::Get(window1.get())->IsMinimized()); |
| |
| // Enter overview, hotseat is visible. Choose the point to the farthest left. |
| // This point will not be visible. |
| auto* overview_controller = OverviewController::Get(); |
| auto* hotseat_widget = GetPrimaryShelf()->hotseat_widget(); |
| EnterOverview(); |
| ASSERT_TRUE(overview_controller->InOverviewSession()); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| gfx::Point far_left_point = |
| hotseat_widget->GetWindowBoundsInScreen().left_center(); |
| |
| // Tests that on clicking, we exit overview and all windows are minimized. |
| GetEventGenerator()->set_current_screen_location(far_left_point); |
| GetEventGenerator()->ClickLeftButton(); |
| EXPECT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(WindowState::Get(window1.get())->IsMinimized()); |
| EXPECT_FALSE(overview_controller->InOverviewSession()); |
| } |
| |
| // Hides the hotseat if the hotseat is in kExtendedMode and the system tray |
| // is about to show (see https://crbug.com/1028321). |
| TEST_P(HotseatWidgetTest, DismissHotseatWhenSystemTrayShows) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| SwipeUpOnShelf(); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Activates the system tray when hotseat is in kExtended mode and waits for |
| // the update in system tray to finish. |
| StatusAreaWidget* status_area_widget = GetShelfWidget()->status_area_widget(); |
| const gfx::Point status_area_widget_center = |
| status_area_widget->GetNativeView()->GetBoundsInScreen().CenterPoint(); |
| GetEventGenerator()->GestureTapAt(status_area_widget_center); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Expects that the system tray shows and the hotseat is hidden. |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(status_area_widget->unified_system_tray()->IsBubbleShown()); |
| |
| // Early out since the remaining code is only meaningful for auto-hide shelf. |
| if (GetPrimaryShelf()->auto_hide_behavior() != |
| ShelfAutoHideBehavior::kAlways) { |
| return; |
| } |
| |
| // Auto-hide shelf should show when opening the system tray. |
| EXPECT_EQ(ShelfAutoHideState::SHELF_AUTO_HIDE_SHOWN, |
| GetShelfLayoutManager()->auto_hide_state()); |
| |
| // Auto-hide shelf should hide when closing the system tray. |
| GetEventGenerator()->GestureTapAt(status_area_widget_center); |
| |
| // Waits for the system tray to be closed. |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(ShelfAutoHideState::SHELF_AUTO_HIDE_HIDDEN, |
| GetShelfLayoutManager()->auto_hide_state()); |
| } |
| |
| // Tests that the hotseat hides when it is in kExtendedMode and a status area |
| // tray bubble is shown. |
| TEST_P(HotseatWidgetTest, DismissHotseatWhenStatusAreaTrayShows) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| StatusAreaWidget* status_area_widget = GetShelfWidget()->status_area_widget(); |
| status_area_widget->ime_menu_tray()->SetVisiblePreferred(true); |
| |
| // Show the hotseat. |
| SwipeUpOnShelf(); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_FALSE(status_area_widget->ime_menu_tray()->GetBubbleView()); |
| |
| // Show the ime menu tray bubble, and wait for the hotseat to be hidden. |
| GetEventGenerator()->GestureTapAt( |
| status_area_widget->ime_menu_tray()->GetBoundsInScreen().CenterPoint()); |
| base::RunLoop().RunUntilIdle(); |
| |
| // The hotseat should be hidden and the tray bubble should be shown. |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(status_area_widget->ime_menu_tray()->GetBubbleView()); |
| |
| // Swiping up on the shelf should hide the tray bubble and extend the hotseat. |
| SwipeUpOnShelf(); |
| EXPECT_FALSE(status_area_widget->ime_menu_tray()->GetBubbleView()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that the work area updates once each when going to/from tablet mode |
| // with no windows open. |
| TEST_P(HotseatWidgetTest, |
| DISABLED_WorkAreaUpdatesClamshellToFromHomeLauncherNoWindows) { |
| DisplayWorkAreaChangeCounter counter; |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| EXPECT_EQ(1, counter.count()); |
| |
| TabletModeControllerTestApi().LeaveTabletMode(); |
| |
| EXPECT_EQ(2, counter.count()); |
| } |
| |
| // Tests that the work area changes just once when opening a window in tablet |
| // mode. |
| TEST_P(HotseatWidgetTest, OpenWindowInTabletModeChangesWorkArea) { |
| DisplayWorkAreaChangeCounter counter; |
| TabletModeControllerTestApi().EnterTabletMode(); |
| ASSERT_EQ(1, counter.count()); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| EXPECT_EQ(1, counter.count()); |
| } |
| |
| // Tests that going to and from tablet mode with an open window results in a |
| // work area change. |
| TEST_P(HotseatWidgetTest, ToFromTabletModeWithWindowChangesWorkArea) { |
| DisplayWorkAreaChangeCounter counter; |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| EXPECT_EQ(1, counter.count()); |
| |
| TabletModeControllerTestApi().LeaveTabletMode(); |
| EXPECT_EQ(2, counter.count()); |
| } |
| |
| // Tests that the work area changes when fullscreening the active window or |
| // autohiding the shelf. |
| TEST_P(HotseatWidgetTest, ShelfVisibilityChangeChangesWorkArea) { |
| UpdateDisplay("800x603"); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| auto window = AshTestBase::CreateTestWindow(gfx::Rect(400, 400)); |
| |
| // The expected work area is 3 pixels smaller to leave space to swipe the auto |
| // hide shelf up. |
| const gfx::Rect expected_auto_hide_work_area(800, 600); |
| const gfx::Rect expected_in_app_work_area( |
| 800, 603 - ShelfConfig::Get()->in_app_shelf_size()); |
| auto get_work_area = []() -> gfx::Rect { |
| return WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow()) |
| ->user_work_area_bounds(); |
| }; |
| |
| DisplayWorkAreaChangeCounter counter; |
| WMEvent toggle_fullscreen(WM_EVENT_TOGGLE_FULLSCREEN); |
| WindowState::Get(window.get())->OnWMEvent(&toggle_fullscreen); |
| EXPECT_EQ(expected_auto_hide_work_area, get_work_area()); |
| EXPECT_EQ(1, counter.count()); |
| |
| WindowState::Get(window.get())->OnWMEvent(&toggle_fullscreen); |
| EXPECT_EQ(expected_in_app_work_area, get_work_area()); |
| EXPECT_EQ(2, counter.count()); |
| |
| GetPrimaryShelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways); |
| EXPECT_EQ(expected_auto_hide_work_area, get_work_area()); |
| EXPECT_EQ(3, counter.count()); |
| |
| GetPrimaryShelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever); |
| EXPECT_EQ(expected_in_app_work_area, get_work_area()); |
| EXPECT_EQ(4, counter.count()); |
| } |
| |
| // Tests that the hotseat is flush with the bottom of the screen when in |
| // clamshell mode and the shelf is oriented on the bottom. |
| TEST_P(HotseatWidgetTest, HotseatFlushWithScreenBottomInClamshell) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| const int display_height = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height(); |
| const int hotseat_bottom = GetPrimaryShelf() |
| ->shelf_widget() |
| ->hotseat_widget() |
| ->GetWindowBoundsInScreen() |
| .bottom(); |
| EXPECT_EQ(hotseat_bottom, display_height); |
| } |
| |
| // Tests that upward drag gesture from the shelf in tablet mode affects the |
| // active window presentation. |
| TEST_P(HotseatWidgetTest, DragActiveWindowInTabletMode) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // Swipe up to bring up the hotseat first. |
| SwipeUpOnShelf(); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Now swipe up again to start drag the active window. |
| ui::test::EventGenerator* generator = GetEventGenerator(); |
| const gfx::Rect bottom_shelf_bounds = |
| GetShelfWidget()->GetWindowBoundsInScreen(); |
| generator->MoveMouseTo(bottom_shelf_bounds.CenterPoint()); |
| generator->PressTouch(); |
| EXPECT_TRUE(window->layer()->transform().IsIdentity()); |
| |
| // Drag upward, test the window transform changes. |
| const gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| generator->MoveTouch(display_bounds.CenterPoint()); |
| const gfx::Transform upward_transform = window->layer()->transform(); |
| EXPECT_FALSE(upward_transform.IsIdentity()); |
| // Drag downwad, test the window tranfrom changes. |
| generator->MoveTouch(display_bounds.bottom_center()); |
| const gfx::Transform downward_transform = window->layer()->transform(); |
| EXPECT_NE(upward_transform, downward_transform); |
| |
| generator->ReleaseTouch(); |
| EXPECT_TRUE(window->layer()->transform().IsIdentity()); |
| } |
| |
| // Tests that when hotseat and drag-window-to-overview features are both |
| // enabled, hotseat is not extended after dragging a window to overview, and |
| // then activating the window. |
| TEST_P(HotseatWidgetTest, ExitingOverviewHidesHotseat) { |
| const ShelfAutoHideBehavior auto_hide_behavior = shelf_auto_hide_behavior(); |
| GetPrimaryShelf()->SetAutoHideBehavior(auto_hide_behavior); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // If the shelf is auto-hidden, swipe up to bring up shelf and hotseat first |
| // (otherwise, the window drag to overview will not be handled). |
| if (auto_hide_behavior == ShelfAutoHideBehavior::kAlways) { |
| SwipeUpOnShelf(); |
| ASSERT_EQ(HotseatState::kExtended, |
| GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Swipe up to start dragging the active window. |
| const gfx::Rect bottom_shelf_bounds = |
| GetShelfWidget()->GetWindowBoundsInScreen(); |
| StartScroll(bottom_shelf_bounds.CenterPoint()); |
| // Ensure swipe goes past the top of the hotseat first to activate the window |
| // drag controller. |
| UpdateScroll(gfx::Vector2d( |
| 0, -GetPrimaryShelf()->hotseat_widget()->GetHotseatFullDragAmount())); |
| // Drag upward, to the center of the screen, and release (this should enter |
| // the overview). |
| const gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| UpdateScroll(gfx::Vector2d(0, display_bounds.CenterPoint().y() - |
| bottom_shelf_bounds.CenterPoint().y())); |
| // Small scroll update, to simulate the user holding the pointer. |
| UpdateScroll(gfx::Vector2d(0, 2)); |
| DragWindowFromShelfController* window_drag_controller = |
| GetShelfLayoutManager()->window_drag_controller_for_testing(); |
| ASSERT_TRUE(window_drag_controller); |
| DragWindowFromShelfControllerTestApi test_api; |
| test_api.WaitUntilOverviewIsShown(window_drag_controller); |
| EndScroll(/*is_fling=*/false, 0.f); |
| |
| OverviewController* overview_controller = OverviewController::Get(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| |
| // Activate the window - the overview session should exit, and hotseat should |
| // be hidden. |
| wm::ActivateWindow(window.get()); |
| EXPECT_FALSE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that failing to drag the maximized window to overview mode results in |
| // an extended hotseat. |
| TEST_P(HotseatWidgetTest, FailingOverviewDragResultsInExtendedHotseat) { |
| const ShelfAutoHideBehavior auto_hide_behavior = shelf_auto_hide_behavior(); |
| GetPrimaryShelf()->SetAutoHideBehavior(auto_hide_behavior); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // If the shelf is auto-hidden, swipe up to bring up shelf and hotseat first |
| // (otherwise, the window drag to overview will not be handled). |
| if (auto_hide_behavior == ShelfAutoHideBehavior::kAlways) { |
| SwipeUpOnShelf(); |
| ASSERT_EQ(HotseatState::kExtended, |
| GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Swipe up to start dragging the active window. |
| const gfx::Rect bottom_shelf_bounds = |
| GetShelfWidget()->GetWindowBoundsInScreen(); |
| StartScroll(bottom_shelf_bounds.top_center()); |
| |
| const int extended_hotseat_distance_from_top_of_shelf = |
| ShelfConfig::Get()->hotseat_bottom_padding() + |
| GetPrimaryShelf()->hotseat_widget()->GetHotseatSize(); |
| // Overview is triggered when the bottom of the dragged window goes past the |
| // top of the hotseat. The window scaling and translation are handled slightly |
| // differently for if the hotseat is extended or not. |
| if (HotseatState::kExtended == GetShelfLayoutManager()->hotseat_state()) { |
| // Drag upward, a bit below the hotseat extended height, to ensure that the |
| // bottom of the dragged window doesn't go past the top of the hotseat, so |
| // that it doesn't go into overview. |
| UpdateScroll( |
| gfx::Vector2d(0, -extended_hotseat_distance_from_top_of_shelf + 20)); |
| } else { |
| // Drag upward, a bit past the hotseat extended height so that the window |
| // drag controller is activated, but not enough to go to overview. |
| UpdateScroll( |
| gfx::Vector2d(0, -extended_hotseat_distance_from_top_of_shelf - 30)); |
| } |
| EndScroll(/*is_fling=*/false, 0.f); |
| |
| ASSERT_FALSE(OverviewController::Get()->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that hotseat remains in extended state while in overview mode when |
| // flinging the shelf up or down. |
| TEST_P(HotseatWidgetTest, SwipeOnHotseatInOverview) { |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| OverviewController* overview_controller = OverviewController::Get(); |
| EnterOverview(); |
| |
| Shelf* const shelf = GetPrimaryShelf(); |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| |
| // Drag from the hotseat to the bezel, the hotseat should remain in extended |
| // state. |
| DragHotseatDownToBezel(); |
| |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| } |
| |
| TEST_P(HotseatWidgetTest, SwipeOnHotseatInSplitViewWithOverview) { |
| Shelf* const shelf = GetPrimaryShelf(); |
| shelf->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| OverviewController* overview_controller = OverviewController::Get(); |
| EnterOverview(); |
| |
| SplitViewController* split_view_controller = |
| SplitViewController::Get(Shell::GetPrimaryRootWindow()); |
| split_view_controller->SnapWindow( |
| window.get(), SplitViewController::SnapPosition::kPrimary); |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| |
| DragHotseatDownToBezel(); |
| |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| EXPECT_TRUE(overview_controller->InOverviewSession()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| } |
| |
| TEST_P(HotseatWidgetTest, SwipeOnHotseatInSplitView) { |
| Shelf* const shelf = GetPrimaryShelf(); |
| shelf->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| std::unique_ptr<aura::Window> window1 = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| std::unique_ptr<aura::Window> window2 = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window1.get()); |
| |
| SplitViewController* split_view_controller = |
| SplitViewController::Get(Shell::GetPrimaryRootWindow()); |
| split_view_controller->SnapWindow( |
| window1.get(), SplitViewController::SnapPosition::kPrimary); |
| split_view_controller->SnapWindow( |
| window2.get(), SplitViewController::SnapPosition::kSecondary); |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| |
| DragHotseatDownToBezel(); |
| |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| |
| SwipeUpOnShelf(); |
| |
| EXPECT_TRUE(split_view_controller->InSplitViewMode()); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| if (shelf_auto_hide_behavior() == ShelfAutoHideBehavior::kAlways) { |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); |
| } else { |
| EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState()); |
| } |
| } |
| |
| // Tests that swiping downward, towards the bezel, from a variety of points |
| // results in hiding the hotseat. |
| TEST_P(HotseatWidgetTest, HotseatHidesWhenSwipedToBezel) { |
| // Go to in-app shelf and extend the hotseat. |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| SwipeUpOnShelf(); |
| |
| // Drag from the hotseat to the bezel, the hotseat should hide. |
| DragHotseatDownToBezel(); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Reset the hotseat and swipe from the center of the hotseat, it should hide. |
| SwipeUpOnShelf(); |
| |
| gfx::Rect shelf_widget_bounds = GetShelfWidget()->GetWindowBoundsInScreen(); |
| gfx::Rect hotseat_bounds = |
| GetPrimaryShelf()->hotseat_widget()->GetWindowBoundsInScreen(); |
| gfx::Point start = hotseat_bounds.CenterPoint(); |
| const gfx::Point end = |
| gfx::Point(shelf_widget_bounds.x() + shelf_widget_bounds.width() / 2, |
| shelf_widget_bounds.bottom() + 1); |
| const base::TimeDelta kTimeDelta = base::Milliseconds(100); |
| const int kNumScrollSteps = 4; |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Reset the hotseat and swipe from the bottom of the hotseat, it should hide. |
| SwipeUpOnShelf(); |
| |
| start = hotseat_bounds.bottom_center(); |
| start.Offset(0, -1); |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Reset the hotseat and swipe from the center of the in-app shelf, it should |
| // hide. |
| SwipeUpOnShelf(); |
| |
| start = shelf_widget_bounds.CenterPoint(); |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Reset the hotseat and swipe from the bottom of the in-app shelf, it should |
| // hide. |
| SwipeUpOnShelf(); |
| |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| start = shelf_widget_bounds.bottom_center(); |
| // The first few events which get sent to ShelfLayoutManager are |
| // ui::ET_TAP_DOWN, and ui::ET_GESTURE_START. After a few px we get |
| // ui::ET_GESTURE_SCROLL_UPDATE. Add 6 px of slop to get the first events out |
| // of the way, and 1 extra px to ensure we are not on the bottom edge of the |
| // display. |
| start.Offset(0, -7); |
| |
| GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta, |
| kNumScrollSteps); |
| |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that flinging up the in-app shelf should show the hotseat. |
| TEST_P(HotseatWidgetTest, FlingUpHotseatWithShortFling) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 0); |
| |
| // Scrolls the hotseat by a distance not sufficuent to trigger the action of |
| // entering home screen from the in-app shelf. |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| const gfx::Point start(display_bounds.bottom_center()); |
| const gfx::Point end(start + gfx::Vector2d(0, -20)); |
| |
| const int fling_speed = |
| DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 1; |
| const int scroll_steps = 20; |
| base::TimeDelta scroll_time = |
| GetEventGenerator()->CalculateScrollDurationForFlingVelocity( |
| start, end, fling_speed, scroll_steps); |
| GetEventGenerator()->GestureScrollSequence(start, end, scroll_time, |
| scroll_steps); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| histogram_tester.ExpectBucketCount(kHotseatGestureHistogramName, |
| InAppShelfGestures::kSwipeUpToShow, 1); |
| } |
| |
| // Tests that flinging up the in-app shelf should show the home launcher if the |
| // gesture distance is long enough. |
| TEST_P(HotseatWidgetTest, FlingUpHotseatWithLongFling) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| GetAppListTestHelper()->CheckVisibility(false); |
| |
| base::HistogramTester histogram_tester; |
| histogram_tester.ExpectBucketCount( |
| kHotseatGestureHistogramName, |
| InAppShelfGestures::kFlingUpToShowHomeScreen, 0); |
| |
| // Scrolls the hotseat by the sufficient distance to trigger the action of |
| // entering home screen from the in-app shelf. |
| gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| const gfx::Point start(display_bounds.bottom_center()); |
| const gfx::Point end(start + gfx::Vector2d(0, -200)); |
| |
| const int fling_speed = |
| DragWindowFromShelfController::kVelocityToHomeScreenThreshold + 1; |
| const int scroll_steps = 20; |
| base::TimeDelta scroll_time = |
| GetEventGenerator()->CalculateScrollDurationForFlingVelocity( |
| start, end, fling_speed, scroll_steps); |
| GetEventGenerator()->GestureScrollSequence(start, end, scroll_time, |
| scroll_steps); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| GetAppListTestHelper()->CheckVisibility(true); |
| histogram_tester.ExpectBucketCount( |
| kHotseatGestureHistogramName, |
| InAppShelfGestures::kFlingUpToShowHomeScreen, 1); |
| } |
| |
| // Tests that UpdateVisibilityState is ignored during a shelf drag. This |
| // prevents drag from getting interrupted. |
| TEST_P(HotseatWidgetTest, NoVisibilityStateUpdateDuringDrag) { |
| // Autohide the shelf, then start a shelf drag. |
| GetPrimaryShelf()->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways); |
| std::unique_ptr<aura::Window> window1 = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window1.get()); |
| ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, GetPrimaryShelf()->GetAutoHideState()); |
| |
| // Drag the autohidden shelf up a bit, then open a new window and activate it |
| // during the drag. The shelf state should not change. |
| gfx::Point start_drag = GetVisibleShelfWidgetBoundsInScreen().top_center(); |
| GetEventGenerator()->set_current_screen_location(start_drag); |
| GetEventGenerator()->PressTouch(); |
| GetEventGenerator()->MoveTouchBy(0, -2); |
| auto shelf_state_watcher = std::make_unique<ShelfStateWatcher>(); |
| std::unique_ptr<aura::Window> window2 = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| |
| wm::ActivateWindow(window2.get()); |
| window2->SetBounds(gfx::Rect(0, 0, 200, 200)); |
| |
| EXPECT_EQ(0, shelf_state_watcher->state_change_count()); |
| } |
| |
| // Tests that when tablet mode has ended, the hotseat background is no longer |
| // visible. See crbug/1050383 |
| TEST_P(HotseatWidgetTest, HotseatBackgroundDisappearsAfterTabletModeEnd) { |
| HotseatWidget* hotseat = GetPrimaryShelf()->hotseat_widget(); |
| EXPECT_FALSE(hotseat->GetIsTranslucentBackgroundVisibleForTest()); |
| |
| TabletModeControllerTestApi().EnterTabletMode(); |
| EXPECT_TRUE(hotseat->GetIsTranslucentBackgroundVisibleForTest()); |
| |
| TabletModeControllerTestApi().LeaveTabletMode(); |
| EXPECT_FALSE(hotseat->GetIsTranslucentBackgroundVisibleForTest()); |
| } |
| |
| // Tests that popups don't activate the hotseat. (crbug.com/1018266) |
| TEST_P(HotseatWidgetTest, HotseatRemainsHiddenIfPopupLaunched) { |
| // Go to in-app shelf and extend the hotseat. |
| TabletModeControllerTestApi().EnterTabletMode(); |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| SwipeUpOnShelf(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Hide hotseat by clicking outside its bounds. |
| gfx::Rect hotseat_bounds = |
| GetPrimaryShelf()->hotseat_widget()->GetWindowBoundsInScreen(); |
| gfx::Point start = hotseat_bounds.top_center(); |
| GetEventGenerator()->GestureTapAt(gfx::Point(start.x() + 1, start.y() - 1)); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Create a popup window and wait until all actions finish. The hotseat should |
| // remain hidden. |
| aura::Window* window_2 = CreateTestWindowInParent(window.get()); |
| window_2->SetBounds(gfx::Rect(201, 0, 100, 100)); |
| window_2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| window_2->Show(); |
| GetAppListTestHelper()->WaitUntilIdle(); |
| EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| // Tests that blur is not showing during animations. |
| TEST_P(HotseatWidgetTest, NoBlurDuringAnimations) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| ASSERT_EQ( |
| ShelfConfig::Get()->shelf_blur_radius(), |
| GetShelfWidget()->hotseat_widget()->GetHotseatBackgroundBlurForTest()); |
| ui::ScopedAnimationDurationScaleMode regular_animations( |
| ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); |
| |
| // Open a window, as the hotseat animates to kHidden, it should lose its blur. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| EXPECT_EQ( |
| 0, GetShelfWidget()->hotseat_widget()->GetHotseatBackgroundBlurForTest()); |
| |
| // Wait for the animation to finish, hotseat blur should return. |
| ShellTestApi().WaitForWindowFinishAnimating(window.get()); |
| EXPECT_EQ( |
| ShelfConfig::Get()->shelf_blur_radius(), |
| GetShelfWidget()->hotseat_widget()->GetHotseatBackgroundBlurForTest()); |
| } |
| |
| // Tests that hotseat bounds don't jump when transitioning from drag to |
| // animation. |
| TEST_P(HotseatWidgetTest, AnimationAfterDrag) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| // Add an app to shelf - the app will be used to track the shelf view position |
| // throughout the test. |
| ShelfTestUtil::AddAppShortcut("fake_app", TYPE_PINNED_APP); |
| |
| // Open a window so the hotseat transitions to hidden state. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| ui::ScopedAnimationDurationScaleMode animation_duration( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| |
| HotseatWidget* const hotseat_widget = GetPrimaryShelf()->hotseat_widget(); |
| gfx::Point last_app_views_position = |
| hotseat_widget->GetWindowBoundsInScreen().origin(); |
| |
| // Returns whether the hotseat vertical position has changed comapred to |
| // |last_hotseat_y|, and updates |last_hotseat_y| to match the current hotseat |
| // position. |
| auto app_views_moved = [&last_app_views_position, &hotseat_widget]() -> bool { |
| gfx::Point app_views_position = |
| ShelfViewTestAPI(hotseat_widget->scrollable_shelf_view()->shelf_view()) |
| .GetViewAt(0) |
| ->GetBoundsInScreen() |
| .origin(); |
| app_views_position = |
| hotseat_widget->GetLayer()->transform().MapPoint(app_views_position); |
| const bool position_changed = app_views_position != last_app_views_position; |
| last_app_views_position = app_views_position; |
| return position_changed; |
| }; |
| |
| ui::test::EventGenerator* generator = GetEventGenerator(); |
| const gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| // Drag upwards from the bottom of the screen to bring up hotseat - this |
| // should request presentation time metric to be reported. |
| generator->PressTouch(display_bounds.bottom_center()); |
| |
| // Drag the hotseat upward, by the height of the shelf. |
| const int shelf_height = GetShelfWidget()->GetWindowBoundsInScreen().height(); |
| |
| generator->MoveTouchBy(0, -shelf_height); |
| ASSERT_TRUE(app_views_moved()); |
| |
| // Release touch, and verify the hotseat position remained the same. |
| generator->ReleaseTouch(); |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Wait for the hotseat to animate to extended state. |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(app_views_moved()); |
| |
| // Drag hotseat down. |
| generator->PressTouch(hotseat_widget->GetWindowBoundsInScreen().top_center()); |
| generator->MoveTouchBy(0, shelf_height); |
| ASSERT_TRUE(app_views_moved()); |
| |
| // Release touch, and verify the hotseat position remained the same. |
| generator->ReleaseTouch(); |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Wait for the hotseat to animate to extended state. |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| ASSERT_TRUE(app_views_moved()); |
| |
| // Drag the hotseat back up, and release so animation to extended state |
| // starts. |
| generator->PressTouch(display_bounds.bottom_center()); |
| generator->MoveTouchBy(0, -shelf_height); |
| ASSERT_TRUE(app_views_moved()); |
| generator->ReleaseTouch(); |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Close the test widget to start transition to the shown state. |
| window.reset(); |
| |
| // The apparent hotseat bound should remain the same as the transition to show |
| // state starts. |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Finish the animation to shown state. |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(app_views_moved()); |
| } |
| |
| // Tests that hotseat bounds don't jump when the hotseat widget is translated |
| // when a transitionj animation starts. |
| TEST_P(HotseatWidgetTest, InitialAnimationPositionWithNonIdentityTransform) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| // Add an app to shelf - the app will be used to track the shelf view position |
| // throughout the test. |
| ShelfTestUtil::AddAppShortcut("fake_app", TYPE_PINNED_APP); |
| |
| // Open a window so the hotseat transitions to hidden state. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // Make sure that all shelf item views complete their bounds animations |
| // before starting the test (tests depend on the first item bounds within the |
| // shelf view). |
| auto* shelf_view = GetPrimaryShelf()->GetShelfViewForTesting(); |
| ShelfViewTestAPI(shelf_view).RunMessageLoopUntilAnimationsDone(); |
| |
| HotseatWidget* const hotseat_widget = GetPrimaryShelf()->hotseat_widget(); |
| gfx::Point last_app_views_position = |
| hotseat_widget->GetWindowBoundsInScreen().origin(); |
| |
| // Returns whether the hotseat vertical position has changed comapred to |
| // |last_hotseat_y|, and updates |last_hotseat_y| to match the current hotseat |
| // position. |
| auto app_views_moved = [&last_app_views_position, &hotseat_widget]() -> bool { |
| gfx::Point app_views_position = |
| ShelfViewTestAPI(hotseat_widget->scrollable_shelf_view()->shelf_view()) |
| .GetViewAt(0) |
| ->GetBoundsInScreen() |
| .origin(); |
| app_views_position = |
| hotseat_widget->GetLayer()->transform().MapPoint(app_views_position); |
| const bool position_changed = app_views_position != last_app_views_position; |
| last_app_views_position = app_views_position; |
| return position_changed; |
| }; |
| |
| ui::test::EventGenerator* generator = GetEventGenerator(); |
| const gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| // Drag upwards from the bottom of the screen to bring up hotseat - this |
| // should request presentation time metric to be reported. |
| generator->PressTouch(display_bounds.bottom_center()); |
| |
| // Drag the hotseat upward, to transition hotseat to the extended state. |
| const int shelf_height = GetShelfWidget()->GetWindowBoundsInScreen().height(); |
| generator->MoveTouchBy(0, -shelf_height); |
| // Release touch, and verify the hotseat position remained the same. |
| generator->ReleaseTouch(); |
| ASSERT_TRUE(app_views_moved()); |
| |
| ui::ScopedAnimationDurationScaleMode animation_duration( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| auto set_animated_transform = [](ui::Layer* layer, |
| const gfx::Vector2d& initial_offset) { |
| // Set translate animation on the hotseat widget, to simulate a state which |
| // the widget may have while a transform animation is in progress. |
| gfx::Transform initial_transform; |
| initial_transform.Translate(initial_offset.x(), initial_offset.y()); |
| layer->SetTransform(initial_transform); |
| |
| // Set up an animation to identity transform. |
| ui::ScopedLayerAnimationSettings animation(layer->GetAnimator()); |
| animation.SetTransitionDuration(base::Milliseconds(300)); |
| layer->SetTransform(gfx::Transform()); |
| }; |
| |
| set_animated_transform(hotseat_widget->GetLayer(), gfx::Vector2d(0, -10)); |
| ASSERT_TRUE(app_views_moved()); |
| |
| // Tap in the middle of the screen to initiate transition to hidden state. |
| generator->GestureTapAt(display_bounds.CenterPoint()); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Verify the current hotseat position remains unchanged. |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Wait for the hotseat animation to hidden state to finish. |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| ASSERT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state()); |
| EXPECT_TRUE(app_views_moved()); |
| |
| // Set the hotseat widget transform again. |
| set_animated_transform(hotseat_widget->GetLayer(), gfx::Vector2d(0, -10)); |
| ASSERT_TRUE(app_views_moved()); |
| |
| // CLose the window to transition to the shown state. |
| window.reset(); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| |
| // The apparent hotseat bound should remain the same as the transition to show |
| // state starts. |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Finish the animation to shown state. |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| EXPECT_TRUE(app_views_moved()); |
| |
| // Open another widow, and move the hotseat to extended state. |
| window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| generator->PressTouch(display_bounds.bottom_center()); |
| generator->MoveTouchBy(0, -shelf_height); |
| generator->ReleaseTouch(); |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| ASSERT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| set_animated_transform(hotseat_widget->GetLayer(), gfx::Vector2d(0, -10)); |
| ASSERT_TRUE(app_views_moved()); |
| |
| // Close the window to transition to shown hotseat state. |
| window.reset(); |
| ASSERT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| |
| // The apparent hotseat bound should remain the same as the transition to show |
| // state starts. |
| EXPECT_FALSE(app_views_moved()); |
| |
| // Finish the animation to shown state. |
| ShellTestApi().WaitForWindowFinishAnimating( |
| hotseat_widget->GetNativeWindow()); |
| EXPECT_TRUE(app_views_moved()); |
| } |
| |
| TEST_P(HotseatWidgetTest, PresentationTimeMetricDuringDrag) { |
| ui::PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest( |
| true); |
| |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| GetPrimaryShelf()->SetAutoHideBehavior(shelf_auto_hide_behavior()); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| |
| ui::test::EventGenerator* generator = GetEventGenerator(); |
| const gfx::Rect display_bounds = |
| display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); |
| // Drag upwards from the bottom of the screen to bring up hotseat - this |
| // should request presentation time metric to be reported. |
| generator->PressTouch(display_bounds.bottom_center()); |
| |
| HotseatWidget* const hotseat_widget = GetPrimaryShelf()->hotseat_widget(); |
| int last_hotseat_y = hotseat_widget->GetWindowBoundsInScreen().y(); |
| |
| // Returns whether the hotseat vertical position has changed comapred to |
| // |last_hotseat_y|, and updates |last_hotseat_y| to match the current hotseat |
| // position. |
| auto hotseat_moved = [&last_hotseat_y, &hotseat_widget]() -> bool { |
| const int hotseat_y = hotseat_widget->GetWindowBoundsInScreen().y(); |
| const bool y_changed = hotseat_y != last_hotseat_y; |
| last_hotseat_y = hotseat_y; |
| return y_changed; |
| }; |
| |
| base::HistogramTester histogram_tester; |
| |
| auto check_bucket_size = [&histogram_tester](int expected_size) { |
| histogram_tester.ExpectTotalCount( |
| "Ash.HotseatTransition.Drag.PresentationTime", expected_size); |
| histogram_tester.ExpectTotalCount( |
| "Ash.HotseatTransition.Drag.PresentationTime.MaxLatency", 0); |
| }; |
| |
| int expected_bucket_size = 0; |
| { |
| SCOPED_TRACE("Initial state"); |
| check_bucket_size(expected_bucket_size); |
| } |
| |
| const int shelf_height = GetShelfWidget()->GetWindowBoundsInScreen().height(); |
| |
| { |
| SCOPED_TRACE("Upward drag with move - 1"); |
| generator->MoveTouchBy(0, -shelf_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Upward drag with move - 2"); |
| generator->MoveTouchBy(0, -shelf_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Downward drag with move"); |
| generator->MoveTouchBy(0, shelf_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Upward drag with move - 3"); |
| generator->MoveTouchBy(0, -shelf_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| const int hotseat_height = |
| GetPrimaryShelf()->hotseat_widget()->GetWindowBoundsInScreen().height(); |
| { |
| SCOPED_TRACE("Upward drag with move above shelf - 1"); |
| generator->MoveTouchBy(0, -hotseat_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Upward drag with move above shelf - 2"); |
| generator->MoveTouchBy(0, -hotseat_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Downward drag with move above shelf"); |
| generator->MoveTouchBy(0, hotseat_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Upward drag with move above shelf - 3"); |
| generator->MoveTouchBy(0, -hotseat_height - hotseat_height / 2); |
| ASSERT_TRUE(hotseat_moved()); |
| check_bucket_size(++expected_bucket_size); |
| } |
| |
| // Once the hotseat has been fully extended, presentation time metric should |
| // stop being reported, as the hotseat is expected to stop moving. |
| { |
| SCOPED_TRACE("Upward drag without moving - 1"); |
| generator->MoveTouchBy(0, -hotseat_height); |
| ASSERT_FALSE(hotseat_moved()); |
| check_bucket_size(expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Upward drag without moving - 2"); |
| generator->MoveTouchBy(0, -hotseat_height / 2); |
| ASSERT_FALSE(hotseat_moved()); |
| check_bucket_size(expected_bucket_size); |
| } |
| |
| // Move hotseat downwards - the presentation time should not get reported |
| // until the hotseat starts moving downwards. |
| { |
| SCOPED_TRACE("Downward drag without moving - 1"); |
| generator->MoveTouchBy(0, hotseat_height / 2); |
| ASSERT_FALSE(hotseat_moved()); |
| check_bucket_size(expected_bucket_size); |
| } |
| |
| { |
| SCOPED_TRACE("Downward drag without moving - 2"); |
| generator->MoveTouchBy(0, hotseat_height); |
| ASSERT_FALSE(hotseat_moved()); |
| check_bucket_size(expected_bucket_size); |
| } |
| |
| generator->ReleaseTouch(); |
| |
| window.reset(); |
| |
| { |
| SCOPED_TRACE("Drag ended."); |
| histogram_tester.ExpectTotalCount( |
| "Ash.HotseatTransition.Drag.PresentationTime", expected_bucket_size); |
| histogram_tester.ExpectTotalCount( |
| "Ash.HotseatTransition.Drag.PresentationTime.MaxLatency", 1); |
| } |
| } |
| |
| // TODO(manucornet): Enable this test once the new API for layer animation |
| // sequence observers is available. |
| TEST_P(HotseatWidgetTest, DISABLED_OverviewToHomeAnimationAndBackIsSmooth) { |
| // Go into tablet mode and make sure animations are over. |
| HotseatWidget* hotseat = GetPrimaryShelf()->hotseat_widget(); |
| { |
| views::WidgetAnimationWaiter waiter(hotseat); |
| TabletModeControllerTestApi().EnterTabletMode(); |
| waiter.WaitForAnimation(); |
| } |
| |
| ui::ScopedAnimationDurationScaleMode regular_animations( |
| ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); |
| |
| // Go into overview and back to know what to expect in terms of bounds. |
| const gfx::Rect shown_hotseat_bounds = hotseat->GetWindowBoundsInScreen(); |
| { |
| views::WidgetAnimationWaiter waiter(hotseat); |
| StartOverview(); |
| waiter.WaitForAnimation(); |
| } |
| |
| const gfx::Rect extended_hotseat_bounds = hotseat->GetWindowBoundsInScreen(); |
| { |
| views::WidgetAnimationWaiter waiter(hotseat); |
| EndOverview(); |
| waiter.WaitForAnimation(); |
| } |
| |
| // The extended hotseat should be higher (lower value of Y) than the |
| // shown hotseat. |
| EXPECT_GT(shown_hotseat_bounds.y(), extended_hotseat_bounds.y()); |
| |
| // We should start with the hotseat in its shown position again. |
| EXPECT_EQ(shown_hotseat_bounds, hotseat->GetWindowBoundsInScreen()); |
| |
| { |
| WidgetAnimationSmoothnessInspector inspector(hotseat); |
| views::WidgetAnimationWaiter waiter(hotseat); |
| StartOverview(); |
| waiter.WaitForAnimation(); |
| EXPECT_TRUE(inspector.CheckAnimation(4)); |
| } |
| |
| // The hotseat should now be extended. |
| EXPECT_EQ(extended_hotseat_bounds, hotseat->GetWindowBoundsInScreen()); |
| |
| { |
| WidgetAnimationSmoothnessInspector inspector(hotseat); |
| views::WidgetAnimationWaiter waiter(hotseat); |
| EndOverview(); |
| waiter.WaitForAnimation(); |
| EXPECT_TRUE(inspector.CheckAnimation(4)); |
| } |
| |
| // And we should now be back where we started. |
| EXPECT_EQ(shown_hotseat_bounds, hotseat->GetWindowBoundsInScreen()); |
| } |
| |
| class HotseatWidgetRTLTest : public ShelfLayoutManagerTestBase, |
| public testing::WithParamInterface<bool> { |
| public: |
| // Use MOCK_TIME to increase number of commits during animation. |
| HotseatWidgetRTLTest() |
| : ShelfLayoutManagerTestBase( |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME), |
| scoped_locale_(GetParam() ? "ar" : "") {} |
| HotseatWidgetRTLTest(const HotseatWidgetRTLTest&) = delete; |
| HotseatWidgetRTLTest& operator=(const HotseatWidgetRTLTest&) = delete; |
| ~HotseatWidgetRTLTest() override = default; |
| |
| private: |
| base::test::ScopedRestoreICUDefaultLocale scoped_locale_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(RTL, HotseatWidgetRTLTest, testing::Bool()); |
| |
| // The test to verify the hotseat transition animation from the extended state |
| // to the home launcher state. |
| // TODO(https://crbug.com/1210530): Disable this test due to flakiness. |
| TEST_P(HotseatWidgetRTLTest, |
| DISABLED_VerifyTransitionFromExtendedModeToHomeLauncher) { |
| TabletModeControllerTestApi().EnterTabletMode(); |
| const auto app_id = |
| ShelfTestUtil::AddAppShortcut("fake_app", TYPE_PINNED_APP); |
| |
| // Open a window so the hotseat transitions to hidden state. |
| std::unique_ptr<aura::Window> window = |
| AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400)); |
| wm::ActivateWindow(window.get()); |
| |
| // Swipe the hotseat up to enter the extended mode. |
| SwipeUpOnShelf(); |
| EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state()); |
| |
| // Animation should be long enough in order to collect sufficient data. |
| // TODO(https://crbug.com/1208651): remove this line when we solve that issue. |
| ui::ScopedAnimationDurationScaleMode animation_duration( |
| ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION); |
| |
| // Wait until shelf animation completes. |
| auto* shelf_view = GetPrimaryShelf()->GetShelfViewForTesting(); |
| ShelfViewTestAPI shelf_test_api(shelf_view); |
| shelf_test_api.RunMessageLoopUntilAnimationsDone(); |
| |
| // Observe a shelf icon. |
| auto* observed_view = shelf_view->GetShelfAppButton(app_id.id); |
| LayerAnimationVerifier verifier( |
| GetPrimaryShelf()->hotseat_widget()->GetNativeView()->layer(), |
| observed_view); |
| |
| // Transit the hotseat from the extended state to the home launcher state. |
| // Wait until the transition animation finishes. |
| views::WidgetAnimationWaiter waiter(GetPrimaryShelf()->hotseat_widget()); |
| FlingUpOnShelf(); |
| waiter.WaitForAnimation(); |
| |
| // Verify the hotseat state at the end of the animation. |
| EXPECT_EQ(HotseatState::kShownHomeLauncher, |
| GetShelfLayoutManager()->hotseat_state()); |
| } |
| |
| } // namespace ash |