Skip to content

Commit

Permalink
capture_selfie_cam: Show a toast when capture surface can't fit preview
Browse files Browse the repository at this point in the history
This CL implemented the mechanism to show a toast when the capture
surface becomes too small to fit the camera preview to notify users.
The toast will be dismissed immedistely when there's an action taken by
the user. Or it will be auto dismissed after 6 seconds when there're no
actions taken.

Fixed: 1306563
Test: Manual, added unit-tests
Change-Id: I5545544a0248cbb86e9efa7839b28b49e552d577
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3624547
Commit-Queue: Connie Xu <conniekxu@chromium.org>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1002394}
  • Loading branch information
conniekxu authored and Chromium LUCI CQ committed May 11, 2022
1 parent 2c0d22e commit a5ce126
Show file tree
Hide file tree
Showing 19 changed files with 955 additions and 283 deletions.
2 changes: 2 additions & 0 deletions ash/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ component("ash") {
"capture_mode/capture_mode_source_view.cc",
"capture_mode/capture_mode_source_view.h",
"capture_mode/capture_mode_test_api.cc",
"capture_mode/capture_mode_toast_controller.cc",
"capture_mode/capture_mode_toast_controller.h",
"capture_mode/capture_mode_toggle_button.cc",
"capture_mode/capture_mode_toggle_button.h",
"capture_mode/capture_mode_type_view.cc",
Expand Down
3 changes: 3 additions & 0 deletions ash/ash_strings.grd
Original file line number Diff line number Diff line change
Expand Up @@ -4007,6 +4007,9 @@ Here are some things you can try to get started.
<message name="IDS_ASH_SCREEN_CAPTURE_SHOW_CAMERA_USER_NUDGE" desc="The message shown in a toast widget to nudge the user and alert them to check out the new settings that allow them to show camera during video recording.">
You can now record yourself and your screen at the same time
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_SURFACE_TOO_SMALL_USER_NUDGE" desc="The message shown in a toast widget to alert the user that the current capture surface is too small to show the camera preview.">
Region is too small to fit camera
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_TOOLTIP_COLLAPSE_SELFIE_CAMERA" desc="Tooltip of the collapse resize button for screen capture selfie camera.">
Collapse camera
</message>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
20b537efce6190a3c41db3f984008536ebf385b4
125 changes: 22 additions & 103 deletions ash/capture_mode/capture_mode_camera_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ constexpr base::TimeDelta kCameraPreviewFadeOutDuration =
constexpr base::TimeDelta kCameraPreviewFadeInDuration =
base::Milliseconds(150);

constexpr float kCameraPreviewScaleUpFactor = 0.8f;

// Defines a map type to map a camera model ID (or display name) to the number
// of cameras of that model that are currently connected.
using ModelIdToCountMap = std::map<std::string, int>;
Expand Down Expand Up @@ -349,6 +347,14 @@ class CameraPreviewTargeter : public aura::WindowTargeter {
aura::Window* const camera_preview_window_;
};

capture_mode_util::AnimationParams BuildCameraVisibilityAnimationParams(
bool target_visibility,
bool apply_scale_up_animation) {
return {target_visibility ? kCameraPreviewFadeInDuration
: kCameraPreviewFadeOutDuration,
gfx::Tween::LINEAR, apply_scale_up_animation};
}

} // namespace

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -547,12 +553,22 @@ void CaptureModeCameraController::MaybeUpdatePreviewWidget(bool animate) {
CalculatePreviewWidgetTargetBounds(confine_bounds, size_specs.size),
animate);

const bool did_visibility_change = SetCameraPreviewVisibility(
size_specs.should_be_visible, should_animate_visibility);
const bool did_visibility_change = capture_mode_util::SetWidgetVisibility(
camera_preview_widget_.get(), size_specs.should_be_visible,
!should_animate_visibility
? absl::nullopt
: absl::make_optional<capture_mode_util::AnimationParams>(
BuildCameraVisibilityAnimationParams(
/*target_visibility=*/size_specs.should_be_visible,
/*apply_scale_up_animation=*/is_first_bounds_update_)));

