0

sunfish: Show error when trying to use Sunfish while offline.

If the user clicks the search button or tries to select a region in
sunfish mode while they are offline, show an error in the action
container.

Bug: b:378582420, b:391713973
Change-Id: I4df7482abeb7ef25e5a084f7b1c6855120998de9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6217704
Reviewed-by: Elijah Hewer <hewer@chromium.org>
Commit-Queue: Michelle Chen <michellegc@google.com>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1416531}
This commit is contained in:
Michelle Chen
2025-02-05 16:43:02 -08:00
committed by Chromium LUCI CQ
parent e788f23975
commit 29d4fb321b
9 changed files with 117 additions and 1 deletions

@ -6850,6 +6850,13 @@ Here are some things you can try to get started.
<message name="IDS_ASH_SCREEN_CAPTURE_TEXT_COPIED_TOAST" desc="The message shown on a toast to indicate text was copied to the user's clipboard from the contents of a screenshot.">
Text copied to Clipboard
</message>
<!-- TODO: crbug.com/375967525 - Finalize this string and mark it as translateable -->
<message name="IDS_ASH_SCREEN_CAPTURE_MORE_ACTIONS_UNAVAILABLE_OFFLINE_ERROR" desc="The error message shown to indicate to the user that some actions (e.g. search) are not available while offline." translateable="false">
More actions unavailable offline
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_ACTION_ATTEMPTED_OFFLINE_ERROR" desc="The error message shown if the user is offline while attempting an action that requires an internet connection.">
Check your internet and try again
</message>
<!-- Scanner -->
<!-- TODO: crbug.com/375967525 - Finalize these strings and mark them as translateable -->

@ -0,0 +1 @@
d0b52723ed1f70209c282cbbbb3733982a7328d3

@ -5,6 +5,7 @@
#ifndef ASH_CAPTURE_MODE_BASE_CAPTURE_MODE_SESSION_H_
#define ASH_CAPTURE_MODE_BASE_CAPTURE_MODE_SESSION_H_
#include <string>
#include <vector>
#include "ash/ash_export.h"
@ -206,6 +207,10 @@ class ASH_EXPORT BaseCaptureModeSession : public ui::LayerOwner,
virtual void OnScannerActionsFetched(
ScannerSession::FetchActionsResponse actions_response) = 0;
// Shows `error_message` in the action container.
virtual void ShowActionContainerError(
const std::u16string& error_message) = 0;
// ShellObserver:
void OnRootWindowWillShutdown(aura::Window* root_window) override;

