FaceGaze: Add DLC notifications
In this change, we add logic to show a notification when the facegaze-assets DLC succeeds/fails to download. This follows the pattern used for other accessibility-related DLCs. We also add prefs to ensure that each notification is shown at most one time. Bug: b:309121742 Change-Id: Idfe32f39f0d0402ccef38e5e792b449de0393d50 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5730872 Reviewed-by: Xiaoqian Dai <xdai@chromium.org> Reviewed-by: Amanda Lin Dietz <aldietz@google.com> Reviewed-by: Ahmed Mehfooz <amehfooz@chromium.org> Commit-Queue: Akihiro Ota <akihiroota@chromium.org> Cr-Commit-Position: refs/heads/main@{#1333687}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
ff1876086d
commit
83e9072f40
ash
accessibility
ash_strings.grdash_strings_grd
IDS_ASH_A11Y_FACEGAZE_ASSETS_DOWNLOADED_DESC.png.sha1IDS_ASH_A11Y_FACEGAZE_ASSETS_DOWNLOADED_TITLE.png.sha1IDS_ASH_A11Y_FACEGAZE_ASSETS_FAILED_DESC.png.sha1IDS_ASH_A11Y_FACEGAZE_ASSETS_FAILED_TITLE.png.sha1
constants
public
chrome/browser/ash/accessibility
@ -295,6 +295,8 @@ constexpr const char* const kCopiedOnSigninAccessibilityPrefs[]{
|
||||
prefs::kDictationNoDlcsDownloadedNotificationHasBeenShown,
|
||||
prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2,
|
||||
prefs::kSelectToSpeakAcceleratorDialogHasBeenAccepted,
|
||||
prefs::kFaceGazeDlcSuccessNotificationHasBeenShown,
|
||||
prefs::kFaceGazeDlcFailureNotificationHasBeenShown,
|
||||
};
|
||||
|
||||
// List of switch access accessibility prefs that are to be copied (if changed
|
||||
@ -494,6 +496,21 @@ void ShowAccessibilityNotification(
|
||||
pinned = false;
|
||||
// Use CRITICAL_WARNING to force the notification color to red.
|
||||
warning = message_center::SystemNotificationWarningLevel::CRITICAL_WARNING;
|
||||
} else if (type == A11yNotificationType::kFaceGazeAssetsDownloaded) {
|
||||
title = l10n_util::GetStringUTF16(
|
||||
IDS_ASH_A11Y_FACEGAZE_ASSETS_DOWNLOADED_TITLE);
|
||||
text =
|
||||
l10n_util::GetStringUTF16(IDS_ASH_A11Y_FACEGAZE_ASSETS_DOWNLOADED_DESC);
|
||||
catalog_name = NotificationCatalogName::kFaceGazeAssetsDownloaded;
|
||||
pinned = false;
|
||||
} else if (type == A11yNotificationType::kFaceGazeAssetsFailed) {
|
||||
title =
|
||||
l10n_util::GetStringUTF16(IDS_ASH_A11Y_FACEGAZE_ASSETS_FAILED_TITLE);
|
||||
text = l10n_util::GetStringUTF16(IDS_ASH_A11Y_FACEGAZE_ASSETS_FAILED_DESC);
|
||||
catalog_name = NotificationCatalogName::kFaceGazeAssetsFailed;
|
||||
pinned = false;
|
||||
// Use CRITICAL_WARNING to force the notification color to red.
|
||||
warning = message_center::SystemNotificationWarningLevel::CRITICAL_WARNING;
|
||||
} else if (type == A11yNotificationType::kSwitchAccessEnabled) {
|
||||
title = l10n_util::GetStringUTF16(
|
||||
IDS_ASH_STATUS_TRAY_SWITCH_ACCESS_ENABLED_TITLE);
|
||||
@ -1201,6 +1218,10 @@ void AccessibilityController::RegisterProfilePrefs(
|
||||
prefs::kDisplayRotationAcceleratorDialogHasBeenAccepted2, false);
|
||||
registry->RegisterBooleanPref(prefs::kShouldAlwaysShowAccessibilityMenu,
|
||||
false);
|
||||
registry->RegisterBooleanPref(
|
||||
prefs::kFaceGazeDlcSuccessNotificationHasBeenShown, false);
|
||||
registry->RegisterBooleanPref(
|
||||
prefs::kFaceGazeDlcFailureNotificationHasBeenShown, false);
|
||||
|
||||
registry->RegisterBooleanPref(prefs::kAccessibilityColorCorrectionEnabled,
|
||||
false);
|
||||
@ -3247,6 +3268,33 @@ void AccessibilityController::ShowNotificationForDictation(
|
||||
notification_type, std::vector<std::u16string>{display_language}));
|
||||
}
|
||||
|
||||
void AccessibilityController::ShowNotificationForFaceGaze(
|
||||
FaceGazeNotificationType type) {
|
||||
A11yNotificationType notification_type;
|
||||
std::string notification_shown_pref;
|
||||
switch (type) {
|
||||
case FaceGazeNotificationType::kDlcSucceeded:
|
||||
notification_type = A11yNotificationType::kFaceGazeAssetsDownloaded;
|
||||
notification_shown_pref =
|
||||
prefs::kFaceGazeDlcSuccessNotificationHasBeenShown;
|
||||
break;
|
||||
case FaceGazeNotificationType::kDlcFailed:
|
||||
notification_type = A11yNotificationType::kFaceGazeAssetsFailed;
|
||||
notification_shown_pref =
|
||||
prefs::kFaceGazeDlcFailureNotificationHasBeenShown;
|
||||
break;
|
||||
}
|
||||
|
||||
if (active_user_prefs_->GetBoolean(notification_shown_pref)) {
|
||||
// Do not show notifications more than once.
|
||||
return;
|
||||
}
|
||||
|
||||
active_user_prefs_->SetBoolean(notification_shown_pref, true);
|
||||
ShowAccessibilityNotification(A11yNotificationWrapper(
|
||||
notification_type, std::vector<std::u16string>()));
|
||||
}
|
||||
|
||||
AccessibilityController::A11yNotificationWrapper::A11yNotificationWrapper() =
|
||||
default;
|
||||
AccessibilityController::A11yNotificationWrapper::A11yNotificationWrapper(
|
||||
|
@ -94,6 +94,10 @@ enum class A11yNotificationType {
|
||||
kDicationOnlyPumpkinDownloaded,
|
||||
// Shown when the SODA DLC (but no other DLCs) have downloaded.
|
||||
kDictationOnlySodaDownloaded,
|
||||
// Shown when the facegaze-assets DLC has successfully downloaded.
|
||||
kFaceGazeAssetsDownloaded,
|
||||
// Shown when the facegaze-assets DLC failed to download.
|
||||
kFaceGazeAssetsFailed,
|
||||
// Shown when braille display is connected while spoken feedback is not
|
||||
// enabled yet. Note: in this case braille display connected would enable
|
||||
// spoken feedback.
|
||||
@ -568,6 +572,9 @@ class ASH_EXPORT AccessibilityController : public SessionObserver,
|
||||
const std::optional<std::u16string>& text,
|
||||
const std::optional<std::vector<DictationBubbleHintType>>& hints);
|
||||
|
||||
// Shows a notification notifying the user about the FaceGaze DLC download.
|
||||
void ShowNotificationForFaceGaze(FaceGazeNotificationType type);
|
||||
|
||||
// Cancels all of spoken feedback's current and queued speech immediately.
|
||||
void SilenceSpokenFeedback();
|
||||
|
||||
|
@ -1808,6 +1808,41 @@ TEST_F(AccessibilityControllerTest,
|
||||
ASSERT_EQ(nullptr, controller->GetDisableTrackpadEventRewriterForTest());
|
||||
}
|
||||
|
||||
TEST_F(AccessibilityControllerTest, FaceGazeNotificationsOnlyShownOnce) {
|
||||
PrefService* prefs =
|
||||
Shell::Get()->session_controller()->GetLastActiveUserPrefService();
|
||||
AccessibilityController* controller =
|
||||
Shell::Get()->accessibility_controller();
|
||||
ASSERT_FALSE(
|
||||
prefs->GetBoolean(prefs::kFaceGazeDlcSuccessNotificationHasBeenShown));
|
||||
ASSERT_FALSE(
|
||||
prefs->GetBoolean(prefs::kFaceGazeDlcFailureNotificationHasBeenShown));
|
||||
|
||||
controller->ShowNotificationForFaceGaze(
|
||||
FaceGazeNotificationType::kDlcSucceeded);
|
||||
ASSERT_EQ(1u, MessageCenter::Get()->GetVisibleNotifications().size());
|
||||
ASSERT_TRUE(
|
||||
prefs->GetBoolean(prefs::kFaceGazeDlcSuccessNotificationHasBeenShown));
|
||||
message_center::MessageCenter::Get()->RemoveAllNotifications(
|
||||
/*by_user=*/false, message_center::MessageCenter::RemoveType::ALL);
|
||||
|
||||
// The success notification shouldn't be shown again.
|
||||
controller->ShowNotificationForFaceGaze(
|
||||
FaceGazeNotificationType::kDlcSucceeded);
|
||||
ASSERT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
|
||||
|
||||
controller->ShowNotificationForFaceGaze(FaceGazeNotificationType::kDlcFailed);
|
||||
ASSERT_EQ(1u, MessageCenter::Get()->GetVisibleNotifications().size());
|
||||
ASSERT_TRUE(
|
||||
prefs->GetBoolean(prefs::kFaceGazeDlcFailureNotificationHasBeenShown));
|
||||
message_center::MessageCenter::Get()->RemoveAllNotifications(
|
||||
/*by_user=*/false, message_center::MessageCenter::RemoveType::ALL);
|
||||
|
||||
// The failure notification shouldn't be shown again.
|
||||
controller->ShowNotificationForFaceGaze(FaceGazeNotificationType::kDlcFailed);
|
||||
ASSERT_EQ(0u, MessageCenter::Get()->GetVisibleNotifications().size());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
enum class TestUserLoginType {
|
||||
|
@ -6885,6 +6885,18 @@ Here are some things you can try to get started.
|
||||
<message name="IDS_ASH_A11Y_DICTATION_NOTIFICATION_ONLY_SODA_DOWNLOADED_DESC" desc="The description for a notification that is shown when speech recognition files download successfully. This notification is only shown if speech recognition assets are downloaded and command parsing assets are not.">
|
||||
Speech is processed locally and dictation works offline, but some voice commands won’t work.
|
||||
</message>
|
||||
<message name="IDS_ASH_A11Y_FACEGAZE_ASSETS_DOWNLOADED_TITLE" desc="The title for a notification that is shown when the facegaze-assets DLC is successfully downloaded.">
|
||||
Face control files downloaded
|
||||
</message>
|
||||
<message name="IDS_ASH_A11Y_FACEGAZE_ASSETS_DOWNLOADED_DESC" desc="The description for a notification that is shown when the facegaze-assets DLC is successfully downloaded.">
|
||||
Face control will be available to other users on the device
|
||||
</message>
|
||||
<message name="IDS_ASH_A11Y_FACEGAZE_ASSETS_FAILED_TITLE" desc="The title for a notification that is shown when the facegaze-assets DLC fails to download.">
|
||||
Couldn't download face control files
|
||||
</message>
|
||||
<message name="IDS_ASH_A11Y_FACEGAZE_ASSETS_FAILED_DESC" desc="The description for a notification that is shown when the facegaze-assets DLC fails to download.">
|
||||
Try again later
|
||||
</message>
|
||||
|
||||
<!-- Debugd notification strings -->
|
||||
<message name="IDS_ASH_DEBUG_PACKET_CAPTURE_STARTED" desc="The label used for the notification to indicate network packet capture operation has started and network information is being collected on the device.">
|
||||
|
@ -0,0 +1 @@
|
||||
8d5a2968967cb0c06e796765686c9957a27a6958
|
@ -0,0 +1 @@
|
||||
8d5a2968967cb0c06e796765686c9957a27a6958
|
@ -0,0 +1 @@
|
||||
e4264aeb054fe6398c45abf9b5f66e9e07a21dc7
|
@ -0,0 +1 @@
|
||||
e4264aeb054fe6398c45abf9b5f66e9e07a21dc7
|
@ -814,6 +814,14 @@ inline constexpr char kAccessibilityFaceGazeActionsEnabled[] =
|
||||
// separately or whether speeds in all directions should be adjusted together.
|
||||
inline constexpr char kAccessibilityFaceGazeAdjustSpeedSeparately[] =
|
||||
"settings.a11y.face_gaze.adjust_speed_separately";
|
||||
// A boolean pref which indicates whether the FaceGaze DLC success notification
|
||||
// has ever been shown.
|
||||
inline constexpr char kFaceGazeDlcSuccessNotificationHasBeenShown[] =
|
||||
"settings.a11y.face_gaze.dlc_success_notification_has_been_shown";
|
||||
// A boolean pref which indicates whether the FaceGaze DLC failure notification
|
||||
// has ever been shown.
|
||||
inline constexpr char kFaceGazeDlcFailureNotificationHasBeenShown[] =
|
||||
"settings.a11y.face_gaze.dlc_failure_notification_has_been_shown";
|
||||
|
||||
// A boolean pref which determines whether the accessibility menu shows
|
||||
// regardless of the state of a11y features.
|
||||
|
@ -200,7 +200,9 @@ enum class NotificationCatalogName {
|
||||
kAudioSelection = 181,
|
||||
kExtendedUpdatesAvailable = 182,
|
||||
kOnDeviceAppControls = 183,
|
||||
kMaxValue = kOnDeviceAppControls
|
||||
kFaceGazeAssetsDownloaded = 184,
|
||||
kFaceGazeAssetsFailed = 185,
|
||||
kMaxValue = kFaceGazeAssetsFailed
|
||||
};
|
||||
|
||||
// A living catalog that registers system nudges.
|
||||
|
@ -246,6 +246,12 @@ enum class DictationNotificationType {
|
||||
kOnlyPumpkinDownloaded,
|
||||
};
|
||||
|
||||
// The types of notifications that can be shown by FaceGaze.
|
||||
enum class FaceGazeNotificationType {
|
||||
kDlcFailed,
|
||||
kDlcSucceeded,
|
||||
};
|
||||
|
||||
// The types of accessibility-related toasts. This enum should be kept in sync
|
||||
// with chrome.accessibilityPrivate.ToastType.
|
||||
enum class AccessibilityToastType {
|
||||
|
@ -2813,7 +2813,8 @@ void AccessibilityManager::InstallFaceGazeAssets(
|
||||
base::BindOnce(&AccessibilityManager::OnFaceGazeAssetsInstalled,
|
||||
weak_ptr_factory_.GetWeakPtr()),
|
||||
/*on_progress=*/base::DoNothing(),
|
||||
/*on_error=*/base::DoNothing());
|
||||
base::BindOnce(&AccessibilityManager::OnFaceGazeAssetsFailed,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void AccessibilityManager::OnFaceGazeAssetsInstalled(
|
||||
@ -2832,6 +2833,8 @@ void AccessibilityManager::OnFaceGazeAssetsInstalled(
|
||||
? base::FilePath(root_path)
|
||||
: dlc_path_for_test_;
|
||||
|
||||
AccessibilityController::Get()->ShowNotificationForFaceGaze(
|
||||
FaceGazeNotificationType::kDlcSucceeded);
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE, {base::MayBlock()},
|
||||
base::BindOnce(&CreateFaceGazeAssets, base::FilePath(base_path)),
|
||||
@ -2839,6 +2842,16 @@ void AccessibilityManager::OnFaceGazeAssetsInstalled(
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void AccessibilityManager::OnFaceGazeAssetsFailed(std::string_view error) {
|
||||
AccessibilityController::Get()->ShowNotificationForFaceGaze(
|
||||
FaceGazeNotificationType::kDlcFailed);
|
||||
if (install_facegaze_assets_callback_.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::move(install_facegaze_assets_callback_).Run(std::nullopt);
|
||||
}
|
||||
|
||||
void AccessibilityManager::OnFaceGazeAssetsCreated(
|
||||
std::optional<FaceGazeAssets> assets) {
|
||||
if (install_facegaze_assets_callback_.is_null()) {
|
||||
|
@ -621,6 +621,7 @@ class AccessibilityManager
|
||||
|
||||
// Methods for managing the FaceGaze assets DLC.
|
||||
void OnFaceGazeAssetsInstalled(bool success, const std::string& root_path);
|
||||
void OnFaceGazeAssetsFailed(std::string_view error);
|
||||
void OnFaceGazeAssetsCreated(
|
||||
std::optional<::extensions::api::accessibility_private::FaceGazeAssets>
|
||||
assets);
|
||||
|
@ -1008,12 +1008,18 @@ class AccessibilityManagerDlcTest : public AccessibilityManagerTest {
|
||||
delete;
|
||||
|
||||
protected:
|
||||
void SetUpCommandLine(base::CommandLine* command_line) override {
|
||||
AccessibilityManagerTest::SetUpCommandLine(command_line);
|
||||
scoped_feature_list_.InitAndEnableFeature(
|
||||
::features::kAccessibilityFaceGaze);
|
||||
}
|
||||
|
||||
void SetUpOnMainThread() override {
|
||||
AccessibilityManagerTest::SetUpOnMainThread();
|
||||
UninstallSodaForTesting();
|
||||
EnsureSodaObservation();
|
||||
ClearMessageCenter();
|
||||
AssertMessageCenterEmpty();
|
||||
AccessibilityManagerTest::SetUpOnMainThread();
|
||||
}
|
||||
|
||||
void TearDownOnMainThread() override {
|
||||
@ -1039,7 +1045,7 @@ class AccessibilityManagerDlcTest : public AccessibilityManagerTest {
|
||||
// We require `install_pumpkin_callback_` to be set before `OnPumpkinError`
|
||||
// can be called.
|
||||
manager->install_pumpkin_callback_ = base::DoNothing();
|
||||
AccessibilityManager::Get()->OnPumpkinError("Error");
|
||||
manager->OnPumpkinError("Error");
|
||||
}
|
||||
|
||||
void OnPumpkinInstalled(bool success, const std::string& root_path) {
|
||||
@ -1051,6 +1057,20 @@ class AccessibilityManagerDlcTest : public AccessibilityManagerTest {
|
||||
AccessibilityManager::Get()->OnPumpkinDataCreated(std::move(data));
|
||||
}
|
||||
|
||||
void InstallFaceGazeAssetsAndWait() {
|
||||
base::RunLoop loop;
|
||||
AccessibilityManager::Get()->InstallFaceGazeAssets(base::DoNothing());
|
||||
loop.RunUntilIdle();
|
||||
}
|
||||
|
||||
void OnFaceGazeAssetsFailed() {
|
||||
AccessibilityManager* manager = AccessibilityManager::Get();
|
||||
// We require `install_facegaze_assets_callback_` to be set before
|
||||
// `OnFaceGazeAssetsFailed` can be called.
|
||||
manager->install_facegaze_assets_callback_ = base::DoNothing();
|
||||
manager->OnFaceGazeAssetsFailed("Error");
|
||||
}
|
||||
|
||||
speech::SodaInstaller* soda_installer() {
|
||||
return speech::SodaInstaller::GetInstance();
|
||||
}
|
||||
@ -1550,6 +1570,35 @@ IN_PROC_BROWSER_TEST_F(AccessibilityManagerDlcTest,
|
||||
OnPumpkinDataCreated(std::nullopt);
|
||||
}
|
||||
|
||||
// Ensures that the correct notification is shown when the facegaze-assets DLC
|
||||
// is successfully downloaded.
|
||||
IN_PROC_BROWSER_TEST_F(AccessibilityManagerDlcTest, FaceGazeAssetsSucceeded) {
|
||||
AccessibilityManager::Get()->EnableFaceGaze(true);
|
||||
InstallFaceGazeAssetsAndWait();
|
||||
|
||||
message_center::NotificationList::Notifications notifications =
|
||||
message_center::MessageCenter::Get()->GetVisibleNotifications();
|
||||
ASSERT_EQ(1u, notifications.size());
|
||||
ASSERT_EQ(u"Face control files downloaded",
|
||||
(*notifications.begin())->title());
|
||||
ASSERT_EQ(u"Face control will be available to other users on the device",
|
||||
(*notifications.begin())->message());
|
||||
}
|
||||
|
||||
// Ensures that the correct notification is shown when the facegaze-assets DLC
|
||||
// fails to download.
|
||||
IN_PROC_BROWSER_TEST_F(AccessibilityManagerDlcTest, FaceGazeAssetsFailed) {
|
||||
AccessibilityManager::Get()->EnableFaceGaze(true);
|
||||
OnFaceGazeAssetsFailed();
|
||||
|
||||
message_center::NotificationList::Notifications notifications =
|
||||
message_center::MessageCenter::Get()->GetVisibleNotifications();
|
||||
ASSERT_EQ(1u, notifications.size());
|
||||
ASSERT_EQ(u"Couldn't download face control files",
|
||||
(*notifications.begin())->title());
|
||||
ASSERT_EQ(u"Try again later", (*notifications.begin())->message());
|
||||
}
|
||||
|
||||
enum DictationDialogTestVariant {
|
||||
kOfflineEnabledAndAvailable,
|
||||
kOfflineEnabledAndUnavailable,
|
||||
|
Reference in New Issue
Block a user