if (controller->IsActive() && (did_visibility_change || did_bounds_change)) {
if (controller->IsActive() && !controller->is_recording_in_progress()) {
controller->capture_mode_session()
->OnCameraPreviewBoundsOrVisibilityChanged();
->OnCameraPreviewBoundsOrVisibilityChanged(
/*capture_surface_became_too_small=*/size_specs
.is_surface_too_small,
/*did_bounds_or_visibility_change=*/did_visibility_change ||
did_bounds_change);
}

if (did_bounds_change) {
Expand Down Expand Up @@ -1017,103 +1033,6 @@ void CaptureModeCameraController::RunPostRefreshCameraPreview(
}
}

bool CaptureModeCameraController::SetCameraPreviewVisibility(
bool target_visibility,
bool animate) {
DCHECK(camera_preview_widget_);

// Note that we use `aura::Window::TargetVisibility()` rather than
// `views::Widget::IsVisible()` (which in turn uses
// `aura::Window::IsVisible()`). The reason is because the latter takes into
// account whether window's layer is drawn or not. We want to calculate the
// current visibility only based on the actual visibility of the window
// itself, so that we can correctly compare it against `target_visibility`.
// Note that the preview may be a child of the unparented container (which is
// always hidden), yet the preview's window is shown.
const bool current_visibility =
camera_preview_widget_->GetNativeWindow()->TargetVisibility() &&
camera_preview_widget_->GetLayer()->GetTargetOpacity() > 0.f;
if (target_visibility == current_visibility)
return false;

if (animate) {
if (target_visibility)
FadeInCameraPreview();
else
FadeOutCameraPreview();
} else {
if (target_visibility)
camera_preview_widget_->Show();
else
camera_preview_widget_->Hide();
}

capture_mode_util::TriggerAccessibilityAlertSoon(
current_visibility ? IDS_ASH_SCREEN_CAPTURE_CAMERA_PREVIEW_HIDDEN
: IDS_ASH_SCREEN_CAPTURE_CAMERA_PREVIEW_ON);
return true;
}

void CaptureModeCameraController::FadeInCameraPreview() {
DCHECK(camera_preview_widget_);
auto* layer = camera_preview_widget_->GetLayer();
DCHECK(!camera_preview_widget_->GetNativeWindow()->TargetVisibility() ||
layer->GetTargetOpacity() < 1.f);

if (!camera_preview_widget_->GetNativeWindow()->TargetVisibility())
camera_preview_widget_->Show();
if (layer->opacity() == 1.f)
layer->SetOpacity(0.f);

if (is_first_bounds_update_) {
layer->SetTransform(capture_mode_util::GetScaleTransformAboutCenter(
layer, kCameraPreviewScaleUpFactor));
}

views::AnimationBuilder builder;
auto& animation_sequence_block =
builder
.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
.Once()
.SetDuration(kCameraPreviewFadeInDuration)
.SetOpacity(layer, 1.f, gfx::Tween::LINEAR);

// We should only set transform here if `is_first_bounds_update_` is true,
// otherwise, it may mess up with the snap animation in
// `SetCameraPreviewBounds`.
if (is_first_bounds_update_) {
animation_sequence_block.SetTransform(layer, gfx::Transform(),
gfx::Tween::ACCEL_20_DECEL_100);
}
}

void CaptureModeCameraController::FadeOutCameraPreview() {
DCHECK(camera_preview_widget_);
DCHECK(camera_preview_widget_->GetNativeWindow()->TargetVisibility());

auto* layer = camera_preview_widget_->GetLayer();
DCHECK_EQ(layer->GetTargetOpacity(), 1.f);

views::AnimationBuilder()
.OnEnded(base::BindOnce(
[](base::WeakPtr<CaptureModeCameraController> controller) {
if (!controller || !controller->camera_preview_widget_)
return;
// Please notice, the order matters here. If we set the layer's
// opacity back to 1.f before calling `Hide`, flickering can be
// seen.
controller->camera_preview_widget_->Hide();
controller->camera_preview_widget_->GetLayer()->SetOpacity(1.f);
},
weak_ptr_factory_.GetWeakPtr()))
.SetPreemptionStrategy(
ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET)
.Once()
.SetDuration(kCameraPreviewFadeOutDuration)
.SetOpacity(layer, 0.f, gfx::Tween::LINEAR);
}

bool CaptureModeCameraController::SetCameraPreviewBounds(
const gfx::Rect& target_bounds,
bool animate) {
Expand Down
10 changes: 0 additions & 10 deletions ash/capture_mode/capture_mode_camera_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,16 +314,6 @@ class ASH_EXPORT CaptureModeCameraController
// panels.
void RunPostRefreshCameraPreview(bool was_preview_visible_before);

// Sets the visibility of the camera preview to the given `target_visibility`
// and returns true only if the `target_visibility` is different than the
// current.
bool SetCameraPreviewVisibility(bool target_visibility, bool animate);

// Fades in or out the `camera_preview_widget_` and updates its visibility
// accordingly.
void FadeInCameraPreview();
void FadeOutCameraPreview();

// Sets the given `target_bounds` on the camera preview widget, potentially
// animating to it if `animate` is true. Returns true if the bounds actually
// changed from the current.
Expand Down
7 changes: 6 additions & 1 deletion ash/capture_mode/capture_mode_camera_preview_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "ash/accessibility/scoped_a11y_override_window_setter.h"
#include "ash/capture_mode/capture_mode_constants.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/capture_mode/capture_mode_session.h"
#include "ash/capture_mode/capture_mode_util.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/shell.h"
Expand Down Expand Up @@ -124,7 +125,11 @@ CameraPreviewView::CameraPreviewView(
UpdateResizeButtonTooltip();
}

CameraPreviewView::~CameraPreviewView() = default;
CameraPreviewView::~CameraPreviewView() {
auto* controller = CaptureModeController::Get();
if (controller->IsActive() && !controller->is_recording_in_progress())
controller->capture_mode_session()->OnCameraPreviewDestroyed();
}

void CameraPreviewView::SetIsCollapsible(bool value) {
if (value != is_collapsible_) {
Expand Down

0 comments on commit a5ce126

Please sign in to comment.