| // Copyright 2023 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_mode_behavior.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "ash/capture_mode/base_capture_mode_session.h" |
| #include "ash/capture_mode/capture_mode_camera_controller.h" |
| #include "ash/capture_mode/capture_mode_constants.h" |
| #include "ash/capture_mode/capture_mode_controller.h" |
| #include "ash/capture_mode/capture_mode_metrics.h" |
| #include "ash/capture_mode/capture_mode_types.h" |
| #include "ash/capture_mode/capture_mode_util.h" |
| #include "ash/capture_mode/game_capture_bar_view.h" |
| #include "ash/capture_mode/normal_capture_bar_view.h" |
| #include "ash/capture_mode/sunfish_capture_bar_view.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/projector/projector_controller_impl.h" |
| #include "ash/public/cpp/capture_mode/capture_mode_api.h" |
| #include "ash/scanner/scanner_controller.h" |
| #include "ash/scanner/scanner_disclaimer.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shelf/shelf.h" |
| #include "ash/shelf/shelf_layout_manager.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "base/check.h" |
| #include "base/feature_list.h" |
| #include "base/files/file_path.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/notreached.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "components/prefs/pref_service.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/message_center/public/cpp/notification.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Width of the full capture bar, which includes all the elements of the normal |
| // capture bar. |
| constexpr int kFullCaptureBarWidth = 376; |
| |
| // Width of the game capture bar. |
| constexpr int kGameCaptureBarWidth = 250; |
| |
| // Returns the current configs before been overwritten by the client-initiated |
| // capture mode session |
| CaptureModeSessionConfigs GetCaptureModeSessionConfigs() { |
| CaptureModeController* controller = CaptureModeController::Get(); |
| CaptureModeSessionConfigs configs = CaptureModeSessionConfigs{ |
| controller->type(), controller->source(), controller->recording_type(), |
| controller->audio_recording_mode(), controller->enable_demo_tools()}; |
| return configs; |
| } |
| |
| void SetCaptureModeSessionConfigs(const CaptureModeSessionConfigs& configs) { |
| CaptureModeController* controller = CaptureModeController::Get(); |
| controller->SetType(configs.type); |
| controller->SetSource(configs.source); |
| controller->SetRecordingType(configs.recording_type); |
| controller->SetAudioRecordingMode(configs.audio_recording_mode); |
| controller->EnableDemoTools(configs.demo_tools_enabled); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| // DefaultBehavior: |
| // Implements the `CaptureModeBehavior` interface with behavior defined for the |
| // default capture mode. |
| class DefaultBehavior : public CaptureModeBehavior { |
| public: |
| DefaultBehavior() |
| : CaptureModeBehavior( |
| {CaptureModeType::kImage, CaptureModeSource::kRegion, |
| RecordingType::kWebM, AudioRecordingMode::kOff, |
| /*demo_tools_enabled=*/false}, |
| BehaviorType::kDefault) {} |
| |
| DefaultBehavior(const DefaultBehavior&) = delete; |
| DefaultBehavior& operator=(const DefaultBehavior&) = delete; |
| ~DefaultBehavior() override = default; |
| |
| // CaptureModeBehavior: |
| void AttachToSession() override { |
| // Do not override the session configs in `DefaultBehavior`, since the |
| // source and type may have been set before the session was started and |
| // initialized. |
| } |
| void DetachFromSession() override { |
| if (auto* scanner_controller = Shell::Get()->scanner_controller()) { |
| scanner_controller->OnSessionUIClosed(); |
| } |
| } |
| bool ShouldRegionOverlayBeAllowed() const override { |
| // TODO(crbug.com/376103983): Verify `CaptureRegionOverlayController` works |
| // correctly. It is always created in Sunfish session to paint the region |
| // selection UI, but should only support text overlay if Scanner is enabled. |
| return CanShowSunfishOrScannerUi(); |
| } |
| bool CanPaintRegionOverlay() const override { |
| auto* controller = CaptureModeController::Get(); |
| return controller->type() == CaptureModeType::kImage && |
| controller->source() == CaptureModeSource::kRegion; |
| } |
| bool ShouldShowGlowWhileProcessingCaptureType( |
| PerformCaptureType capture_type) const override { |
| return CanPaintRegionOverlay() && Shell::Get()->scanner_controller() && |
| capture_type == PerformCaptureType::kScanner; |
| } |
| bool ShouldEndSessionOnShowingSearchResults() const override { return true; } |
| bool CanShowActionButtons() const override { return true; } |
| void OnRegionSelectedOrAdjustedWhenActionContainerShowing() override { |
| CHECK(ShouldShowDefaultActionButtonsInActionContainer()); |
| auto* capture_mode_controller = CaptureModeController::Get(); |
| if (features::IsCaptureModeOnDeviceOcrEnabled()) { |
| // Perform text detection to determine whether the copy text and smart |
| // actions buttons should be shown. |
| capture_mode_controller->PerformCapture( |
| PerformCaptureType::kTextDetection); |
| } else { |
| // Show the smart actions button regardless of whether there is text |
| // in the selected area or not. |
| BaseCaptureModeSession* session = |
| capture_mode_controller->capture_mode_session(); |
| CHECK(session); |
| session->AddSmartActionsButton(); |
| } |
| } |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // ProjectorBehavior: |
| // Implements the `CaptureModeBehavior` interface with behavior defined for the |
| // projector-initiated capture mode. |
| class ProjectorBehavior : public CaptureModeBehavior { |
| public: |
| ProjectorBehavior() |
| : CaptureModeBehavior( |
| {CaptureModeType::kVideo, CaptureModeSource::kFullscreen, |
| RecordingType::kWebM, AudioRecordingMode::kMicrophone, |
| /*demo_tools_enabled=*/true}, |
| BehaviorType::kProjector) {} |
| |
| ProjectorBehavior(const ProjectorBehavior&) = delete; |
| ProjectorBehavior& operator=(const ProjectorBehavior&) = delete; |
| ~ProjectorBehavior() override = default; |
| |
| bool ShouldImageCaptureTypeBeAllowed() const override { return false; } |
| bool ShouldSaveToSettingsBeIncluded() const override { return false; } |
| bool ShouldGifBeSupported() const override { return false; } |
| bool ShouldShowPreviewNotification() const override { return false; } |
| bool SupportsAudioRecordingMode(AudioRecordingMode mode) const override { |
| switch (mode) { |
| case AudioRecordingMode::kOff: |
| case AudioRecordingMode::kSystem: |
| // Projector does not support turning off audio recording nor recording |
| // the system audio separately without the microphone. |
| return false; |
| case AudioRecordingMode::kMicrophone: |
| case AudioRecordingMode::kSystemAndMicrophone: |
| return true; |
| } |
| } |
| bool ShouldCreateAnnotationsOverlayController() const override { |
| return true; |
| } |
| bool ShouldShowUserNudge() const override { return false; } |
| bool ShouldAutoSelectFirstCamera() const override { return true; } |
| bool RequiresCaptureFolderCreation() const override { return true; } |
| void CreateCaptureFolder(OnCaptureFolderCreatedCallback callback) override { |
| ProjectorControllerImpl::Get()->CreateScreencastContainerFolder( |
| base::BindOnce(&ProjectorBehavior::OnScreencastContainerFolderCreated, |
| weak_ptr_factory_.GetWeakPtr(), std::move(callback))); |
| } |
| std::vector<RecordingType> GetSupportedRecordingTypes() const override { |
| return std::vector<RecordingType>{RecordingType::kWebM}; |
| } |
| const char* GetClientMetricComponent() const override { return "Projector."; } |
| |
| protected: |
| int GetCaptureBarWidth() const override { |
| return kFullCaptureBarWidth - capture_mode::kButtonSize.width() - |
| capture_mode::kSpaceBetweenCaptureModeTypeButtons; |
| } |
| |
| private: |
| // Called when the Projector controller creates the DriveFS folder that will |
| // host the video file along with the associated metadata file created by the |
| // Projector session. |
| void OnScreencastContainerFolderCreated( |
| OnCaptureFolderCreatedCallback callback, |
| const base::FilePath& capture_file_full_path) { |
| base::FilePath path; |
| // An empty path is sent to indicate an error. |
| if (!capture_file_full_path.empty()) { |
| path = capture_file_full_path.AddExtension("webm"); |
| } |
| std::move(callback).Run(path); |
| } |
| |
| base::WeakPtrFactory<ProjectorBehavior> weak_ptr_factory_{this}; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // GameDashboardBehavior: |
| // Implements the `CaptureModeBehavior` interface with behaviors defined by the |
| // game dashboard-initiated capture mode. |
| class GameDashboardBehavior : public CaptureModeBehavior, |
| public aura::WindowObserver { |
| public: |
| GameDashboardBehavior() |
| : CaptureModeBehavior( |
| {CaptureModeType::kVideo, CaptureModeSource::kWindow, |
| RecordingType::kWebM, AudioRecordingMode::kSystemAndMicrophone, |
| /*demo_tools_enabled=*/false}, |
| BehaviorType::kGameDashboard) {} |
| |
| GameDashboardBehavior(const GameDashboardBehavior&) = delete; |
| GameDashboardBehavior operator=(const GameDashboardBehavior&) = delete; |
| ~GameDashboardBehavior() override = default; |
| |
| // CaptureModeBehavior: |
| void AttachToSession() override { |
| CaptureModeBehavior::AttachToSession(); |
| |
| CaptureModeController* controller = CaptureModeController::Get(); |
| BaseCaptureModeSession* session = controller->capture_mode_session(); |
| CHECK(session); |
| if (!pre_selected_window_) { |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, |
| base::BindOnce( |
| [](base::WeakPtr<GameDashboardBehavior> game_dashboard_behavior, |
| CaptureModeController* controller) { |
| if (controller->IsActive()) { |
| controller->Stop(); |
| } |
| }, |
| weak_ptr_factory_.GetWeakPtr(), controller)); |
| } else { |
| session->SetPreSelectedWindow(pre_selected_window_); |
| } |
| } |
| |
| void DetachFromSession() override { |
| CaptureModeBehavior::DetachFromSession(); |
| |
| if (pre_selected_window_) { |
| pre_selected_window_->RemoveObserver(this); |
| pre_selected_window_ = nullptr; |
| } |
| } |
| |
| bool ShouldImageCaptureTypeBeAllowed() const override { return false; } |
| bool ShouldFulscreenCaptureSourceBeAllowed() const override { return false; } |
| bool ShouldRegionCaptureSourceBeAllowed() const override { return false; } |
| bool ShouldDemoToolsSettingsBeIncluded() const override { return false; } |
| bool ShouldGifBeSupported() const override { return false; } |
| bool ShouldShowUserNudge() const override { return false; } |
| bool ShouldAutoSelectFirstCamera() const override { |
| return !CaptureModeController::Get() |
| ->camera_controller() |
| ->did_user_ever_change_camera(); |
| } |
| |
| std::unique_ptr<CaptureModeBarView> CreateCaptureModeBarView() override { |
| return std::make_unique<GameCaptureBarView>(); |
| } |
| |
| void SetPreSelectedWindow(aura::Window* pre_selected_window) override { |
| CHECK(!pre_selected_window_); |
| pre_selected_window_ = pre_selected_window; |
| pre_selected_window_->AddObserver(this); |
| } |
| |
| const char* GetClientMetricComponent() const override { |
| return "GameDashboard."; |
| } |
| |
| std::vector<message_center::ButtonInfo> GetNotificationButtonsInfo( |
| bool for_video) const override { |
| return {message_center::ButtonInfo{l10n_util::GetStringUTF16( |
| for_video ? IDS_ASH_SCREEN_CAPTURE_SHARE_TO_YOUTUBE |
| : IDS_ASH_SCREEN_CAPTURE_BUTTON_EDIT)}, |
| message_center::ButtonInfo{l10n_util::GetStringUTF16( |
| IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE)}}; |
| } |
| |
| void OnAudioRecordingModeChanged() override { |
| capture_mode_configs_.audio_recording_mode = |
| CaptureModeController::Get()->audio_recording_mode(); |
| } |
| |
| void OnDemoToolsSettingsChanged() override { |
| capture_mode_configs_.demo_tools_enabled = |
| CaptureModeController::Get()->enable_demo_tools(); |
| } |
| |
| // aura::WindowObserver: |
| void OnWindowDestroying(aura::Window* window) override { |
| CHECK_EQ(window, pre_selected_window_); |
| pre_selected_window_->RemoveObserver(this); |
| pre_selected_window_ = nullptr; |
| } |
| |
| protected: |
| // CaptureModeBehavior: |
| gfx::Rect GetBarAnchorBoundsInScreen(aura::Window* root) const override { |
| CHECK(pre_selected_window_); |
| return pre_selected_window_->GetBoundsInScreen(); |
| } |
| |
| int GetCaptureBarBottomPadding() const override { |
| return capture_mode::kGameCaptureBarBottomPadding; |
| } |
| |
| int GetCaptureBarWidth() const override { return kGameCaptureBarWidth; } |
| |
| private: |
| raw_ptr<aura::Window> pre_selected_window_ = nullptr; |
| base::WeakPtrFactory<GameDashboardBehavior> weak_ptr_factory_{this}; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // SunfishBehavior: |
| // Implements the `CaptureModeBehavior` interface with behavior defined for the |
| // sunfish capture mode. |
| class SunfishBehavior : public CaptureModeBehavior { |
| public: |
| SunfishBehavior() |
| : CaptureModeBehavior( |
| {CaptureModeType::kImage, CaptureModeSource::kRegion, |
| RecordingType::kWebM, AudioRecordingMode::kOff, |
| /*demo_tools_enabled=*/false}, |
| BehaviorType::kSunfish) {} |
| |
| SunfishBehavior(const SunfishBehavior&) = delete; |
| SunfishBehavior& operator=(const SunfishBehavior&) = delete; |
| ~SunfishBehavior() override = default; |
| |
| // CaptureModeBehavior: |
| // The Scanner session is started from |
| // `CaptureModeController::MaybeShowScannerDisclaimerOnSunfishStartup`. |
| void DetachFromSession() override { |
| CaptureModeBehavior::DetachFromSession(); |
| if (auto* scanner_controller = Shell::Get()->scanner_controller()) { |
| scanner_controller->OnSessionUIClosed(); |
| } |
| } |
| bool ShouldRegionOverlayBeAllowed() const override { |
| return CanShowSunfishOrScannerUi(); |
| } |
| bool CanPaintRegionOverlay() const override { return true; } |
| bool ShouldShowGlowWhileProcessingCaptureType( |
| PerformCaptureType capture_type) const override { |
| return CanPaintRegionOverlay(); |
| } |
| bool ShouldShowUserNudge() const override { return false; } |
| bool ShouldReShowUisAtPerformingCapture( |
| PerformCaptureType capture_type) const override { |
| return true; |
| } |
| bool ShouldShowDefaultActionButtonsInActionContainer() const override { |
| // We show action buttons in Sunfish mode for individual Scanner actions, |
| // which is a different set of buttons to the default action buttons shown |
| // in normal capture mode (search, copy text, smart actions button). |
| return false; |
| } |
| bool ShouldShowCaptureButtonAfterRegionSelected() const override { |
| return false; |
| } |
| bool ShouldPaintSunfishCaptureRegion() const override { return true; } |
| bool CanShowActionButtons() const override { return true; } |
| bool ShouldEndSessionOnSearchResultClicked() const override { return true; } |
| bool NeedsDisclaimerOnInit() const override { |
| // Return true if Scanner is enabled and any type of disclaimer should be |
| // shown at the start of a Sunfish-session. |
| return ScannerController::CanShowUiForShell() && |
| GetScannerDisclaimerType( |
| *capture_mode_util::GetActiveUserPrefService(), |
| ScannerEntryPoint::kSunfishSession) != |
| ScannerDisclaimerType::kNone; |
| } |
| bool ShouldAnnounceCaptureModeUIOnDisclaimerDismissed() const override { |
| return true; |
| } |
| const std::u16string GetCaptureLabelRegionText() const override { |
| return l10n_util::GetStringUTF16( |
| IDS_ASH_SUNFISH_CAPTURE_LABEL_KEYBOARD_NAVIGATION); |
| } |
| const std::u16string GetActionButtonContainerTitle() const override { |
| return l10n_util::GetStringUTF16( |
| IDS_ASH_SCREEN_CAPTURE_SUNFISH_ACTION_BUTTON_WINDOW_TITLE); |
| } |
| const std::u16string GetCaptureModeBarTitle() const override { |
| // The capture mode bar window does not need a title for Sunfish behavior |
| // since it only contains a close button. |
| return u""; |
| } |
| const std::string GetCaptureModeOpenAnnouncement() const override { |
| return l10n_util::GetStringUTF8(IDS_ASH_SUNFISH_MODE_ALERT_OPEN); |
| } |
| int GetCaptureBarWidth() const override { |
| // Return the height so the button is circular. |
| return capture_mode::kCaptureBarHeight; |
| } |
| std::unique_ptr<CaptureModeBarView> CreateCaptureModeBarView() override { |
| return std::make_unique<SunfishCaptureBarView>(); |
| } |
| void OnRegionSelectedOrAdjustedWhenActionContainerShowing() override { |
| auto* controller = CaptureModeController::Get(); |
| controller->MaybeUpdateSearchResultsPanelBounds(); |
| |
| // `CaptureModeController` will perform DLP restriction checks and determine |
| // whether the image can be sent for search. |
| controller->PerformCapture(PerformCaptureType::kSunfish); |
| } |
| void OnEnterKeyPressed() override {} |
| }; |
| |
| } // namespace |
| |
| // ----------------------------------------------------------------------------- |
| // CaptureModeBehavior: |
| |
| CaptureModeBehavior::CaptureModeBehavior( |
| const CaptureModeSessionConfigs& configs, |
| const BehaviorType behavior_type) |
| : capture_mode_configs_(configs), behavior_type_(behavior_type) {} |
| |
| CaptureModeBehavior::~CaptureModeBehavior() = default; |
| |
| // static |
| std::unique_ptr<CaptureModeBehavior> CaptureModeBehavior::Create( |
| BehaviorType behavior_type) { |
| switch (behavior_type) { |
| case BehaviorType::kProjector: |
| return std::make_unique<ProjectorBehavior>(); |
| case BehaviorType::kGameDashboard: |
| return std::make_unique<GameDashboardBehavior>(); |
| case BehaviorType::kDefault: |
| return std::make_unique<DefaultBehavior>(); |
| case BehaviorType::kSunfish: |
| return std::make_unique<SunfishBehavior>(); |
| } |
| } |
| |
| void CaptureModeBehavior::AttachToSession() { |
| cached_configs_ = GetCaptureModeSessionConfigs(); |
| |
| // Overwrite the current capture mode session with the behavior |
| // configurations. |
| SetCaptureModeSessionConfigs(capture_mode_configs_); |
| } |
| |
| void CaptureModeBehavior::DetachFromSession() { |
| CHECK(cached_configs_); |
| |
| // Restore the capture mode configurations after being overwritten with the |
| // behavior-specific configurations. |
| SetCaptureModeSessionConfigs(cached_configs_.value()); |
| cached_configs_.reset(); |
| } |
| |
| bool CaptureModeBehavior::ShouldRegionOverlayBeAllowed() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::CanPaintRegionOverlay() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldShowGlowWhileProcessingCaptureType( |
| PerformCaptureType capture_type) const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldImageCaptureTypeBeAllowed() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldVideoCaptureTypeBeAllowed() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldFulscreenCaptureSourceBeAllowed() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldRegionCaptureSourceBeAllowed() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldWindowCaptureSourceBeAllowed() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::SupportsAudioRecordingMode( |
| AudioRecordingMode mode) const { |
| switch (mode) { |
| case AudioRecordingMode::kOff: |
| case AudioRecordingMode::kMicrophone: |
| case AudioRecordingMode::kSystem: |
| case AudioRecordingMode::kSystemAndMicrophone: |
| return true; |
| } |
| } |
| |
| bool CaptureModeBehavior::ShouldCameraSelectionSettingsBeIncluded() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldDemoToolsSettingsBeIncluded() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldSaveToSettingsBeIncluded() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldGifBeSupported() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldShowPreviewNotification() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldSkipVideoRecordingCountDown() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldCreateAnnotationsOverlayController() const { |
| if (base::FeatureList::IsEnabled(ash::features::kAnnotatorMode)) { |
| return true; |
| } |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldShowUserNudge() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldAutoSelectFirstCamera() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::RequiresCaptureFolderCreation() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldReShowUisAtPerformingCapture( |
| PerformCaptureType capture_type) const { |
| switch (capture_type) { |
| case PerformCaptureType::kCapture: |
| // The session shuts down after image capture so there is no need to |
| // reshow the UIs. For video recording, we need to reshow the UIs so that |
| // we can start the 3-second count down animation. |
| return CaptureModeController::Get()->type() != CaptureModeType::kImage; |
| case PerformCaptureType::kSearch: |
| // The session shuts down after capture for `PerformCaptureType::kSearch` |
| // so there is no need to reshow the UIs. |
| return false; |
| case PerformCaptureType::kScanner: |
| case PerformCaptureType::kTextDetection: |
| case PerformCaptureType::kSunfish: |
| return true; |
| } |
| } |
| |
| bool CaptureModeBehavior::ShouldShowDefaultActionButtonsInActionContainer() |
| const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::CanShowActionButtons() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldPaintSunfishCaptureRegion() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldShowCaptureButtonAfterRegionSelected() const { |
| return true; |
| } |
| |
| bool CaptureModeBehavior::ShouldEndSessionOnShowingSearchResults() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldEndSessionOnSearchResultClicked() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::NeedsDisclaimerOnInit() const { |
| return false; |
| } |
| |
| bool CaptureModeBehavior::ShouldAnnounceCaptureModeUIOnDisclaimerDismissed() |
| const { |
| return false; |
| } |
| |
| void CaptureModeBehavior::CreateCaptureFolder( |
| OnCaptureFolderCreatedCallback callback) { |
| NOTREACHED(); |
| } |
| |
| std::vector<RecordingType> CaptureModeBehavior::GetSupportedRecordingTypes() |
| const { |
| return {RecordingType::kWebM, RecordingType::kGif}; |
| } |
| |
| void CaptureModeBehavior::SetPreSelectedWindow( |
| aura::Window* pre_selected_window) { |
| NOTREACHED(); |
| } |
| |
| const char* CaptureModeBehavior::GetClientMetricComponent() const { |
| return ""; |
| } |
| |
| std::vector<message_center::ButtonInfo> |
| CaptureModeBehavior::GetNotificationButtonsInfo(bool for_video) const { |
| std::vector<message_center::ButtonInfo> buttons_info; |
| |
| if (!for_video && |
| !Shell::Get()->session_controller()->IsUserSessionBlocked()) { |
| buttons_info.emplace_back( |
| l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_EDIT)); |
| } |
| |
| buttons_info.emplace_back( |
| l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_BUTTON_DELETE)); |
| |
| return buttons_info; |
| } |
| |
| const std::u16string CaptureModeBehavior::GetCaptureLabelRegionText() const { |
| CaptureModeController* controller = CaptureModeController::Get(); |
| DCHECK(controller->user_capture_region().IsEmpty()); |
| return l10n_util::GetStringUTF16( |
| controller->type() == CaptureModeType::kImage |
| ? IDS_ASH_SCREEN_CAPTURE_LABEL_REGION_IMAGE_CAPTURE_KEYBOARD_NAVIGATION |
| : IDS_ASH_SCREEN_CAPTURE_LABEL_REGION_VIDEO_RECORD_KEYBOARD_NAVIGATION); |
| } |
| |
| const std::u16string CaptureModeBehavior::GetActionButtonContainerTitle() |
| const { |
| return l10n_util::GetStringUTF16( |
| IDS_ASH_SCREEN_CAPTURE_DEFAULT_ACTION_BUTTON_WINDOW_TITLE); |
| } |
| |
| const std::u16string CaptureModeBehavior::GetCaptureModeBarTitle() const { |
| return l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_A11Y_TITLE); |
| } |
| |
| const std::string CaptureModeBehavior::GetCaptureModeOpenAnnouncement() const { |
| CaptureModeController* controller = CaptureModeController::Get(); |
| int capture_source_id; |
| switch (controller->source()) { |
| case CaptureModeSource::kFullscreen: |
| capture_source_id = IDS_ASH_SCREEN_CAPTURE_SOURCE_FULLSCREEN; |
| break; |
| case CaptureModeSource::kRegion: |
| capture_source_id = IDS_ASH_SCREEN_CAPTURE_SOURCE_PARTIAL; |
| break; |
| case CaptureModeSource::kWindow: |
| capture_source_id = IDS_ASH_SCREEN_CAPTURE_SOURCE_WINDOW; |
| break; |
| } |
| |
| return l10n_util::GetStringFUTF8( |
| IDS_ASH_SCREEN_CAPTURE_KEYBOARD_NAVIGATION_ALERT_OPEN_REVISED, |
| l10n_util::GetStringUTF16(capture_source_id), |
| l10n_util::GetStringUTF16( |
| controller->type() == CaptureModeType::kImage |
| ? IDS_ASH_SCREEN_CAPTURE_TYPE_SCREENSHOT |
| : IDS_ASH_SCREEN_CAPTURE_TYPE_SCREEN_RECORDING)); |
| } |
| |
| std::unique_ptr<CaptureModeBarView> |
| CaptureModeBehavior::CreateCaptureModeBarView() { |
| return std::make_unique<NormalCaptureBarView>(this); |
| } |
| |
| gfx::Rect CaptureModeBehavior::GetCaptureBarBounds(aura::Window* root) const { |
| auto bounds = GetBarAnchorBoundsInScreen(root); |
| const int bar_y = bounds.bottom() - GetCaptureBarBottomPadding() - |
| capture_mode::kCaptureBarHeight; |
| bounds.ClampToCenteredSize( |
| gfx::Size(GetCaptureBarWidth(), capture_mode::kCaptureBarHeight)); |
| bounds.set_y(bar_y); |
| return bounds; |
| } |
| |
| gfx::Rect CaptureModeBehavior::GetBarAnchorBoundsInScreen( |
| aura::Window* root) const { |
| CHECK(root); |
| auto bounds = root->GetBoundsInScreen(); |
| int new_bottom = bounds.bottom(); |
| |
| Shelf* shelf = Shelf::ForWindow(root); |
| if (shelf->IsHorizontalAlignment()) { |
| // Get the widget which has the shelf icons. This is the hotseat widget if |
| // the hotseat is extended, shelf widget otherwise. |
| const bool hotseat_extended = |
| shelf->shelf_layout_manager()->hotseat_state() == |
| HotseatState::kExtended; |
| views::Widget* shelf_widget = |
| hotseat_extended ? static_cast<views::Widget*>(shelf->hotseat_widget()) |
| : static_cast<views::Widget*>(shelf->shelf_widget()); |
| new_bottom = shelf_widget->GetWindowBoundsInScreen().y(); |
| } |
| bounds.set_height(new_bottom - bounds.y()); |
| return bounds; |
| } |
| |
| int CaptureModeBehavior::GetCaptureBarBottomPadding() const { |
| return capture_mode::kCaptureBarBottomPadding; |
| } |
| |
| int CaptureModeBehavior::GetCaptureBarWidth() const { |
| return kFullCaptureBarWidth; |
| } |
| |
| void CaptureModeBehavior::OnAudioRecordingModeChanged() {} |
| |
| void CaptureModeBehavior::OnDemoToolsSettingsChanged() {} |
| |
| void CaptureModeBehavior:: |
| OnRegionSelectedOrAdjustedWhenActionContainerShowing() {} |
| |
| void CaptureModeBehavior::OnEnterKeyPressed() { |
| CaptureModeController::Get()->PerformCapture(); |
| } |
| |
| } // namespace ash |