blob: df7e3d848f16518fef261ae71744584159f52bab [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_PREVIEW_VIEW_H_
#define ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_PREVIEW_VIEW_H_
#include "ash/accessibility/accessibility_controller_impl.h"
#include "ash/accessibility/accessibility_observer.h"
#include "ash/capture_mode/camera_video_frame_renderer.h"
#include "ash/capture_mode/capture_mode_button.h"
#include "ash/capture_mode/capture_mode_camera_controller.h"
#include "ash/capture_mode/capture_mode_session_focus_cycler.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/view.h"
namespace media {
struct VideoCaptureFormat;
} // namespace media
namespace video_capture::mojom {
class VideoSource;
} // namespace video_capture::mojom
namespace views {
class NativeViewHost;
} // namespace views
namespace ash {
class CaptureModeCameraController;
class ScopedA11yOverrideWindowSetter;
// Resize button inside the camera preview view.
class CameraPreviewResizeButton : public CaptureModeButton {
public:
METADATA_HEADER(CameraPreviewResizeButton);
CameraPreviewResizeButton(CameraPreviewView* camera_preview_view,
views::Button::PressedCallback callback,
const gfx::VectorIcon& icon);
CameraPreviewResizeButton(const CameraPreviewResizeButton&) = delete;
CameraPreviewResizeButton& operator=(const CameraPreviewResizeButton&) =
delete;
~CameraPreviewResizeButton() override;
// CaptureModeSessionFocusCycler::HighlightableView:
void PseudoFocus() override;
void PseudoBlur() override;
private:
CameraPreviewView* const camera_preview_view_; // not owned.
};
// A view that acts as the contents view of the camera preview widget. It will
// be responsible for painting the latest camera video frame inside its bounds.
class CameraPreviewView
: public views::View,
public CaptureModeSessionFocusCycler::HighlightableView,
public AccessibilityObserver {
public:
METADATA_HEADER(CameraPreviewView);
CameraPreviewView(
CaptureModeCameraController* camera_controller,
const CameraId& camera_id,
mojo::Remote<video_capture::mojom::VideoSource> camera_video_source,
const media::VideoCaptureFormat& capture_format,
bool should_flip_frames_horizontally);
CameraPreviewView(const CameraPreviewView&) = delete;
CameraPreviewView& operator=(const CameraPreviewView&) = delete;
~CameraPreviewView() override;
const CameraId& camera_id() const { return camera_id_; }
CameraPreviewResizeButton* resize_button() const { return resize_button_; }
bool is_collapsible() const { return is_collapsible_; }
bool should_flip_frames_horizontally() const {
return camera_video_renderer_.should_flip_frames_horizontally();
}
// Sets this camera preview collapsability to the given `value`, which will
// update the resize button visibility.
void SetIsCollapsible(bool value);
// Returns true if the `event` has been handled by CameraPrevieView. It
// happens if it is control+arrow keys, which will be used to move the camera
// preview to different snap positions.
bool MaybeHandleKeyEvent(const ui::KeyEvent* event);
// Called to update visibility of the `resize_button_` when necessary.
void RefreshResizeButtonVisibility();
// Updates the a11y override window when focus state changes on the camera
// preview. The a11y override window will be set to nullptr if neither the
// camera preview nor the resize button has focus. This is done to make sure
// a11y focus can be moved to others appropriately.
void UpdateA11yOverrideWindow();
// Removes the focus from camera preview when necessary. Happens if mouse
// pressing outside of the camera preview when it has focus. A11y override
// window will be updated as well.
void MaybeBlurFocus(const ui::MouseEvent& event);
// views::View:
void AddedToWidget() override;
bool OnMousePressed(const ui::MouseEvent& event) override;
bool OnMouseDragged(const ui::MouseEvent& event) override;
void OnMouseReleased(const ui::MouseEvent& event) override;
void OnGestureEvent(ui::GestureEvent* event) override;
void OnMouseEntered(const ui::MouseEvent& event) override;
void OnMouseExited(const ui::MouseEvent& event) override;
void Layout() override;
void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
// CaptureModeSessionFocusCycler::HighlightableView:
views::View* GetView() override;
std::unique_ptr<views::HighlightPathGenerator> CreatePathGenerator() override;
// AccessibilityObserver:
void OnAccessibilityStatusChanged() override;
void OnAccessibilityControllerShutdown() override;
base::OneShotTimer* resize_button_hide_timer_for_test() {
return &resize_button_hide_timer_;
}
private:
friend class CameraPreviewResizeButton;
friend class CaptureModeTestApi;
// Called when the resize button is clicked or touched.
void OnResizeButtonPressed();
// Updates the icon of the `resize_button_` based on value of
// `is_camera_preview_collapsed()` inferred from the `camera_controller`.
void UpdateResizeButton();
// Updates the tooltip of the `resize_button_`. The `resize_button_` can be an
// expand button or collapse button.
void UpdateResizeButtonTooltip();
// Located events within the bounds of this view should be sent to, and
// handled by this view only (e.g. for drag and drop). They should not be sent
// to any native window hosting the camera video frames, otherwise we will
// lose those events. This function disable event targeting for the
// `camera_video_host_view_` and all the native windows it is hosting.
void DisableEventHandlingInCameraVideoHostHierarchy();
// Fades in or out the `resize_button_` and updates its visibility
// accordingly.
void FadeInResizeButton();
void FadeOutResizeButton();
// Called when the mouse exits the camera preview, after the latest tap inside
// the camera preview or when focus being removed from the resize button to
// start the `resize_button_hide_timer_`.
void ScheduleRefreshResizeButtonVisibility();
// Returns the target opacity for resize button.
float CalculateResizeButtonTargetOpacity();
// Removes the focus from the camera preview and updates the a11y override
// window.
void BlurA11yFocus();
CaptureModeCameraController* const camera_controller_;
// The ID of the camera for which this preview was created.
const CameraId camera_id_;
// Renders the camera video frames into its `host_window()`.
CameraVideoFrameRenderer camera_video_renderer_;
// The view that hosts the native window `host_window()` of the
// `camera_video_renderer_` into this view's hierarchy.
views::NativeViewHost* const camera_video_host_view_;
CameraPreviewResizeButton* const resize_button_;
// Started when the mouse exits the camera preview or after the latest tap
// inside the camera preview. Runs RefreshResizeButtonVisibility() to fade out
// the resize button if possible.
base::OneShotTimer resize_button_hide_timer_;
// True if the size of the preview in the expanded state is big enough to
// allow it to be collapsible.
bool is_collapsible_ = true;
// True only while handling a gesture tap event on this view.
bool has_been_tapped_ = false;
base::ScopedObservation<AccessibilityControllerImpl, AccessibilityObserver>
accessibility_observation_{this};
// Helps to update the current a11y override window. It will be the native
// window of the camera preview or nullptr, depends on whether the camera
// preview has focus or not. Accessibility features will focus on the window
// after it is set. Once `this` goes out of scope, the a11y override window is
// set to nullptr.
std::unique_ptr<ScopedA11yOverrideWindowSetter> scoped_a11y_overrider_;
base::WeakPtrFactory<CameraPreviewView> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_PREVIEW_VIEW_H_