[Live Caption] Display SODA download progress updates in quick settings.
Screenshots: - Soda install message in accessibility tray: https://screenshot.googleplex.com/9iRmn7Y6xpoVDxJ - Soda error message in audio settings tray: https://screenshot.googleplex.com/Az5xt44wAVTmKLy - Soda progress message in audio settings tray: https://screenshot.googleplex.com/5mnxpXcY6MMkP2A Bug: 1196105 Change-Id: Ie7b5708355b6269d5c37a340959e039750ac4227 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3217417 Reviewed-by: Akihiro Ota <akihiroota@chromium.org> Reviewed-by: James Cook <jamescook@chromium.org> Commit-Queue: Abigail Klein <abigailbklein@google.com> Cr-Commit-Position: refs/heads/main@{#987183}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
50c7624533
commit
e4c6b5ccb7
@@ -57,6 +57,7 @@
|
|||||||
#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
|
#include "chromeos/services/assistant/public/cpp/assistant_prefs.h"
|
||||||
#include "components/language/core/browser/pref_names.h"
|
#include "components/language/core/browser/pref_names.h"
|
||||||
#include "components/live_caption/pref_names.h"
|
#include "components/live_caption/pref_names.h"
|
||||||
|
#include "components/soda/constants.h"
|
||||||
|
|
||||||
namespace ash {
|
namespace ash {
|
||||||
|
|
||||||
@@ -117,6 +118,8 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry, bool for_test) {
|
|||||||
registry->RegisterBooleanPref(chromeos::prefs::kSuggestedContentEnabled,
|
registry->RegisterBooleanPref(chromeos::prefs::kSuggestedContentEnabled,
|
||||||
true);
|
true);
|
||||||
registry->RegisterBooleanPref(::prefs::kLiveCaptionEnabled, false);
|
registry->RegisterBooleanPref(::prefs::kLiveCaptionEnabled, false);
|
||||||
|
registry->RegisterStringPref(::prefs::kLiveCaptionLanguageCode,
|
||||||
|
speech::kUsEnglishLocale);
|
||||||
registry->RegisterStringPref(language::prefs::kApplicationLocale,
|
registry->RegisterStringPref(language::prefs::kApplicationLocale,
|
||||||
std::string());
|
std::string());
|
||||||
}
|
}
|
||||||
|
@@ -4377,13 +4377,13 @@ Here are some things you can try to get started.
|
|||||||
</message>
|
</message>
|
||||||
|
|
||||||
<!-- SODA Download strings -->
|
<!-- SODA Download strings -->
|
||||||
<message name="IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE" desc="Description explaining that the speech recognition library download has completed.">
|
<message name="IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE" desc="Description explaining that the speech recognition library download has completed.">
|
||||||
Speech files downloaded
|
Speech files downloaded
|
||||||
</message>
|
</message>
|
||||||
<message name="IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS" desc="Description explaining the progress for the speech recognition library download.">
|
<message name="IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS" desc="Description explaining the progress for the speech recognition library download.">
|
||||||
Downloading speech recognition files... <ph name="PERCENT">$1<ex>17</ex></ph>%
|
Downloading speech recognition files... <ph name="PERCENT">$1<ex>17</ex></ph>%
|
||||||
</message>
|
</message>
|
||||||
<message name="IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR" desc="Description explaining that there was an error with the speech recognition library download.">
|
<message name="IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR" desc="Description explaining that there was an error with the speech recognition library download.">
|
||||||
Can't download speech files. Try again later.
|
Can't download speech files. Try again later.
|
||||||
</message>
|
</message>
|
||||||
<message name="IDS_ASH_ACCESSIBILITY_DICTATION_BUTTON_TOOLTIP_SODA_DOWNLOADING" desc="A tooltip explaining that speech recognition files are downloading." >
|
<message name="IDS_ASH_ACCESSIBILITY_DICTATION_BUTTON_TOOLTIP_SODA_DOWNLOADING" desc="A tooltip explaining that speech recognition files are downloading." >
|
||||||
|
@@ -26,9 +26,11 @@
|
|||||||
#include "ash/system/tray/tri_view.h"
|
#include "ash/system/tray/tri_view.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/metrics/user_metrics.h"
|
#include "base/metrics/user_metrics.h"
|
||||||
|
#include "components/live_caption/pref_names.h"
|
||||||
#include "components/prefs/pref_service.h"
|
#include "components/prefs/pref_service.h"
|
||||||
#include "components/soda/soda_installer.h"
|
#include "components/soda/soda_installer.h"
|
||||||
#include "components/vector_icons/vector_icons.h"
|
#include "components/vector_icons/vector_icons.h"
|
||||||
|
#include "media/base/media_switches.h"
|
||||||
#include "ui/accessibility/accessibility_features.h"
|
#include "ui/accessibility/accessibility_features.h"
|
||||||
#include "ui/base/l10n/l10n_util.h"
|
#include "ui/base/l10n/l10n_util.h"
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
@@ -36,6 +38,8 @@
|
|||||||
#include "ui/views/controls/separator.h"
|
#include "ui/views/controls/separator.h"
|
||||||
|
|
||||||
namespace ash {
|
namespace ash {
|
||||||
|
namespace tray {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using ml::UserSettingsEvent;
|
using ml::UserSettingsEvent;
|
||||||
@@ -68,21 +72,47 @@ void LogUserAccessibilityEvent(UserSettingsEvent::Event::AccessibilityId id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
speech::LanguageCode GetDictationLocale() {
|
speech::LanguageCode GetSodaFeatureLocale(SodaFeature feature) {
|
||||||
std::string dictation_locale = speech::kUsEnglishLocale;
|
std::string feature_locale = speech::kUsEnglishLocale;
|
||||||
PrefService* pref_service =
|
PrefService* pref_service =
|
||||||
Shell::Get()->session_controller()->GetActivePrefService();
|
Shell::Get()->session_controller()->GetActivePrefService();
|
||||||
if (pref_service) {
|
if (pref_service) {
|
||||||
dictation_locale =
|
switch (feature) {
|
||||||
pref_service->GetString(prefs::kAccessibilityDictationLocale);
|
case SodaFeature::kDictation:
|
||||||
|
feature_locale =
|
||||||
|
pref_service->GetString(prefs::kAccessibilityDictationLocale);
|
||||||
|
break;
|
||||||
|
case SodaFeature::kLiveCaption:
|
||||||
|
feature_locale = ::prefs::GetLiveCaptionLanguageCode(pref_service);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return speech::GetLanguageCode(dictation_locale);
|
return speech::GetLanguageCode(feature_locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSodaFeatureEnabled(SodaFeature feature) {
|
||||||
|
AccessibilityControllerImpl* controller =
|
||||||
|
Shell::Get()->accessibility_controller();
|
||||||
|
switch (feature) {
|
||||||
|
case SodaFeature::kDictation:
|
||||||
|
return ::features::IsDictationOfflineAvailable() &&
|
||||||
|
controller->dictation().enabled();
|
||||||
|
case SodaFeature::kLiveCaption:
|
||||||
|
return controller->live_caption().enabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SodaFeatureHasUpdate(SodaFeature feature,
|
||||||
|
speech::LanguageCode language_code) {
|
||||||
|
// Only show updates for this feature if the language code applies to the SODA
|
||||||
|
// binary (encoded by by LanguageCode::kNone) or the language pack matching
|
||||||
|
// the feature locale.
|
||||||
|
return language_code == speech::LanguageCode::kNone ||
|
||||||
|
language_code == GetSodaFeatureLocale(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace tray {
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// ash::tray::AccessibilityDetailedView
|
// ash::tray::AccessibilityDetailedView
|
||||||
|
|
||||||
@@ -95,19 +125,27 @@ AccessibilityDetailedView::AccessibilityDetailedView(
|
|||||||
AppendAccessibilityList();
|
AppendAccessibilityList();
|
||||||
CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE);
|
CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE);
|
||||||
Layout();
|
Layout();
|
||||||
UpdateSodaInstallerObserverStatus();
|
|
||||||
|
if (!::features::IsDictationOfflineAvailable() &&
|
||||||
|
!media::IsLiveCaptionFeatureEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
|
||||||
|
if (soda_installer)
|
||||||
|
soda_installer->AddObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessibilityDetailedView::~AccessibilityDetailedView() {
|
AccessibilityDetailedView::~AccessibilityDetailedView() {
|
||||||
if (!::features::IsDictationOfflineAvailable())
|
if (!::features::IsDictationOfflineAvailable() &&
|
||||||
|
!media::IsLiveCaptionFeatureEnabled()) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
|
|
||||||
if (soda_installer) {
|
|
||||||
// `soda_installer` is not guaranteed to be valid, since it's possible for
|
|
||||||
// this class to out-live it.
|
|
||||||
soda_installer->RemoveObserver(this);
|
|
||||||
}
|
}
|
||||||
|
speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
|
||||||
|
// `soda_installer` is not guaranteed to be valid, since it's possible for
|
||||||
|
// this class to out-live it. This means that this class cannot use
|
||||||
|
// ScopedObservation and needs to manage removing the observer itself.
|
||||||
|
if (soda_installer)
|
||||||
|
soda_installer->RemoveObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessibilityDetailedView::OnAccessibilityStatusChanged() {
|
void AccessibilityDetailedView::OnAccessibilityStatusChanged() {
|
||||||
@@ -133,7 +171,6 @@ void AccessibilityDetailedView::OnAccessibilityStatusChanged() {
|
|||||||
dictation_enabled_ = controller->dictation().enabled();
|
dictation_enabled_ = controller->dictation().enabled();
|
||||||
TrayPopupUtils::UpdateCheckMarkVisibility(dictation_view_,
|
TrayPopupUtils::UpdateCheckMarkVisibility(dictation_view_,
|
||||||
dictation_enabled_);
|
dictation_enabled_);
|
||||||
UpdateSodaInstallerObserverStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (high_contrast_view_ && controller->IsHighContrastSettingVisibleInTray()) {
|
if (high_contrast_view_ && controller->IsHighContrastSettingVisibleInTray()) {
|
||||||
@@ -582,89 +619,66 @@ void AccessibilityDetailedView::ShowHelp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessibilityDetailedView::UpdateSodaInstallerObserverStatus() {
|
|
||||||
if (!::features::IsDictationOfflineAvailable())
|
|
||||||
return;
|
|
||||||
|
|
||||||
speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
|
|
||||||
if (!soda_installer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool dictation_enabled =
|
|
||||||
Shell::Get()->accessibility_controller()->dictation().enabled();
|
|
||||||
if (!dictation_enabled) {
|
|
||||||
soda_installer->RemoveObserver(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!soda_installer->IsSodaInstalled(GetDictationLocale())) {
|
|
||||||
// Make sure this view observes SODA installation.
|
|
||||||
soda_installer->AddObserver(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SodaInstaller::Observer:
|
// SodaInstaller::Observer:
|
||||||
void AccessibilityDetailedView::OnSodaInstalled(
|
void AccessibilityDetailedView::OnSodaInstalled(
|
||||||
speech::LanguageCode language_code) {
|
speech::LanguageCode language_code) {
|
||||||
if (language_code != GetDictationLocale())
|
std::u16string message = l10n_util::GetStringUTF16(
|
||||||
return;
|
IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE);
|
||||||
|
MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
|
||||||
// Show the success message if both the SODA binary and the language pack
|
MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message);
|
||||||
// matching the Dictation locale have been downloaded.
|
|
||||||
speech::SodaInstaller::GetInstance()->RemoveObserver(this);
|
|
||||||
AccessibilityControllerImpl* controller =
|
|
||||||
Shell::Get()->accessibility_controller();
|
|
||||||
if (dictation_view_ && controller->IsDictationSettingVisibleInTray()) {
|
|
||||||
dictation_view_->SetSubText(l10n_util::GetStringUTF16(
|
|
||||||
IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessibilityDetailedView::OnSodaError(
|
void AccessibilityDetailedView::OnSodaError(
|
||||||
speech::LanguageCode language_code) {
|
speech::LanguageCode language_code) {
|
||||||
if (language_code != speech::LanguageCode::kNone &&
|
std::u16string message = l10n_util::GetStringUTF16(
|
||||||
language_code != GetDictationLocale()) {
|
IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR);
|
||||||
return;
|
MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
|
||||||
}
|
MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message);
|
||||||
|
|
||||||
// Show the failed message if either the Dictation locale failed or the SODA
|
|
||||||
// binary failed (encoded by LanguageCode::kNone).
|
|
||||||
speech::SodaInstaller::GetInstance()->RemoveObserver(this);
|
|
||||||
AccessibilityControllerImpl* controller =
|
|
||||||
Shell::Get()->accessibility_controller();
|
|
||||||
if (dictation_view_ && controller->IsDictationSettingVisibleInTray()) {
|
|
||||||
dictation_view_->SetSubText(l10n_util::GetStringUTF16(
|
|
||||||
IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessibilityDetailedView::OnSodaProgress(
|
void AccessibilityDetailedView::OnSodaProgress(
|
||||||
speech::LanguageCode language_code,
|
speech::LanguageCode language_code,
|
||||||
int progress) {
|
int progress) {
|
||||||
if (language_code != speech::LanguageCode::kNone &&
|
std::u16string message = l10n_util::GetStringFUTF16Int(
|
||||||
language_code != GetDictationLocale()) {
|
IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS, progress);
|
||||||
return;
|
MaybeShowSodaMessage(SodaFeature::kDictation, language_code, message);
|
||||||
}
|
MaybeShowSodaMessage(SodaFeature::kLiveCaption, language_code, message);
|
||||||
|
}
|
||||||
|
|
||||||
// Only show the progress message if this applies to the SODA binary (encoded
|
void AccessibilityDetailedView::MaybeShowSodaMessage(
|
||||||
// by LanguageCode::kNone) or the language pack matching the Dictation locale.
|
SodaFeature feature,
|
||||||
|
speech::LanguageCode language_code,
|
||||||
|
std::u16string message) {
|
||||||
|
if (IsSodaFeatureEnabled(feature) && IsSodaFeatureInTray(feature) &&
|
||||||
|
SodaFeatureHasUpdate(feature, language_code)) {
|
||||||
|
SetSodaFeatureSubtext(feature, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AccessibilityDetailedView::IsSodaFeatureInTray(SodaFeature feature) {
|
||||||
AccessibilityControllerImpl* controller =
|
AccessibilityControllerImpl* controller =
|
||||||
Shell::Get()->accessibility_controller();
|
Shell::Get()->accessibility_controller();
|
||||||
if (dictation_view_ && controller->IsDictationSettingVisibleInTray()) {
|
switch (feature) {
|
||||||
dictation_view_->SetSubText(l10n_util::GetStringFUTF16Int(
|
case SodaFeature::kDictation:
|
||||||
IDS_ASH_ACCESSIBILITY_DICTATION_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS,
|
return dictation_view_ && controller->IsDictationSettingVisibleInTray();
|
||||||
progress));
|
case SodaFeature::kLiveCaption:
|
||||||
|
return live_caption_view_ &&
|
||||||
|
controller->IsLiveCaptionSettingVisibleInTray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessibilityDetailedView::SetDictationViewSubtitleTextForTesting(
|
void AccessibilityDetailedView::SetSodaFeatureSubtext(SodaFeature feature,
|
||||||
std::u16string text) {
|
std::u16string message) {
|
||||||
dictation_view_->SetSubText(text);
|
switch (feature) {
|
||||||
}
|
case SodaFeature::kDictation:
|
||||||
|
DCHECK(dictation_view_);
|
||||||
std::u16string
|
dictation_view_->SetSubText(message);
|
||||||
AccessibilityDetailedView::GetDictationViewSubtitleTextForTesting() {
|
break;
|
||||||
return dictation_view_->sub_text_label()->GetText();
|
case SodaFeature::kLiveCaption:
|
||||||
|
DCHECK(live_caption_view_);
|
||||||
|
live_caption_view_->SetSubText(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace tray
|
} // namespace tray
|
||||||
|
@@ -35,6 +35,11 @@ class TrayAccessibilityTest;
|
|||||||
|
|
||||||
namespace tray {
|
namespace tray {
|
||||||
|
|
||||||
|
enum class SodaFeature {
|
||||||
|
kDictation,
|
||||||
|
kLiveCaption,
|
||||||
|
};
|
||||||
|
|
||||||
// Create the detailed view of accessibility tray.
|
// Create the detailed view of accessibility tray.
|
||||||
class ASH_EXPORT AccessibilityDetailedView
|
class ASH_EXPORT AccessibilityDetailedView
|
||||||
: public TrayDetailedView,
|
: public TrayDetailedView,
|
||||||
@@ -74,16 +79,19 @@ class ASH_EXPORT AccessibilityDetailedView
|
|||||||
// Add the accessibility feature list.
|
// Add the accessibility feature list.
|
||||||
void AppendAccessibilityList();
|
void AppendAccessibilityList();
|
||||||
|
|
||||||
void UpdateSodaInstallerObserverStatus();
|
|
||||||
|
|
||||||
// SodaInstaller::Observer:
|
// SodaInstaller::Observer:
|
||||||
void OnSodaInstalled(speech::LanguageCode language_code) override;
|
void OnSodaInstalled(speech::LanguageCode language_code) override;
|
||||||
void OnSodaError(speech::LanguageCode language_code) override;
|
void OnSodaError(speech::LanguageCode language_code) override;
|
||||||
void OnSodaProgress(speech::LanguageCode language_code,
|
void OnSodaProgress(speech::LanguageCode language_code,
|
||||||
int combined_progress) override;
|
int combined_progress) override;
|
||||||
|
|
||||||
void SetDictationViewSubtitleTextForTesting(std::u16string text);
|
// Shows a message next to the feature icon in the tray if it is available
|
||||||
std::u16string GetDictationViewSubtitleTextForTesting();
|
// and if the language code provided is relevant to the feature.
|
||||||
|
void MaybeShowSodaMessage(SodaFeature feature,
|
||||||
|
speech::LanguageCode language_code,
|
||||||
|
std::u16string message);
|
||||||
|
bool IsSodaFeatureInTray(SodaFeature feature);
|
||||||
|
void SetSodaFeatureSubtext(SodaFeature feature, std::u16string message);
|
||||||
|
|
||||||
HoverHighlightView* spoken_feedback_view_ = nullptr;
|
HoverHighlightView* spoken_feedback_view_ = nullptr;
|
||||||
HoverHighlightView* select_to_speak_view_ = nullptr;
|
HoverHighlightView* select_to_speak_view_ = nullptr;
|
||||||
|
@@ -17,19 +17,23 @@
|
|||||||
#include "ash/test/ash_test_base.h"
|
#include "ash/test/ash_test_base.h"
|
||||||
#include "base/command_line.h"
|
#include "base/command_line.h"
|
||||||
#include "base/test/scoped_feature_list.h"
|
#include "base/test/scoped_feature_list.h"
|
||||||
|
#include "components/live_caption/pref_names.h"
|
||||||
#include "components/prefs/pref_service.h"
|
#include "components/prefs/pref_service.h"
|
||||||
#include "components/soda/soda_installer_impl_chromeos.h"
|
#include "components/soda/soda_installer_impl_chromeos.h"
|
||||||
#include "media/base/media_switches.h"
|
#include "media/base/media_switches.h"
|
||||||
#include "ui/accessibility/accessibility_features.h"
|
#include "ui/accessibility/accessibility_features.h"
|
||||||
#include "ui/accessibility/ax_enums.mojom-shared.h"
|
#include "ui/accessibility/ax_enums.mojom-shared.h"
|
||||||
#include "ui/accessibility/ax_node_data.h"
|
#include "ui/accessibility/ax_node_data.h"
|
||||||
|
#include "ui/views/controls/label.h"
|
||||||
|
|
||||||
namespace ash {
|
namespace ash {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const std::u16string kInitialDictationViewSubtitleText = u"This is a test";
|
const std::u16string kInitialFeatureViewSubtitleText = u"This is a test";
|
||||||
const std::u16string kSodaDownloaded = u"Speech files downloaded";
|
const std::u16string kSodaDownloaded = u"Speech files downloaded";
|
||||||
const std::u16string kSodaInProgress =
|
const std::u16string kSodaInProgress25 =
|
||||||
|
u"Downloading speech recognition files… 25%";
|
||||||
|
const std::u16string kSodaInProgress50 =
|
||||||
u"Downloading speech recognition files… 50%";
|
u"Downloading speech recognition files… 50%";
|
||||||
const std::u16string kSodaFailed =
|
const std::u16string kSodaFailed =
|
||||||
u"Can't download speech files. Try again later.";
|
u"Can't download speech files. Try again later.";
|
||||||
@@ -105,17 +109,24 @@ void EnableSwitchAccess(bool enabled) {
|
|||||||
Shell::Get()->accessibility_controller()->switch_access().SetEnabled(enabled);
|
Shell::Get()->accessibility_controller()->switch_access().SetEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
speech::LanguageCode en_us() {
|
||||||
|
return speech::LanguageCode::kEnUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
speech::LanguageCode fr_fr() {
|
||||||
|
return speech::LanguageCode::kFrFr;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class TrayAccessibilityTest : public AshTestBase, public AccessibilityObserver {
|
class TrayAccessibilityTest : public AshTestBase, public AccessibilityObserver {
|
||||||
public:
|
public:
|
||||||
|
TrayAccessibilityTest() = default;
|
||||||
TrayAccessibilityTest(const TrayAccessibilityTest&) = delete;
|
TrayAccessibilityTest(const TrayAccessibilityTest&) = delete;
|
||||||
TrayAccessibilityTest& operator=(const TrayAccessibilityTest&) = delete;
|
TrayAccessibilityTest& operator=(const TrayAccessibilityTest&) = delete;
|
||||||
|
|
||||||
protected:
|
|
||||||
TrayAccessibilityTest() = default;
|
|
||||||
~TrayAccessibilityTest() override = default;
|
~TrayAccessibilityTest() override = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
scoped_feature_list_.InitWithFeatures(
|
scoped_feature_list_.InitWithFeatures(
|
||||||
{media::kLiveCaption, media::kLiveCaptionSystemWideOnChromeOS,
|
{media::kLiveCaption, media::kLiveCaptionSystemWideOnChromeOS,
|
||||||
@@ -673,13 +684,20 @@ TEST_F(TrayAccessibilityTest, GetClassName) {
|
|||||||
GetDetailedViewClassName());
|
GetDetailedViewClassName());
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrayAccessibilitySodaTest : public TrayAccessibilityTest {
|
enum SodaFeature {
|
||||||
|
kDictation,
|
||||||
|
kLiveCaption,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TrayAccessibilitySodaTest
|
||||||
|
: public TrayAccessibilityTest,
|
||||||
|
public testing::WithParamInterface<SodaFeature> {
|
||||||
protected:
|
protected:
|
||||||
TrayAccessibilitySodaTest() { set_start_session(false); }
|
TrayAccessibilitySodaTest() { set_start_session(false); }
|
||||||
~TrayAccessibilitySodaTest() override = default;
|
|
||||||
TrayAccessibilitySodaTest(const TrayAccessibilitySodaTest&) = delete;
|
TrayAccessibilitySodaTest(const TrayAccessibilitySodaTest&) = delete;
|
||||||
TrayAccessibilitySodaTest& operator=(const TrayAccessibilitySodaTest&) =
|
TrayAccessibilitySodaTest& operator=(const TrayAccessibilitySodaTest&) =
|
||||||
delete;
|
delete;
|
||||||
|
~TrayAccessibilitySodaTest() override = default;
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
TrayAccessibilityTest::SetUp();
|
TrayAccessibilityTest::SetUp();
|
||||||
@@ -687,42 +705,71 @@ class TrayAccessibilitySodaTest : public TrayAccessibilityTest {
|
|||||||
// SodaInstallerImplChromeOS is never created (it's normally created when
|
// SodaInstallerImplChromeOS is never created (it's normally created when
|
||||||
// `ChromeBrowserMainPartsAsh` initializes). Create it here so that
|
// `ChromeBrowserMainPartsAsh` initializes). Create it here so that
|
||||||
// calling speech::SodaInstaller::GetInstance() returns a valid instance.
|
// calling speech::SodaInstaller::GetInstance() returns a valid instance.
|
||||||
scoped_feature_list_.InitWithFeatures(
|
std::vector<base::Feature> enabled_features(
|
||||||
{ash::features::kOnDeviceSpeechRecognition}, {});
|
{ash::features::kOnDeviceSpeechRecognition});
|
||||||
|
if (GetParam() == SodaFeature::kLiveCaption)
|
||||||
|
enabled_features.push_back(media::kLiveCaptionMultiLanguage);
|
||||||
|
scoped_feature_list_.InitWithFeatures(enabled_features, {});
|
||||||
soda_installer_impl_ =
|
soda_installer_impl_ =
|
||||||
std::make_unique<speech::SodaInstallerImplChromeOS>();
|
std::make_unique<speech::SodaInstallerImplChromeOS>();
|
||||||
soda_installer()->UninstallSodaForTesting();
|
|
||||||
|
|
||||||
CreateDetailedMenu();
|
CreateDetailedMenu();
|
||||||
EnableDictation(true);
|
EnableFeature(true);
|
||||||
SetDictationViewSubtitleText(kInitialDictationViewSubtitleText);
|
SetFeatureViewSubtitleText(kInitialFeatureViewSubtitleText);
|
||||||
SetDictationLocale("en-US");
|
SetFeatureLocale("en-US");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override {
|
void TearDown() override {
|
||||||
soda_installer()->UninstallSodaForTesting();
|
|
||||||
soda_installer_impl_.reset();
|
soda_installer_impl_.reset();
|
||||||
TrayAccessibilityTest::TearDown();
|
TrayAccessibilityTest::TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDictationLocale(const std::string& locale) {
|
void EnableFeature(bool enabled) {
|
||||||
Shell::Get()->session_controller()->GetActivePrefService()->SetString(
|
switch (GetParam()) {
|
||||||
prefs::kAccessibilityDictationLocale, locale);
|
case kDictation:
|
||||||
|
EnableDictation(enabled);
|
||||||
|
break;
|
||||||
|
case kLiveCaption:
|
||||||
|
EnableLiveCaption(enabled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetFeatureLocale(const std::string& locale) {
|
||||||
|
switch (GetParam()) {
|
||||||
|
case kDictation:
|
||||||
|
Shell::Get()->session_controller()->GetActivePrefService()->SetString(
|
||||||
|
prefs::kAccessibilityDictationLocale, locale);
|
||||||
|
break;
|
||||||
|
case kLiveCaption:
|
||||||
|
Shell::Get()->session_controller()->GetActivePrefService()->SetString(
|
||||||
|
::prefs::kLiveCaptionLanguageCode, locale);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
speech::SodaInstaller* soda_installer() {
|
speech::SodaInstaller* soda_installer() {
|
||||||
return speech::SodaInstaller::GetInstance();
|
return speech::SodaInstaller::GetInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
speech::LanguageCode en_us() { return speech::LanguageCode::kEnUs; }
|
void SetFeatureViewSubtitleText(std::u16string text) {
|
||||||
speech::LanguageCode fr_fr() { return speech::LanguageCode::kFrFr; }
|
switch (GetParam()) {
|
||||||
|
case kDictation:
|
||||||
void SetDictationViewSubtitleText(std::u16string text) {
|
detailed_menu()->dictation_view_->SetSubText(text);
|
||||||
detailed_menu()->SetDictationViewSubtitleTextForTesting(text);
|
break;
|
||||||
|
case kLiveCaption:
|
||||||
|
detailed_menu()->live_caption_view_->SetSubText(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string GetDictationViewSubtitleText() {
|
std::u16string GetFeatureViewSubtitleText() {
|
||||||
return detailed_menu()->GetDictationViewSubtitleTextForTesting();
|
switch (GetParam()) {
|
||||||
|
case kDictation:
|
||||||
|
return detailed_menu()->dictation_view_->sub_text_label()->GetText();
|
||||||
|
case kLiveCaption:
|
||||||
|
return detailed_menu()->live_caption_view_->sub_text_label()->GetText();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -730,54 +777,67 @@ class TrayAccessibilitySodaTest : public TrayAccessibilityTest {
|
|||||||
base::test::ScopedFeatureList scoped_feature_list_;
|
base::test::ScopedFeatureList scoped_feature_list_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensures that the Dictation subtitle changes when SODA AND the language pack
|
INSTANTIATE_TEST_SUITE_P(All,
|
||||||
// matching the Dictation locale are installed.
|
TrayAccessibilitySodaTest,
|
||||||
TEST_F(TrayAccessibilitySodaTest, OnSodaInstalledNotification) {
|
::testing::Values(SodaFeature::kDictation,
|
||||||
SetDictationLocale("fr-FR");
|
SodaFeature::kLiveCaption));
|
||||||
|
|
||||||
|
// Ensures that the feature subtitle changes when SODA AND the language pack
|
||||||
|
// matching the feature locale are installed.
|
||||||
|
TEST_P(TrayAccessibilitySodaTest, OnSodaInstalledNotification) {
|
||||||
|
SetFeatureLocale("fr-FR");
|
||||||
|
|
||||||
// Pretend that the SODA binary was installed. We still need to wait for the
|
// Pretend that the SODA binary was installed. We still need to wait for the
|
||||||
// correct language pack before doing anything.
|
// correct language pack before doing anything.
|
||||||
soda_installer()->NotifySodaInstalledForTesting();
|
soda_installer()->NotifySodaInstalledForTesting();
|
||||||
EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
soda_installer()->NotifySodaInstalledForTesting(en_us());
|
soda_installer()->NotifySodaInstalledForTesting(en_us());
|
||||||
EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
soda_installer()->NotifySodaInstalledForTesting(fr_fr());
|
soda_installer()->NotifySodaInstalledForTesting(fr_fr());
|
||||||
EXPECT_EQ(kSodaDownloaded, GetDictationViewSubtitleText());
|
EXPECT_EQ(kSodaDownloaded, GetFeatureViewSubtitleText());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures we only notify the user of progress for the language pack matching
|
// Ensures we only notify the user of progress for the language pack matching
|
||||||
// the Dictation locale.
|
// the feature locale.
|
||||||
TEST_F(TrayAccessibilitySodaTest, OnSodaProgressNotification) {
|
TEST_P(TrayAccessibilitySodaTest, OnSodaProgressNotification) {
|
||||||
soda_installer()->NotifySodaProgressForTesting(50, fr_fr());
|
SetFeatureLocale("en-US");
|
||||||
EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
|
|
||||||
|
soda_installer()->NotifySodaProgressForTesting(75, fr_fr());
|
||||||
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
soda_installer()->NotifySodaProgressForTesting(50);
|
soda_installer()->NotifySodaProgressForTesting(50);
|
||||||
EXPECT_EQ(kSodaInProgress, GetDictationViewSubtitleText());
|
EXPECT_EQ(kSodaInProgress50, GetFeatureViewSubtitleText());
|
||||||
soda_installer()->NotifySodaProgressForTesting(50, en_us());
|
soda_installer()->NotifySodaProgressForTesting(25, en_us());
|
||||||
EXPECT_EQ(kSodaInProgress, GetDictationViewSubtitleText());
|
EXPECT_EQ(kSodaInProgress25, GetFeatureViewSubtitleText());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures we only notify the user of an error when the SODA binary fails to
|
// Ensures we notify the user of an error when the SODA binary fails to
|
||||||
// download.
|
// download.
|
||||||
TEST_F(TrayAccessibilitySodaTest, SodaBinaryErrorNotification) {
|
TEST_P(TrayAccessibilitySodaTest, SodaBinaryErrorNotification) {
|
||||||
soda_installer()->NotifySodaErrorForTesting();
|
soda_installer()->NotifySodaErrorForTesting();
|
||||||
EXPECT_EQ(kSodaFailed, GetDictationViewSubtitleText());
|
EXPECT_EQ(kSodaFailed, GetFeatureViewSubtitleText());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TrayAccessibilitySodaTest, SodaLanguageErrorNotification) {
|
// Ensures we only notify the user of an error if the failed language pack
|
||||||
// Do nothing if the failed language pack is different than the Dictation
|
// matches the feature locale.
|
||||||
// locale.
|
TEST_P(TrayAccessibilitySodaTest, SodaLanguageErrorNotification) {
|
||||||
|
SetFeatureLocale("en-US");
|
||||||
soda_installer()->NotifySodaErrorForTesting(fr_fr());
|
soda_installer()->NotifySodaErrorForTesting(fr_fr());
|
||||||
EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
soda_installer()->NotifySodaErrorForTesting(en_us());
|
soda_installer()->NotifySodaErrorForTesting(en_us());
|
||||||
EXPECT_EQ(kSodaFailed, GetDictationViewSubtitleText());
|
EXPECT_EQ(kSodaFailed, GetFeatureViewSubtitleText());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures that we don't respond to SODA download updates when dictation is off.
|
// Ensures that we don't respond to SODA download updates when the feature is
|
||||||
TEST_F(TrayAccessibilitySodaTest, SodaDownloadDictationDisabled) {
|
// off.
|
||||||
EnableDictation(false);
|
TEST_P(TrayAccessibilitySodaTest, SodaDownloadFeatureDisabled) {
|
||||||
EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
|
EnableFeature(false);
|
||||||
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
soda_installer()->NotifySodaErrorForTesting();
|
soda_installer()->NotifySodaErrorForTesting();
|
||||||
EXPECT_EQ(kInitialDictationViewSubtitleText, GetDictationViewSubtitleText());
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaInstalledForTesting();
|
||||||
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaProgressForTesting(50);
|
||||||
|
EXPECT_EQ(kInitialFeatureViewSubtitleText, GetFeatureViewSubtitleText());
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrayAccessibilityLoginScreenTest : public TrayAccessibilityTest {
|
class TrayAccessibilityLoginScreenTest : public TrayAccessibilityTest {
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "ash/components/audio/cras_audio_handler.h"
|
#include "ash/components/audio/cras_audio_handler.h"
|
||||||
#include "ash/constants/ash_features.h"
|
#include "ash/constants/ash_features.h"
|
||||||
#include "ash/resources/vector_icons/vector_icons.h"
|
#include "ash/resources/vector_icons/vector_icons.h"
|
||||||
|
#include "ash/session/session_controller_impl.h"
|
||||||
#include "ash/shell.h"
|
#include "ash/shell.h"
|
||||||
#include "ash/strings/grit/ash_strings.h"
|
#include "ash/strings/grit/ash_strings.h"
|
||||||
#include "ash/style/ash_color_provider.h"
|
#include "ash/style/ash_color_provider.h"
|
||||||
@@ -19,7 +20,9 @@
|
|||||||
#include "ash/system/tray/tri_view.h"
|
#include "ash/system/tray/tri_view.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
|
#include "components/live_caption/pref_names.h"
|
||||||
#include "components/vector_icons/vector_icons.h"
|
#include "components/vector_icons/vector_icons.h"
|
||||||
|
#include "media/base/media_switches.h"
|
||||||
#include "third_party/cros_system_api/dbus/service_constants.h"
|
#include "third_party/cros_system_api/dbus/service_constants.h"
|
||||||
#include "ui/base/l10n/l10n_util.h"
|
#include "ui/base/l10n/l10n_util.h"
|
||||||
#include "ui/views/border.h"
|
#include "ui/views/border.h"
|
||||||
@@ -75,6 +78,16 @@ std::u16string GetAudioDeviceName(const AudioDevice& device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
speech::LanguageCode GetLiveCaptionLocale() {
|
||||||
|
std::string live_caption_locale = speech::kUsEnglishLocale;
|
||||||
|
PrefService* pref_service =
|
||||||
|
Shell::Get()->session_controller()->GetActivePrefService();
|
||||||
|
if (pref_service) {
|
||||||
|
live_caption_locale = ::prefs::GetLiveCaptionLanguageCode(pref_service);
|
||||||
|
}
|
||||||
|
return speech::GetLanguageCode(live_caption_locale);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace tray {
|
namespace tray {
|
||||||
@@ -84,10 +97,24 @@ AudioDetailedView::AudioDetailedView(DetailedViewDelegate* delegate)
|
|||||||
CreateItems();
|
CreateItems();
|
||||||
|
|
||||||
Shell::Get()->accessibility_controller()->AddObserver(this);
|
Shell::Get()->accessibility_controller()->AddObserver(this);
|
||||||
|
|
||||||
|
if (!media::IsLiveCaptionFeatureEnabled())
|
||||||
|
return;
|
||||||
|
speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
|
||||||
|
if (soda_installer)
|
||||||
|
soda_installer->AddObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDetailedView::~AudioDetailedView() {
|
AudioDetailedView::~AudioDetailedView() {
|
||||||
Shell::Get()->accessibility_controller()->RemoveObserver(this);
|
Shell::Get()->accessibility_controller()->RemoveObserver(this);
|
||||||
|
if (!media::IsLiveCaptionFeatureEnabled())
|
||||||
|
return;
|
||||||
|
speech::SodaInstaller* soda_installer = speech::SodaInstaller::GetInstance();
|
||||||
|
// `soda_installer` is not guaranteed to be valid, since it's possible for
|
||||||
|
// this class to out-live it. This means that this class cannot use
|
||||||
|
// ScopedObservation and needs to manage removing the observer itself.
|
||||||
|
if (soda_installer)
|
||||||
|
soda_installer->RemoveObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDetailedView::Update() {
|
void AudioDetailedView::Update() {
|
||||||
@@ -326,5 +353,43 @@ void AudioDetailedView::OnAccessibilityStatusChanged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SodaInstaller::Observer:
|
||||||
|
void AudioDetailedView::OnSodaInstalled(speech::LanguageCode language_code) {
|
||||||
|
std::u16string message = l10n_util::GetStringUTF16(
|
||||||
|
IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_COMPLETE);
|
||||||
|
MaybeShowSodaMessage(language_code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDetailedView::OnSodaError(speech::LanguageCode language_code) {
|
||||||
|
std::u16string message = l10n_util::GetStringUTF16(
|
||||||
|
IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_ERROR);
|
||||||
|
MaybeShowSodaMessage(language_code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDetailedView::OnSodaProgress(speech::LanguageCode language_code,
|
||||||
|
int progress) {
|
||||||
|
std::u16string message = l10n_util::GetStringFUTF16Int(
|
||||||
|
IDS_ASH_ACCESSIBILITY_SETTING_SUBTITLE_SODA_DOWNLOAD_PROGRESS, progress);
|
||||||
|
MaybeShowSodaMessage(language_code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDetailedView::MaybeShowSodaMessage(speech::LanguageCode language_code,
|
||||||
|
std::u16string message) {
|
||||||
|
AccessibilityControllerImpl* controller =
|
||||||
|
Shell::Get()->accessibility_controller();
|
||||||
|
bool is_live_caption_enabled = controller->live_caption().enabled();
|
||||||
|
bool is_live_caption_in_tray =
|
||||||
|
live_caption_view_ && controller->IsLiveCaptionSettingVisibleInTray();
|
||||||
|
// Only show updates for this feature if the language code applies to the SODA
|
||||||
|
// binary (encoded by by LanguageCode::kNone) or the language pack matching
|
||||||
|
// the feature locale.
|
||||||
|
bool live_caption_has_update = language_code == speech::LanguageCode::kNone ||
|
||||||
|
language_code == GetLiveCaptionLocale();
|
||||||
|
if (is_live_caption_enabled && is_live_caption_in_tray &&
|
||||||
|
live_caption_has_update) {
|
||||||
|
live_caption_view_->SetSubText(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tray
|
} // namespace tray
|
||||||
} // namespace ash
|
} // namespace ash
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include "ash/system/tray/tray_detailed_view.h"
|
#include "ash/system/tray/tray_detailed_view.h"
|
||||||
#include "ash/system/tray/tray_toggle_button.h"
|
#include "ash/system/tray/tray_toggle_button.h"
|
||||||
#include "base/callback.h"
|
#include "base/callback.h"
|
||||||
|
#include "components/soda/soda_installer.h"
|
||||||
#include "ui/views/controls/button/toggle_button.h"
|
#include "ui/views/controls/button/toggle_button.h"
|
||||||
#include "ui/views/view.h"
|
#include "ui/views/view.h"
|
||||||
|
|
||||||
@@ -23,12 +24,14 @@ struct VectorIcon;
|
|||||||
|
|
||||||
namespace ash {
|
namespace ash {
|
||||||
class MicGainSliderController;
|
class MicGainSliderController;
|
||||||
|
class UnifiedAudioDetailedViewControllerSodaTest;
|
||||||
class UnifiedAudioDetailedViewControllerTest;
|
class UnifiedAudioDetailedViewControllerTest;
|
||||||
|
|
||||||
namespace tray {
|
namespace tray {
|
||||||
|
|
||||||
class ASH_EXPORT AudioDetailedView : public TrayDetailedView,
|
class ASH_EXPORT AudioDetailedView : public TrayDetailedView,
|
||||||
public ::ash::AccessibilityObserver {
|
public ::ash::AccessibilityObserver,
|
||||||
|
public speech::SodaInstaller::Observer {
|
||||||
public:
|
public:
|
||||||
explicit AudioDetailedView(DetailedViewDelegate* delegate);
|
explicit AudioDetailedView(DetailedViewDelegate* delegate);
|
||||||
|
|
||||||
@@ -51,6 +54,7 @@ class ASH_EXPORT AudioDetailedView : public TrayDetailedView,
|
|||||||
void OnAccessibilityStatusChanged() override;
|
void OnAccessibilityStatusChanged() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class ::ash::UnifiedAudioDetailedViewControllerSodaTest;
|
||||||
friend class ::ash::UnifiedAudioDetailedViewControllerTest;
|
friend class ::ash::UnifiedAudioDetailedViewControllerTest;
|
||||||
|
|
||||||
// Helper function to add non-clickable header rows within the scrollable
|
// Helper function to add non-clickable header rows within the scrollable
|
||||||
@@ -70,6 +74,15 @@ class ASH_EXPORT AudioDetailedView : public TrayDetailedView,
|
|||||||
// TrayDetailedView:
|
// TrayDetailedView:
|
||||||
void HandleViewClicked(views::View* view) override;
|
void HandleViewClicked(views::View* view) override;
|
||||||
|
|
||||||
|
// SodaInstaller::Observer:
|
||||||
|
void OnSodaInstalled(speech::LanguageCode language_code) override;
|
||||||
|
void OnSodaError(speech::LanguageCode language_code) override;
|
||||||
|
void OnSodaProgress(speech::LanguageCode language_code,
|
||||||
|
int combined_progress) override;
|
||||||
|
|
||||||
|
void MaybeShowSodaMessage(speech::LanguageCode language_code,
|
||||||
|
std::u16string message);
|
||||||
|
|
||||||
typedef std::map<views::View*, AudioDevice> AudioDeviceMap;
|
typedef std::map<views::View*, AudioDevice> AudioDeviceMap;
|
||||||
|
|
||||||
std::unique_ptr<MicGainSliderController> mic_gain_controller_;
|
std::unique_ptr<MicGainSliderController> mic_gain_controller_;
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "ash/components/audio/audio_devices_pref_handler.h"
|
#include "ash/components/audio/audio_devices_pref_handler.h"
|
||||||
#include "ash/components/audio/audio_devices_pref_handler_stub.h"
|
#include "ash/components/audio/audio_devices_pref_handler_stub.h"
|
||||||
#include "ash/constants/ash_features.h"
|
#include "ash/constants/ash_features.h"
|
||||||
|
#include "ash/session/session_controller_impl.h"
|
||||||
#include "ash/shell.h"
|
#include "ash/shell.h"
|
||||||
#include "ash/system/audio/audio_detailed_view.h"
|
#include "ash/system/audio/audio_detailed_view.h"
|
||||||
#include "ash/system/audio/mic_gain_slider_controller.h"
|
#include "ash/system/audio/mic_gain_slider_controller.h"
|
||||||
@@ -20,11 +21,14 @@
|
|||||||
#include "base/test/scoped_feature_list.h"
|
#include "base/test/scoped_feature_list.h"
|
||||||
#include "chromeos/dbus/audio/cras_audio_client.h"
|
#include "chromeos/dbus/audio/cras_audio_client.h"
|
||||||
#include "chromeos/dbus/audio/fake_cras_audio_client.h"
|
#include "chromeos/dbus/audio/fake_cras_audio_client.h"
|
||||||
|
#include "components/live_caption/pref_names.h"
|
||||||
|
#include "components/soda/soda_installer_impl_chromeos.h"
|
||||||
#include "media/base/media_switches.h"
|
#include "media/base/media_switches.h"
|
||||||
#include "mojo/public/cpp/bindings/receiver_set.h"
|
#include "mojo/public/cpp/bindings/receiver_set.h"
|
||||||
#include "testing/gmock/include/gmock/gmock.h"
|
#include "testing/gmock/include/gmock/gmock.h"
|
||||||
#include "third_party/cros_system_api/dbus/service_constants.h"
|
#include "third_party/cros_system_api/dbus/service_constants.h"
|
||||||
#include "ui/events/base_event_utils.h"
|
#include "ui/events/base_event_utils.h"
|
||||||
|
#include "ui/views/controls/label.h"
|
||||||
#include "ui/views/test/button_test_api.h"
|
#include "ui/views/test/button_test_api.h"
|
||||||
#include "ui/views/widget/widget.h"
|
#include "ui/views/widget/widget.h"
|
||||||
|
|
||||||
@@ -39,6 +43,23 @@ constexpr uint64_t kInternalMicId = 10003;
|
|||||||
constexpr uint64_t kFrontMicId = 10012;
|
constexpr uint64_t kFrontMicId = 10012;
|
||||||
constexpr uint64_t kRearMicId = 10013;
|
constexpr uint64_t kRearMicId = 10013;
|
||||||
|
|
||||||
|
const std::u16string kInitialLiveCaptionViewSubtitleText = u"This is a test";
|
||||||
|
const std::u16string kSodaDownloaded = u"Speech files downloaded";
|
||||||
|
const std::u16string kSodaInProgress25 =
|
||||||
|
u"Downloading speech recognition files… 25%";
|
||||||
|
const std::u16string kSodaInProgress50 =
|
||||||
|
u"Downloading speech recognition files… 50%";
|
||||||
|
const std::u16string kSodaFailed =
|
||||||
|
u"Can't download speech files. Try again later.";
|
||||||
|
|
||||||
|
speech::LanguageCode en_us() {
|
||||||
|
return speech::LanguageCode::kEnUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
speech::LanguageCode fr_fr() {
|
||||||
|
return speech::LanguageCode::kFrFr;
|
||||||
|
}
|
||||||
|
|
||||||
struct AudioNodeInfo {
|
struct AudioNodeInfo {
|
||||||
bool is_input;
|
bool is_input;
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
@@ -161,7 +182,7 @@ class UnifiedAudioDetailedViewControllerTest : public AshTestBase {
|
|||||||
return audio_detailed_view_.get();
|
return audio_detailed_view_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
views::View* live_caption_view() {
|
HoverHighlightView* live_caption_view() {
|
||||||
return audio_detailed_view()->live_caption_view_;
|
return audio_detailed_view()->live_caption_view_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,4 +368,135 @@ TEST_F(UnifiedAudioDetailedViewControllerTest, LiveCaptionNotAvailable) {
|
|||||||
EXPECT_FALSE(live_caption_enabled());
|
EXPECT_FALSE(live_caption_enabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnifiedAudioDetailedViewControllerSodaTest
|
||||||
|
: public UnifiedAudioDetailedViewControllerTest {
|
||||||
|
protected:
|
||||||
|
UnifiedAudioDetailedViewControllerSodaTest() = default;
|
||||||
|
UnifiedAudioDetailedViewControllerSodaTest(
|
||||||
|
const UnifiedAudioDetailedViewControllerSodaTest&) = delete;
|
||||||
|
UnifiedAudioDetailedViewControllerSodaTest& operator=(
|
||||||
|
const UnifiedAudioDetailedViewControllerSodaTest&) = delete;
|
||||||
|
~UnifiedAudioDetailedViewControllerSodaTest() override = default;
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
UnifiedAudioDetailedViewControllerTest::SetUp();
|
||||||
|
// Since this test suite is part of ash unit tests, the
|
||||||
|
// SodaInstallerImplChromeOS is never created (it's normally created when
|
||||||
|
// `ChromeBrowserMainPartsAsh` initializes). Create it here so that
|
||||||
|
// calling speech::SodaInstaller::GetInstance() returns a valid instance.
|
||||||
|
scoped_feature_list_.InitWithFeatures(
|
||||||
|
{ash::features::kOnDeviceSpeechRecognition, media::kLiveCaption,
|
||||||
|
media::kLiveCaptionMultiLanguage,
|
||||||
|
media::kLiveCaptionSystemWideOnChromeOS},
|
||||||
|
{});
|
||||||
|
soda_installer_impl_ =
|
||||||
|
std::make_unique<speech::SodaInstallerImplChromeOS>();
|
||||||
|
|
||||||
|
EnableLiveCaption(true);
|
||||||
|
SetLiveCaptionViewSubtitleText(kInitialLiveCaptionViewSubtitleText);
|
||||||
|
SetLiveCaptionLocale("en-US");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
soda_installer_impl_.reset();
|
||||||
|
UnifiedAudioDetailedViewControllerTest::TearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableLiveCaption(bool enabled) {
|
||||||
|
Shell::Get()->accessibility_controller()->live_caption().SetEnabled(
|
||||||
|
enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLiveCaptionLocale(const std::string& locale) {
|
||||||
|
Shell::Get()->session_controller()->GetActivePrefService()->SetString(
|
||||||
|
::prefs::kLiveCaptionLanguageCode, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
speech::SodaInstaller* soda_installer() {
|
||||||
|
return speech::SodaInstaller::GetInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLiveCaptionViewSubtitleText(std::u16string text) {
|
||||||
|
live_caption_view()->SetSubText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::u16string GetLiveCaptionViewSubtitleText() {
|
||||||
|
return live_caption_view()->sub_text_label()->GetText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<speech::SodaInstallerImplChromeOS> soda_installer_impl_;
|
||||||
|
base::test::ScopedFeatureList scoped_feature_list_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensures that the Dictation subtitle changes when SODA AND the language pack
|
||||||
|
// matching the Live Caption locale are installed.
|
||||||
|
TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
|
||||||
|
OnSodaInstalledNotification) {
|
||||||
|
SetLiveCaptionLocale("fr-FR");
|
||||||
|
|
||||||
|
// Pretend that the SODA binary was installed. We still need to wait for the
|
||||||
|
// correct language pack before doing anything.
|
||||||
|
soda_installer()->NotifySodaInstalledForTesting();
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaInstalledForTesting(en_us());
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaInstalledForTesting(fr_fr());
|
||||||
|
EXPECT_EQ(kSodaDownloaded, GetLiveCaptionViewSubtitleText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures we only notify the user of progress for the language pack matching
|
||||||
|
// the Live Caption locale.
|
||||||
|
TEST_F(UnifiedAudioDetailedViewControllerSodaTest, OnSodaProgressNotification) {
|
||||||
|
SetLiveCaptionLocale("en-US");
|
||||||
|
|
||||||
|
soda_installer()->NotifySodaProgressForTesting(75, fr_fr());
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaProgressForTesting(50);
|
||||||
|
EXPECT_EQ(kSodaInProgress50, GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaProgressForTesting(25, en_us());
|
||||||
|
EXPECT_EQ(kSodaInProgress25, GetLiveCaptionViewSubtitleText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures we notify the user of an error when the SODA binary fails to
|
||||||
|
// download.
|
||||||
|
TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
|
||||||
|
SodaBinaryErrorNotification) {
|
||||||
|
soda_installer()->NotifySodaErrorForTesting();
|
||||||
|
EXPECT_EQ(kSodaFailed, GetLiveCaptionViewSubtitleText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures we only notify the user of an error if the failed language pack
|
||||||
|
// matches the Live Caption locale.
|
||||||
|
TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
|
||||||
|
SodaLanguageErrorNotification) {
|
||||||
|
SetLiveCaptionLocale("en-US");
|
||||||
|
soda_installer()->NotifySodaErrorForTesting(fr_fr());
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaErrorForTesting(en_us());
|
||||||
|
EXPECT_EQ(kSodaFailed, GetLiveCaptionViewSubtitleText());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensures that we don't respond to SODA download updates when Live Caption is
|
||||||
|
// off.
|
||||||
|
TEST_F(UnifiedAudioDetailedViewControllerSodaTest,
|
||||||
|
SodaDownloadLiveCaptionDisabled) {
|
||||||
|
EnableLiveCaption(false);
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaErrorForTesting();
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaInstalledForTesting();
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
soda_installer()->NotifySodaProgressForTesting(50);
|
||||||
|
EXPECT_EQ(kInitialLiveCaptionViewSubtitleText,
|
||||||
|
GetLiveCaptionViewSubtitleText());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ash
|
} // namespace ash
|
||||||
|
@@ -25,7 +25,7 @@ class ViewClickListener;
|
|||||||
// A view that changes background color on hover, and triggers a callback in the
|
// A view that changes background color on hover, and triggers a callback in the
|
||||||
// associated ViewClickListener on click. The view can also be forced to
|
// associated ViewClickListener on click. The view can also be forced to
|
||||||
// maintain a fixed height.
|
// maintain a fixed height.
|
||||||
class HoverHighlightView : public ActionableView {
|
class ASH_EXPORT HoverHighlightView : public ActionableView {
|
||||||
public:
|
public:
|
||||||
enum class AccessibilityState {
|
enum class AccessibilityState {
|
||||||
// The default accessibility view.
|
// The default accessibility view.
|
||||||
|
Reference in New Issue
Block a user