0

scanner: Add "feedback enabled" pref

This will be used by enterprises to prevent feedback from being sent.
This blocks the feedback button from appearing in the toast, which is
the only way feedback can be sent.

Bug: b:391961194
Change-Id: I6a6a21002e0099b9f4d00c253f8362c8550fddfc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6196877
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Commit-Queue: Michael Cui <mlcui@google.com>
Reviewed-by: Michelle Chen <michellegc@google.com>
Cr-Commit-Position: refs/heads/main@{#1412043}
This commit is contained in:
Michael Cui
2025-01-27 18:37:54 -08:00
committed by Chromium LUCI CQ
parent b06b5913de
commit 04a5995a15
5 changed files with 75 additions and 9 deletions

@ -40,6 +40,7 @@
#include "ash/quick_insert/quick_insert_controller.h"
#include "ash/quick_pair/feature_status_tracker/scanning_enabled_provider.h"
#include "ash/quick_pair/keyed_service/quick_pair_mediator.h"
#include "ash/scanner/scanner_controller.h"
#include "ash/session/fullscreen_controller.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shelf/shelf_controller.h"
@ -180,6 +181,7 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry,
QuickInsertController::RegisterProfilePrefs(registry);
quick_pair::Mediator::RegisterProfilePrefs(registry);
RegisterSystemShortcutBehaviorProfilePrefs(registry);
ScannerController::RegisterProfilePrefs(registry);
ScreensaverImagesPolicyHandler::RegisterPrefs(registry);
ShelfController::RegisterProfilePrefs(registry);
SnoopingProtectionController::RegisterProfilePrefs(registry);

@ -2461,6 +2461,11 @@ inline constexpr char kSunfishEnabled[] = "ash.capture_mode.sunfish_enabled";
inline constexpr char kSunfishConsentDisclaimerAccepted[] =
"ash.capture_mode.sunfish_consent_disclaimer_accepted";
// A boolean pref that records whether users can submit feedback with Scanner.
// Intended to be managed by policy.
inline constexpr char kScannerFeedbackEnabled[] =
"ash.scanner.feedback_enabled";
// A dictionary that stores app icons' light vibrant colors.
inline constexpr char kAshAppIconLightVibrantColorCache[] =
"ash.app_icon_light_vibrant_color_cache";

@ -11,6 +11,7 @@
#include <utility>
#include <vector>
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/notification_utils.h"
#include "ash/public/cpp/scanner/scanner_delegate.h"
@ -263,6 +264,11 @@ ScannerController::ScannerController(std::unique_ptr<ScannerDelegate> delegate,
ScannerController::~ScannerController() = default;
// static
void ScannerController::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kScannerFeedbackEnabled, true);
}
void ScannerController::OnActiveUserSessionChanged(
const AccountId& account_id) {
scanner_session_ = nullptr;
@ -412,19 +418,26 @@ void ScannerController::OnActionFinished(
: u"Action succeeded";
ToastData toast_data(kScannerActionSuccessToastId,
ToastCatalogName::kScannerActionSuccess, toast_text);
toast_data.button_type = ToastData::ButtonType::kIconButton;
toast_data.button_text = u"Send feedback";
toast_data.button_icon = &kFeedbackIcon;
// TODO: b/367882164 - Pass in the account ID to this method to ensure that
// the feedback form is shown for the same account that performed the
// action.
const AccountId& account_id = session_controller_->GetActiveAccountId();
// TODO: b/259100049 - Change this to be `BindOnce` once
// `ToastData::button_callback` is migrated to be a `OnceClosure`.
toast_data.button_callback = base::BindRepeating(
&ScannerController::OpenFeedbackDialog, weak_ptr_factory_.GetWeakPtr(),
account_id, std::move(populated_action),
std::move(downscaled_jpeg_bytes));
PrefService* prefs =
session_controller_->GetUserPrefServiceForUser(account_id);
if (prefs && prefs->GetBoolean(prefs::kScannerFeedbackEnabled)) {
toast_data.button_type = ToastData::ButtonType::kIconButton;
toast_data.button_text = u"Send feedback";
toast_data.button_icon = &kFeedbackIcon;
// TODO: b/259100049 - Change this to be `BindOnce` once
// `ToastData::button_callback` is migrated to be a `OnceClosure`.
toast_data.button_callback = base::BindRepeating(
&ScannerController::OpenFeedbackDialog,
weak_ptr_factory_.GetWeakPtr(), account_id,
std::move(populated_action), std::move(downscaled_jpeg_bytes));
}
ToastManager::Get()->Show(std::move(toast_data));
} else {
// TODO: crbug.com/383926250 - The action failure text should depend on the

@ -17,6 +17,8 @@
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
class PrefRegistrySimple;
namespace manta::proto {
class ScannerAction;
}
@ -39,6 +41,8 @@ class ASH_EXPORT ScannerController : public SessionObserver {
ScannerController& operator=(const ScannerController&) = delete;
~ScannerController() override;
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
// SessionObserver:
void OnActiveUserSessionChanged(const AccountId& account_id) override;
@ -79,6 +83,8 @@ class ASH_EXPORT ScannerController : public SessionObserver {
// Opens a feedback dialog for an action that has been performed, and the
// (resized) screenshot which initiated the action.
// WARNING: This function does not check whether the account has feedback
// enabled or not!
void OpenFeedbackDialog(const AccountId& account_id,
manta::proto::ScannerAction action,
scoped_refptr<base::RefCountedMemory> screenshot);

@ -13,6 +13,7 @@
#include <vector>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/public/cpp/scanner/scanner_delegate.h"
#include "ash/public/cpp/scanner/scanner_enums.h"
#include "ash/public/cpp/scanner/scanner_feedback_info.h"
@ -463,6 +464,45 @@ TEST_F(ScannerControllerTest, ActionSuccessToastButtonOpensFeedbackDialog) {
})json"));
}
TEST_F(ScannerControllerTest, ActionSuccessToastDoesNotHaveButtonIfDisabled) {
Shell::Get()->session_controller()->GetActivePrefService()->SetBoolean(
prefs::kScannerFeedbackEnabled, false);
base::test::TestFuture<std::vector<ScannerActionViewModel>> actions_future;
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);
EXPECT_TRUE(scanner_controller->StartNewSession());
manta::proto::ScannerOutput output;
output.add_objects()
->add_actions()
->mutable_copy_to_clipboard()
->set_html_text("<b>Hello</b>");
FakeScannerProfileScopedDelegate& fake_profile_scoped_delegate =
*GetFakeScannerProfileScopedDelegate(*scanner_controller);
// Mock a successful action.
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionsForImage)
.WillOnce(RunOnceCallback<1>(
std::make_unique<manta::proto::ScannerOutput>(output),
manta::MantaStatus()));
EXPECT_CALL(fake_profile_scoped_delegate, FetchActionDetailsForImage)
.WillOnce(RunOnceCallback<2>(
std::make_unique<manta::proto::ScannerOutput>(output),
manta::MantaStatus{.status_code = manta::MantaStatusCode::kOk}));
// Fetch an action and execute it.
scanner_controller->FetchActionsForImage(/*jpeg_bytes=*/nullptr,
actions_future.GetCallback());
std::vector<ScannerActionViewModel> actions = actions_future.Take();
ASSERT_THAT(actions, SizeIs(1));
scanner_controller->ExecuteAction(actions[0]);
EXPECT_TRUE(ToastManager::Get()->IsToastShown(kScannerActionSuccessToastId));
ToastOverlay* overlay =
Shell::Get()->toast_manager()->GetCurrentOverlayForTesting();
ASSERT_TRUE(overlay);
views::Button* button = overlay->button_for_testing();
EXPECT_FALSE(button);
}
TEST_F(ScannerControllerTest, OpenFeedbackDialogCallsDelegate) {
ScannerController* scanner_controller = Shell::Get()->scanner_controller();
ASSERT_TRUE(scanner_controller);