| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/capture_mode/capture_button_view.h" |
| #include "ash/capture_mode/capture_label_view.h" |
| #include "ash/capture_mode/capture_mode_bar_view.h" |
| #include "ash/capture_mode/capture_mode_controller.h" |
| #include "ash/capture_mode/capture_mode_metrics.h" |
| #include "ash/capture_mode/capture_mode_session_test_api.h" |
| #include "ash/capture_mode/capture_mode_test_util.h" |
| #include "ash/capture_mode/capture_mode_types.h" |
| #include "ash/capture_mode/recording_type_menu_view.h" |
| #include "ash/capture_mode/test_capture_mode_delegate.h" |
| #include "ash/public/cpp/capture_mode/capture_mode_test_api.h" |
| #include "ash/shell.h" |
| #include "ash/style/icon_button.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/test/ash_test_util.h" |
| #include "base/test/gtest_tags.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "ui/events/keycodes/keyboard_codes_posix.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/vector2d.h" |
| #include "ui/views/controls/button/image_button.h" |
| #include "ui/views/controls/button/label_button.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| |
| class GifRecordingTest : public AshTestBase { |
| public: |
| GifRecordingTest() = default; |
| GifRecordingTest(const GifRecordingTest&) = delete; |
| GifRecordingTest& operator=(const GifRecordingTest&) = delete; |
| ~GifRecordingTest() override = default; |
| |
| // AshTestBase: |
| void SetUp() override { |
| AshTestBase::SetUp(); |
| CaptureModeController::Get()->SetUserCaptureRegion(gfx::Rect(200, 200), |
| /*by_user=*/true); |
| } |
| |
| CaptureModeController* StartRegionVideoCapture() { |
| return StartCaptureSession(CaptureModeSource::kRegion, |
| CaptureModeType::kVideo); |
| } |
| |
| CaptureLabelView* GetCaptureLabelView() { |
| return CaptureModeSessionTestApi().GetCaptureLabelView(); |
| } |
| |
| RecordingTypeMenuView* GetRecordingTypeMenuView() { |
| return CaptureModeSessionTestApi().GetRecordingTypeMenuView(); |
| } |
| |
| views::LabelButton* GetCaptureButton() { |
| auto* label_view = GetCaptureLabelView(); |
| return label_view->capture_button_container()->capture_button(); |
| } |
| |
| views::ImageButton* GetRecordingTypeDropDownButton() { |
| auto* label_view = GetCaptureLabelView(); |
| EXPECT_TRUE(label_view->IsRecordingTypeDropDownButtonVisible()); |
| return label_view->capture_button_container()->drop_down_button(); |
| } |
| |
| views::Widget* GetRecordingTypeMenuWidget() { |
| return CaptureModeSessionTestApi().GetRecordingTypeMenuWidget(); |
| } |
| |
| views::Widget* GetSettingsMenuWidget() { |
| return CaptureModeSessionTestApi().GetCaptureModeSettingsWidget(); |
| } |
| |
| void ClickOnDropDownButton() { |
| LeftClickOn(GetRecordingTypeDropDownButton()); |
| } |
| |
| void ClickOnSettingsButton() { |
| CaptureModeBarView* bar_view = |
| CaptureModeSessionTestApi().GetCaptureModeBarView(); |
| LeftClickOn(bar_view->settings_button()); |
| } |
| |
| protected: |
| base::HistogramTester histogram_tester_; |
| }; |
| |
| TEST_F(GifRecordingTest, DropDownButtonVisibility) { |
| // With region video recording, the drop down button should be visible. |
| auto* controller = StartRegionVideoCapture(); |
| auto* label_view = GetCaptureLabelView(); |
| EXPECT_TRUE(label_view->IsRecordingTypeDropDownButtonVisible()); |
| |
| // It should hide, once we switch to image recording, but the label view |
| // should remain interactable. |
| controller->SetType(CaptureModeType::kImage); |
| EXPECT_FALSE(label_view->IsRecordingTypeDropDownButtonVisible()); |
| EXPECT_TRUE(label_view->IsViewInteractable()); |
| |
| // Switching to a fullscreen source, the label view becomes no longer |
| // interactable, and the drop down button remains hidden. |
| controller->SetSource(CaptureModeSource::kFullscreen); |
| EXPECT_FALSE(label_view->IsRecordingTypeDropDownButtonVisible()); |
| EXPECT_FALSE(label_view->IsViewInteractable()); |
| |
| // Even when we switch back to video recording. |
| controller->SetType(CaptureModeType::kVideo); |
| EXPECT_FALSE(label_view->IsRecordingTypeDropDownButtonVisible()); |
| EXPECT_FALSE(label_view->IsViewInteractable()); |
| |
| // Only region recording in video mode, that the label view is interactable, |
| // and the button is visible. |
| controller->SetSource(CaptureModeSource::kRegion); |
| EXPECT_TRUE(label_view->IsRecordingTypeDropDownButtonVisible()); |
| EXPECT_TRUE(label_view->IsViewInteractable()); |
| } |
| |
| TEST_F(GifRecordingTest, RecordingTypeMenuCreation) { |
| // The drop down button acts as a toggle. |
| StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| ClickOnDropDownButton(); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| |
| // The settings menu and the recording type menu are mutually exclusive, |
| // opening one closes the other. |
| ClickOnSettingsButton(); |
| EXPECT_TRUE(GetSettingsMenuWidget()); |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| EXPECT_FALSE(GetSettingsMenuWidget()); |
| ClickOnSettingsButton(); |
| EXPECT_TRUE(GetSettingsMenuWidget()); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| } |
| |
| TEST_F(GifRecordingTest, EscKeyClosesMenu) { |
| // Hitting the ESC key closes the recording type menu, but the session remains |
| // active. |
| auto* controller = StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| PressAndReleaseKey(ui::VKEY_ESCAPE); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_TRUE(controller->IsActive()); |
| } |
| |
| TEST_F(GifRecordingTest, EnterKeyHidesMenuAndStartsCountDown) { |
| StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| auto* recording_type_menu = GetRecordingTypeMenuWidget(); |
| EXPECT_TRUE(recording_type_menu); |
| |
| // Pressing the ENTER key starts the recording count down, at which point, the |
| // menu remains open but fades out to an opacity of 0. |
| PressAndReleaseKey(ui::VKEY_RETURN); |
| EXPECT_TRUE(CaptureModeTestApi().IsInCountDownAnimation()); |
| ASSERT_EQ(recording_type_menu, GetRecordingTypeMenuWidget()); |
| EXPECT_FLOAT_EQ(recording_type_menu->GetLayer()->GetTargetOpacity(), 0); |
| } |
| |
| TEST_F(GifRecordingTest, ClickingOutsideClosesMenu) { |
| auto* controller = StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| |
| // Clicking outside the menu widget should close it, but the region should not |
| // change. |
| const auto region = controller->user_capture_region(); |
| auto* generator = GetEventGenerator(); |
| generator->MoveMouseTo(region.bottom_right() + gfx::Vector2d(10, 10)); |
| generator->ClickLeftButton(); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(region, controller->user_capture_region()); |
| } |
| |
| TEST_F(GifRecordingTest, ChangingTypeFromMenu) { |
| auto* controller = StartRegionVideoCapture(); |
| EXPECT_EQ(RecordingType::kWebM, controller->recording_type()); |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| |
| // The WebM option should be selected and marked with a check. Once the GIF |
| // option is clicked, the menu should close, and the recording type in the |
| // controller is updated. |
| auto* recording_type_menu_view = GetRecordingTypeMenuView(); |
| EXPECT_TRUE( |
| recording_type_menu_view->IsOptionChecked(ToInt(RecordingType::kWebM))); |
| LeftClickOn(recording_type_menu_view->GetGifOptionForTesting()); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(RecordingType::kGif, controller->recording_type()); |
| } |
| |
| TEST_F(GifRecordingTest, MenuIsClosedWhenClickingCheckedOption) { |
| auto* controller = StartRegionVideoCapture(); |
| EXPECT_EQ(RecordingType::kWebM, controller->recording_type()); |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| |
| // Clicking on the same checked option closes the menu even though there is no |
| // change. |
| auto* recording_type_menu_view = GetRecordingTypeMenuView(); |
| LeftClickOn(recording_type_menu_view->GetWebMOptionForTesting()); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(RecordingType::kWebM, controller->recording_type()); |
| } |
| |
| TEST_F(GifRecordingTest, CaptureButtonStateUpdatedFromMenuSelection) { |
| // Select GIF from the menu, the capture button label should be updated. |
| StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| LeftClickOn(GetRecordingTypeMenuView()->GetGifOptionForTesting()); |
| auto* capture_button = GetCaptureButton(); |
| EXPECT_EQ(capture_button->GetText(), u"Record GIF"); |
| |
| // Select WebM from the menu, and expect the button label to be updated too. |
| ClickOnDropDownButton(); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| LeftClickOn(GetRecordingTypeMenuView()->GetWebMOptionForTesting()); |
| EXPECT_EQ(capture_button->GetText(), u"Record video"); |
| } |
| |
| // When the recording type is set programmatically, the capture button should |
| // still get updated. |
| TEST_F(GifRecordingTest, CaptureButtonStateUpdatedFromController) { |
| auto* controller = StartRegionVideoCapture(); |
| controller->SetRecordingType(RecordingType::kGif); |
| auto* capture_button = GetCaptureButton(); |
| EXPECT_EQ(capture_button->GetText(), u"Record GIF"); |
| |
| controller->SetRecordingType(RecordingType::kWebM); |
| EXPECT_EQ(capture_button->GetText(), u"Record video"); |
| } |
| |
| // Recording type selection affects future capture sessions. |
| TEST_F(GifRecordingTest, FutureCaptureSessionsAffected) { |
| auto* controller = StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| LeftClickOn(GetRecordingTypeMenuView()->GetGifOptionForTesting()); |
| |
| // Press the ESC key to exit the current session. |
| PressAndReleaseKey(ui::VKEY_ESCAPE); |
| EXPECT_FALSE(controller->IsActive()); |
| |
| // Start a new session, and expect that the capture button should be labeled |
| // correctly. |
| StartRegionVideoCapture(); |
| EXPECT_EQ(GetCaptureButton()->GetText(), u"Record GIF"); |
| |
| // When the menu is open, the correct option is marked as checked. |
| ClickOnDropDownButton(); |
| EXPECT_TRUE( |
| GetRecordingTypeMenuView()->IsOptionChecked(ToInt(RecordingType::kGif))); |
| } |
| |
| TEST_F(GifRecordingTest, TabNavigation) { |
| base::AddFeatureIdTagToTestResult( |
| "screenplay-759f3130-3839-408a-8342-a373654e8927"); |
| |
| auto* controller = StartRegionVideoCapture(); |
| |
| // Tab 15 times until we reach the capture button. |
| auto* event_generator = GetEventGenerator(); |
| SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/15); |
| using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup; |
| CaptureModeSessionTestApi test_api(controller->capture_mode_session()); |
| EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(0u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(GetCaptureButton(), test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Tab one more time to get to the drop down button. |
| SendKey(ui::VKEY_TAB, event_generator); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(GetRecordingTypeDropDownButton(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Pressing the spacebar should open the menu, and we should be in the |
| // `kPendingRecordingType` focus group. |
| SendKey(ui::VKEY_SPACE, event_generator); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(FocusGroup::kPendingRecordingType, test_api.GetCurrentFocusGroup()); |
| |
| // The next tab will move the focus inside the menu. |
| SendKey(ui::VKEY_TAB, event_generator); |
| EXPECT_EQ(FocusGroup::kRecordingTypeMenu, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(0u, test_api.GetCurrentFocusIndex()); |
| // And the WebM option will be focused. |
| auto* recording_type_menu_view = GetRecordingTypeMenuView(); |
| EXPECT_EQ(recording_type_menu_view->GetWebMOptionForTesting(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Tabbing again will focus on the GIF option. |
| SendKey(ui::VKEY_TAB, event_generator); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(recording_type_menu_view->GetGifOptionForTesting(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // The next tab will focus on the settings button, but the recording type menu |
| // stays open. |
| SendKey(ui::VKEY_TAB, event_generator); |
| EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(0u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(test_api.GetCaptureModeBarView()->settings_button(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Reverse tabbing should get us back to the GIF option. |
| SendKey(ui::VKEY_TAB, event_generator, ui::EF_SHIFT_DOWN); |
| EXPECT_EQ(FocusGroup::kRecordingTypeMenu, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(recording_type_menu_view->GetGifOptionForTesting(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Pressing the spacebar should select GIF, and close the menu. |
| SendKey(ui::VKEY_SPACE, event_generator); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(RecordingType::kGif, controller->recording_type()); |
| |
| // The focus is moved back to the drop down button. |
| EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(GetRecordingTypeDropDownButton(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| } |
| |
| TEST_F(GifRecordingTest, PressingEnterOnAFocusedItemBehavesLikeSpace) { |
| auto* controller = StartRegionVideoCapture(); |
| |
| // Tab 16 times until we reach the drop down button. |
| auto* event_generator = GetEventGenerator(); |
| SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/16); |
| using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup; |
| CaptureModeSessionTestApi test_api(controller->capture_mode_session()); |
| EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(GetRecordingTypeDropDownButton(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Pressing the enter should open the menu, and we should be in the |
| // `kPendingRecordingType` focus group. |
| SendKey(ui::VKEY_RETURN, event_generator); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(FocusGroup::kPendingRecordingType, test_api.GetCurrentFocusGroup()); |
| |
| // Then tab twice to reach the GIF recording option. |
| SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/2); |
| EXPECT_EQ(FocusGroup::kRecordingTypeMenu, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| auto* recording_type_menu_view = GetRecordingTypeMenuView(); |
| EXPECT_EQ(recording_type_menu_view->GetGifOptionForTesting(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Pressing the enter key should select GIF, and close the menu. |
| SendKey(ui::VKEY_RETURN, event_generator); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(RecordingType::kGif, controller->recording_type()); |
| |
| // The focus is moved back to the drop down button. |
| EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(GetRecordingTypeDropDownButton(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| } |
| TEST_F(GifRecordingTest, CloseRecordingMenuWhileFocusIsSomewhereElse) { |
| auto* controller = StartRegionVideoCapture(); |
| |
| // Tab 16 times until we reach the drop down button. |
| auto* event_generator = GetEventGenerator(); |
| SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/16); |
| using FocusGroup = CaptureModeSessionFocusCycler::FocusGroup; |
| CaptureModeSessionTestApi test_api(controller->capture_mode_session()); |
| EXPECT_EQ(FocusGroup::kCaptureButton, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(GetRecordingTypeDropDownButton(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Pressing the spacebar should open the menu, and we should be in the |
| // `kPendingRecordingType` focus group. |
| SendKey(ui::VKEY_SPACE, event_generator); |
| EXPECT_TRUE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(FocusGroup::kPendingRecordingType, test_api.GetCurrentFocusGroup()); |
| |
| // Now tab 4 times to put the focus on the close button. |
| SendKey(ui::VKEY_TAB, event_generator, ui::EF_NONE, /*count=*/4); |
| EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(test_api.GetCaptureModeBarView()->close_button(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| |
| // Press the escape key, the menu should close, but the focus should not |
| // change, since focus was not in or about to be in the menu. |
| SendKey(ui::VKEY_ESCAPE, event_generator); |
| EXPECT_FALSE(GetRecordingTypeMenuWidget()); |
| EXPECT_EQ(FocusGroup::kSettingsClose, test_api.GetCurrentFocusGroup()); |
| EXPECT_EQ(1u, test_api.GetCurrentFocusIndex()); |
| EXPECT_EQ(test_api.GetCaptureModeBarView()->close_button(), |
| test_api.GetCurrentFocusedView()->GetView()); |
| } |
| |
| TEST_F(GifRecordingTest, GifIsNotSupportedForFullscreenOrWindow) { |
| struct { |
| const char* const scope_name; |
| CaptureModeSource source; |
| } kTestCases[] = { |
| {"Testing fullscreen", CaptureModeSource::kFullscreen}, |
| {"Testing window", CaptureModeSource::kWindow}, |
| }; |
| |
| auto window = CreateTestWindow(gfx::Rect(200, 200)); |
| |
| for (const auto& test_case : kTestCases) { |
| SCOPED_TRACE(test_case.scope_name); |
| auto* controller = StartRegionVideoCapture(); |
| controller->SetRecordingType(RecordingType::kGif); |
| |
| // Audio recording is not supported for GIF, but switching to fullscreen or |
| // window recording should switch to webm recording, which do support audio |
| // recording, so we should expect that. |
| controller->SetAudioRecordingMode(AudioRecordingMode::kMicrophone); |
| |
| // Switch to another source than region. |
| controller->SetSource(test_case.source); |
| // The recording type remains the same, and is still set as GIF. However, |
| // the recording will be forced to webm, since GIF is only supported for |
| // `kRegion`. |
| EXPECT_EQ(controller->recording_type(), RecordingType::kGif); |
| |
| // This is needed for window recording. |
| GetEventGenerator()->MoveMouseToCenterOf(window.get()); |
| |
| StartVideoRecordingImmediately(); |
| |
| EXPECT_TRUE(controller->is_recording_in_progress()); |
| auto* test_delegate = static_cast<TestCaptureModeDelegate*>( |
| controller->delegate_for_testing()); |
| CaptureModeTestApi().FlushRecordingServiceForTesting(); |
| EXPECT_TRUE(test_delegate->IsDoingAudioRecording()); |
| controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton); |
| |
| // The resulting file should have a ".webm" extension. |
| const auto file = WaitForCaptureFileToBeSaved(); |
| EXPECT_TRUE(file.MatchesExtension(".webm")); |
| } |
| } |
| |
| TEST_F(GifRecordingTest, RecordingTypeIsRespected) { |
| auto* controller = StartRegionVideoCapture(); |
| controller->SetRecordingType(RecordingType::kGif); |
| |
| // Even though audio recording is enabled, when performing a GIF recording, |
| // the recording service should not be asked to connect to the audio streaming |
| // factory and should not be doing any audio recording. |
| controller->SetAudioRecordingMode(AudioRecordingMode::kMicrophone); |
| StartVideoRecordingImmediately(); |
| |
| // Test that the configuration histogram was reported correctly, and that the |
| // audio histogram was never reported. |
| histogram_tester_.ExpectUniqueSample( |
| "Ash.CaptureModeController.CaptureConfiguration.ClamshellMode", |
| CaptureModeConfiguration::kRegionGifRecording, |
| /*expected_bucket_count=*/1); |
| histogram_tester_.ExpectTotalCount( |
| "Ash.CaptureModeController.CaptureAudioOnMetric.ClamshellMode", |
| /*expected_count=*/0); |
| |
| EXPECT_TRUE(controller->is_recording_in_progress()); |
| auto* test_delegate = |
| static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing()); |
| CaptureModeTestApi().FlushRecordingServiceForTesting(); |
| EXPECT_FALSE(test_delegate->IsDoingAudioRecording()); |
| |
| // Record for one second so that we can test the recording length histogram. |
| WaitForSeconds(1); |
| controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton); |
| |
| // The resulting file should have a ".gif" extension. |
| const auto file = WaitForCaptureFileToBeSaved(); |
| EXPECT_TRUE(file.MatchesExtension(".gif")); |
| |
| histogram_tester_.ExpectUniqueSample( |
| "Ash.CaptureModeController.GIFRecordingLength.ClamshellMode", |
| /*sample=*/1, // 1 second. |
| /*expected_bucket_count=*/1); |
| |
| // Since getting the file size is an async operation, we have to run a loop |
| // until the task that records the file size is done. |
| base::RunLoop().RunUntilIdle(); |
| histogram_tester_.ExpectTotalCount( |
| "Ash.CaptureModeController.GIFRecordingFileSize.ClamshellMode", |
| /*expected_count=*/1); |
| } |
| |
| TEST_F(GifRecordingTest, RegionToScreenRatioHistogram) { |
| UpdateDisplay("900x600"); |
| |
| // Contains 3 test cases where the user region areas are different percentages |
| // of the full screen area. |
| struct { |
| const char* const scope_title; |
| gfx::Rect user_region_bounds; |
| int expected_percent_ratio; |
| } kTestCases[] = { |
| {"With region 450x300", gfx::Rect(450, 300), 25}, // 25%. |
| {"With region 900x300", gfx::Rect(900, 300), 50}, // 50%. |
| {"With region 900x600", gfx::Rect(900, 600), 100}, // 100%. |
| }; |
| |
| for (const auto& test_case : kTestCases) { |
| SCOPED_TRACE(test_case.scope_title); |
| auto* controller = CaptureModeController::Get(); |
| controller->SetUserCaptureRegion(test_case.user_region_bounds, |
| /*by_user=*/true); |
| controller->SetRecordingType(RecordingType::kGif); |
| |
| StartRegionVideoCapture(); |
| StartVideoRecordingImmediately(); |
| |
| histogram_tester_.ExpectBucketCount( |
| "Ash.CaptureModeController.GIFRecordingRegionToScreenRatio." |
| "ClamshellMode", |
| /*sample=*/test_case.expected_percent_ratio, |
| /*expected_count=*/1); |
| |
| controller->EndVideoRecording(EndRecordingReason::kStopRecordingButton); |
| WaitForCaptureFileToBeSaved(); |
| } |
| } |
| |
| // Regression test for b/293340894. When the region is selected in a such a way |
| // that will cause the default bounds of the recording type menu to go outside |
| // the display bounds, the bounds should be adjusted such that it remains within |
| // the target display. |
| TEST_F(GifRecordingTest, RecordingMenuOutsideOfBounds) { |
| UpdateDisplay("800x700,801+0-800x700"); |
| auto* controller = CaptureModeController::Get(); |
| controller->SetUserCaptureRegion(gfx::Rect(1550, 650, 50, 50), |
| /*by_user=*/true); |
| controller->SetRecordingType(RecordingType::kGif); |
| |
| auto* event_generator = GetEventGenerator(); |
| // Move cursor to the second display so capture mode is created there when it |
| // starts. |
| event_generator->MoveMouseTo(gfx::Point(1000, 500)); |
| StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| |
| // The menu should be created without any crashes and should be contained |
| // within the bounds of the external display. |
| auto* recording_type_menu_widget = GetRecordingTypeMenuWidget(); |
| ASSERT_TRUE(recording_type_menu_widget); |
| const gfx::Rect display_bounds{801, 0, 800, 700}; |
| EXPECT_TRUE(display_bounds.Contains( |
| recording_type_menu_widget->GetWindowBoundsInScreen())); |
| } |
| |
| // Regression test for b/319551191. |
| TEST_F(GifRecordingTest, RecordingMenuAtTheLeftOrRightEdge) { |
| // Set a region touching the left edge of the screen. |
| const gfx::Size region_size(177, 165); |
| auto* controller = CaptureModeController::Get(); |
| controller->SetUserCaptureRegion(gfx::Rect(gfx::Point(0, 0), region_size), |
| /*by_user=*/true); |
| |
| // There should be no crashes when we open the recording type menu. |
| StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| |
| // Restart the session with a region touching the right edge of the screen. |
| controller->Stop(); |
| const auto root_bounds = Shell::GetPrimaryRootWindow()->bounds(); |
| controller->SetUserCaptureRegion( |
| gfx::Rect(gfx::Point(root_bounds.right() - region_size.width(), 0), |
| region_size), |
| /*by_user=*/true); |
| |
| // Similarly, there should be no crashes. |
| StartRegionVideoCapture(); |
| ClickOnDropDownButton(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // ProjectorGifRecordingTest: |
| |
| class ProjectorGifRecordingTest : public GifRecordingTest { |
| public: |
| ProjectorGifRecordingTest() = default; |
| ~ProjectorGifRecordingTest() override = default; |
| |
| // ProjectorGifRecordingTest: |
| void SetUp() override { |
| GifRecordingTest::SetUp(); |
| projector_helper_.SetUp(); |
| } |
| |
| void StartProjectorModeSession() { |
| projector_helper_.StartProjectorModeSession(); |
| } |
| |
| private: |
| ProjectorCaptureModeIntegrationHelper projector_helper_; |
| }; |
| |
| TEST_F(ProjectorGifRecordingTest, ProjectorRecordingType) { |
| // Start a normal session and enable GIF recording. |
| auto* controller = StartRegionVideoCapture(); |
| controller->SetRecordingType(RecordingType::kGif); |
| |
| // Exit this session and start a new projector-initiated session. The active |
| // recording type should be `kWebM`. |
| controller->Stop(); |
| StartProjectorModeSession(); |
| EXPECT_TRUE(controller->IsActive()); |
| EXPECT_EQ(controller->recording_type(), RecordingType::kWebM); |
| |
| // By default, the capture source is fullscreen in projector sessions. Switch |
| // to `kRegion` and expect that the capture button will show the correct text. |
| controller->SetSource(CaptureModeSource::kRegion); |
| EXPECT_EQ(GetCaptureButton()->GetText(), u"Record video"); |
| |
| // The drop-down button should not be created in this case. |
| EXPECT_FALSE( |
| GetCaptureLabelView()->capture_button_container()->drop_down_button()); |
| |
| // Exit this session and start a new normal session with the most recent |
| // values and expect that the pre-projector-session recording type was |
| // restored. |
| controller->Stop(); |
| controller->Start(CaptureModeEntryType::kQuickSettings); |
| EXPECT_EQ(controller->recording_type(), RecordingType::kGif); |
| EXPECT_EQ(GetCaptureButton()->GetText(), u"Record GIF"); |
| EXPECT_TRUE( |
| GetCaptureLabelView()->capture_button_container()->drop_down_button()); |
| } |
| |
| } // namespace ash |