@ -546,6 +546,19 @@ bool ShouldSendRegionSearch(PerformCaptureType capture_type) {
capture_type == PerformCaptureType::kSearch);
}
// Returns true if the capture type requires a network connection.
bool CaptureTypeRequiresNetworkConnection(PerformCaptureType capture_type) {
switch (capture_type) {
case PerformCaptureType::kCapture:
case PerformCaptureType::kTextDetection:
return false;
case PerformCaptureType::kSearch:
case PerformCaptureType::kScanner:
case PerformCaptureType::kSunfish:
return true;
}
}
// Returns the target panel bounds in screen coordinates.
gfx::Rect CalculateSearchResultPanelScreenBounds(
const gfx::Rect& work_area_in_screen,
@ -1118,6 +1131,13 @@ void CaptureModeController::CaptureScreenshotOfGivenWindow(
void CaptureModeController::PerformCapture(PerformCaptureType capture_type) {
DCHECK(IsActive());
if (CaptureTypeRequiresNetworkConnection(capture_type) &&
delegate_->IsNetworkConnectionOffline()) {
capture_mode_session_->ShowActionContainerError(l10n_util::GetStringUTF16(
IDS_ASH_SCREEN_CAPTURE_ACTION_ATTEMPTED_OFFLINE_ERROR));
return;
}
if (pending_dlp_check_)
return;

@ -1496,6 +1496,16 @@ void CaptureModeSession::OnScannerActionsFetched(
}
}
void CaptureModeSession::ShowActionContainerError(
const std::u16string& error_message) {
if (!action_container_widget_) {
return;
}
CHECK(action_container_view_);
action_container_view_->ShowErrorView(error_message);
UpdateActionContainerWidget();
}
void CaptureModeSession::OnDisclaimerDeclined() {
RecordScannerFeatureUserState(
ScannerFeatureUserState::kConsentDisclaimerRejected);
@ -3303,7 +3313,8 @@ CaptureModeSession::ShowDefaultActionButtonsOrPerformSearch() {
if (active_behavior_->ShouldShowDefaultActionButtonsAfterRegionSelected() &&
features::IsSunfishFeatureEnabled()) {
if (controller_->IsNetworkConnectionOffline()) {
// TODO(crbug.com/391713973): Show an error.
ShowActionContainerError(l10n_util::GetStringUTF16(
IDS_ASH_SCREEN_CAPTURE_MORE_ACTIONS_UNAVAILABLE_OFFLINE_ERROR));
} else {
RecordSearchButtonShown();
// TODO(crbug.com/388898754): Finalize and translate the search button

@ -196,6 +196,7 @@ class ASH_EXPORT CaptureModeSession
base::RepeatingClosure accept_callback) override;
void OnScannerActionsFetched(
ScannerSession::FetchActionsResponse actions_response) override;
void ShowActionContainerError(const std::u16string& error_message) override;
gfx::Rect GetFeedbackWidgetScreenBounds() const override;
// ui::LayerDelegate:

@ -141,6 +141,9 @@ void NullCaptureModeSession::MaybeShowScannerDisclaimer(
void NullCaptureModeSession::OnScannerActionsFetched(
ScannerSession::FetchActionsResponse actions_response) {}
void NullCaptureModeSession::ShowActionContainerError(
const std::u16string& error_message) {}
void NullCaptureModeSession::InitInternal() {
layer()->SetName("NullCaptureModeSession");
}

@ -62,6 +62,7 @@ class ASH_EXPORT NullCaptureModeSession : public BaseCaptureModeSession {
base::RepeatingClosure accept_callback) override;
void OnScannerActionsFetched(
ScannerSession::FetchActionsResponse actions_response) override;
void ShowActionContainerError(const std::u16string& error_message) override;
gfx::Rect GetFeedbackWidgetScreenBounds() const override;
private:

@ -14,6 +14,7 @@
#include "ash/app_list/views/app_list_bubble_view.h"
#include "ash/app_list/views/app_list_view.h"
#include "ash/app_list/views/search_box_view.h"
#include "ash/capture_mode/action_button_container_view.h"
#include "ash/capture_mode/action_button_view.h"
#include "ash/capture_mode/base_capture_mode_session.h"
#include "ash/capture_mode/capture_button_view.h"
@ -2272,11 +2273,77 @@ TEST_F(SunfishTest, SearchButtonNotShownWhenOffline) {
/*release_mouse=*/true, /*verify_region=*/true);
WaitForCaptureModeWidgetsVisible();
// The search button should not be shown, and an error should be shown
// instead.
auto* session =
static_cast<CaptureModeSession*>(controller->capture_mode_session());
CaptureModeSessionTestApi session_test_api(session);
EXPECT_FALSE(
session_test_api.GetButtonWithViewID(ActionButtonViewID::kSearchButton));
ActionButtonContainerView::ErrorView* error_view =
session_test_api.GetActionContainerErrorView();
ASSERT_TRUE(error_view);
EXPECT_TRUE(error_view->GetVisible());
}
// Tests that selecting a region in Sunfish mode shows an error when the network
// connection is offline.
TEST_F(SunfishTest, SelectingRegionInSunfishModeShowsErrorIfOffline) {
auto* controller = CaptureModeController::Get();
controller->StartSunfishSession();
auto* test_delegate =
static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
ON_CALL(*test_delegate, IsNetworkConnectionOffline)
.WillByDefault(Return(true));
SelectCaptureModeRegion(GetEventGenerator(), gfx::Rect(0, 0, 50, 200),
/*release_mouse=*/true, /*verify_region=*/true);
WaitForCaptureModeWidgetsVisible();
// An error should be shown.
auto* session =
static_cast<CaptureModeSession*>(controller->capture_mode_session());
CaptureModeSessionTestApi session_test_api(session);
ActionButtonContainerView::ErrorView* error_view =
session_test_api.GetActionContainerErrorView();
ASSERT_TRUE(error_view);
EXPECT_TRUE(error_view->GetVisible());
}
// Tests that pressing the search button shows an error when the network
// connection is offline.
TEST_F(SunfishTest, PressingSearchButtonShowsErrorIfOffline) {
// Start default capture mode.
auto* controller =
StartCaptureSession(CaptureModeSource::kRegion, CaptureModeType::kImage);
// Simulate the network being online initially, so that the search button
// will appear when a region is selected.
auto* test_delegate =
static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing());
ON_CALL(*test_delegate, IsNetworkConnectionOffline)
.WillByDefault(Return(false));
SelectCaptureModeRegion(GetEventGenerator(), gfx::Rect(100, 100, 600, 500),
/*release_mouse=*/true, /*verify_region=*/true);
WaitForCaptureModeWidgetsVisible();
auto* session =
static_cast<CaptureModeSession*>(controller->capture_mode_session());
CaptureModeSessionTestApi session_test_api(session);
ActionButtonView* search_button =
session_test_api.GetButtonWithViewID(ActionButtonViewID::kSearchButton);
ASSERT_TRUE(search_button);
// Simulate the network disconnecting before clicking on the search button.
ON_CALL(*test_delegate, IsNetworkConnectionOffline)
.WillByDefault(Return(true));
LeftClickOn(search_button);
// The session should still be active and an error should be shown.
ASSERT_TRUE(controller->IsActive());
ActionButtonContainerView::ErrorView* error_view =
session_test_api.GetActionContainerErrorView();
ASSERT_TRUE(error_view);
EXPECT_TRUE(error_view->GetVisible());
}
using SunfishMultiDisplayTest = SunfishTest;