blob: 6fe05144a8d23128e9a736f2cc328deb3a7b272b [file] [log] [blame]
Abigail Klein4a4ac272020-04-07 17:47:151// Copyright (c) 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/accessibility/caption_controller.h"
6
Abigail Klein5eb53a42020-11-08 22:06:157#include <memory>
Abigail Klein4a4ac272020-04-07 17:47:158
9#include "base/bind.h"
evliu60658b22020-08-31 18:55:4310#include "base/command_line.h"
Abigail Klein4a4ac272020-04-07 17:47:1511#include "base/feature_list.h"
Katie D31f377f32020-05-05 19:22:0412#include "base/metrics/histogram_functions.h"
Abigail Kleina81f2e22020-05-04 14:32:4113#include "chrome/browser/accessibility/caption_util.h"
Abigail Klein5eb53a42020-11-08 22:06:1514#include "chrome/browser/accessibility/soda_installer.h"
Abigail Klein4a4ac272020-04-07 17:47:1515#include "chrome/browser/browser_process.h"
Abigail Klein4a4ac272020-04-07 17:47:1516#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/ui/browser.h"
Abigail Klein22b06332020-04-30 20:57:1818#include "chrome/browser/ui/browser_finder.h"
Abigail Klein4a4ac272020-04-07 17:47:1519#include "chrome/browser/ui/browser_list.h"
20#include "chrome/browser/ui/caption_bubble_controller.h"
21#include "chrome/common/pref_names.h"
22#include "components/pref_registry/pref_registry_syncable.h"
23#include "components/prefs/pref_change_registrar.h"
evliu5826f332020-08-21 21:01:2224#include "components/soda/constants.h"
Abigail Klein4a4ac272020-04-07 17:47:1525#include "components/sync_preferences/pref_service_syncable.h"
Katie D31f377f32020-05-05 19:22:0426#include "content/public/browser/browser_accessibility_state.h"
Abigail Klein22b06332020-04-30 20:57:1827#include "content/public/browser/web_contents.h"
Abigail Klein4a4ac272020-04-07 17:47:1528#include "media/base/media_switches.h"
29
Abigail Kleina81f2e22020-05-04 14:32:4130namespace {
31
32const char* const kCaptionStylePrefsToObserve[] = {
33 prefs::kAccessibilityCaptionsTextSize,
34 prefs::kAccessibilityCaptionsTextFont,
35 prefs::kAccessibilityCaptionsTextColor,
36 prefs::kAccessibilityCaptionsTextOpacity,
37 prefs::kAccessibilityCaptionsBackgroundColor,
38 prefs::kAccessibilityCaptionsTextShadow,
39 prefs::kAccessibilityCaptionsBackgroundOpacity};
40
evliu854ee3e2020-11-05 00:27:5441constexpr int kSodaCleanUpDelayInDays = 30;
42
Abigail Kleina81f2e22020-05-04 14:32:4143} // namespace
44
Abigail Klein4a4ac272020-04-07 17:47:1545namespace captions {
46
47CaptionController::CaptionController(Profile* profile) : profile_(profile) {}
48
49CaptionController::~CaptionController() = default;
50
51// static
52void CaptionController::RegisterProfilePrefs(
53 user_prefs::PrefRegistrySyncable* registry) {
54 registry->RegisterBooleanPref(
55 prefs::kLiveCaptionEnabled, false,
56 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
evliu5826f332020-08-21 21:01:2257
58 // Initially default the language to en-US.
59 registry->RegisterStringPref(prefs::kLiveCaptionLanguageCode, "en-US");
Abigail Klein4a4ac272020-04-07 17:47:1560}
61
Abigail Klein4a4ac272020-04-07 17:47:1562void CaptionController::Init() {
63 // Hidden behind a feature flag.
64 if (!base::FeatureList::IsEnabled(media::kLiveCaption))
65 return;
66
67 pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
68 pref_change_registrar_->Init(profile_->GetPrefs());
evliu60658b22020-08-31 18:55:4369 auto* command_line = base::CommandLine::ForCurrentProcess();
70 if (command_line &&
71 command_line->HasSwitch(switches::kEnableLiveCaptionPrefForTesting)) {
72 profile_->GetPrefs()->SetBoolean(prefs::kLiveCaptionEnabled, true);
73 }
74
Abigail Klein4a4ac272020-04-07 17:47:1575 pref_change_registrar_->Add(
76 prefs::kLiveCaptionEnabled,
77 base::BindRepeating(&CaptionController::OnLiveCaptionEnabledChanged,
78 base::Unretained(this)));
evliu5826f332020-08-21 21:01:2279 pref_change_registrar_->Add(
80 prefs::kLiveCaptionLanguageCode,
81 base::BindRepeating(&CaptionController::OnLiveCaptionLanguageChanged,
82 base::Unretained(this)));
Abigail Klein225ff312020-04-17 16:52:3383
84 enabled_ = IsLiveCaptionEnabled();
85 if (enabled_)
86 UpdateUIEnabled();
Katie D31f377f32020-05-05 19:22:0487
88 content::BrowserAccessibilityState::GetInstance()
89 ->AddUIThreadHistogramCallback(base::BindOnce(
90 &CaptionController::UpdateAccessibilityCaptionHistograms,
91 base::Unretained(this)));
Abigail Klein4a4ac272020-04-07 17:47:1592}
93
94void CaptionController::OnLiveCaptionEnabledChanged() {
Abigail Klein225ff312020-04-17 16:52:3395 bool enabled = IsLiveCaptionEnabled();
Abigail Klein4a4ac272020-04-07 17:47:1596 if (enabled == enabled_)
97 return;
98 enabled_ = enabled;
Abigail Klein225ff312020-04-17 16:52:3399
Abigail Klein4a4ac272020-04-07 17:47:15100 if (enabled_) {
Abigail Klein5eb53a42020-11-08 22:06:15101 // Register SODA component and download speech model.
evliu854ee3e2020-11-05 00:27:54102 g_browser_process->local_state()->SetTime(prefs::kSodaScheduledDeletionTime,
103 base::Time());
Abigail Klein5eb53a42020-11-08 22:06:15104 speech::SODAInstaller::GetInstance()->InstallSODA(profile_->GetPrefs());
105 speech::SODAInstaller::GetInstance()->InstallLanguage(profile_->GetPrefs());
Abigail Klein225ff312020-04-17 16:52:33106 } else {
evliu854ee3e2020-11-05 00:27:54107 // Schedule SODA to be deleted in 30 days if the feature is not enabled
108 // before then.
109 g_browser_process->local_state()->SetTime(
110 prefs::kSodaScheduledDeletionTime,
111 base::Time::Now() + base::TimeDelta::FromDays(kSodaCleanUpDelayInDays));
Abigail Klein225ff312020-04-17 16:52:33112 }
Abigail Klein5eb53a42020-11-08 22:06:15113 UpdateUIEnabled();
Abigail Klein225ff312020-04-17 16:52:33114}
Abigail Klein4a4ac272020-04-07 17:47:15115
Abigail Klein5eb53a42020-11-08 22:06:15116void CaptionController::OnLiveCaptionLanguageChanged() {
117 if (enabled_)
118 speech::SODAInstaller::GetInstance()->InstallLanguage(profile_->GetPrefs());
119}
120
121bool CaptionController::IsLiveCaptionEnabled() {
122 PrefService* profile_prefs = profile_->GetPrefs();
123 return profile_prefs->GetBoolean(prefs::kLiveCaptionEnabled);
124}
evliu5826f332020-08-21 21:01:22125
Abigail Klein225ff312020-04-17 16:52:33126void CaptionController::UpdateUIEnabled() {
127 if (enabled_) {
Abigail Klein4a4ac272020-04-07 17:47:15128 // Create captions UI in each browser view.
129 for (Browser* browser : *BrowserList::GetInstance()) {
130 OnBrowserAdded(browser);
131 }
132
133 // Add observers to the BrowserList for new browser views being added.
134 BrowserList::GetInstance()->AddObserver(this);
Abigail Kleina81f2e22020-05-04 14:32:41135
136 // Observe caption style prefs.
137 for (const char* const pref_name : kCaptionStylePrefsToObserve) {
138 pref_change_registrar_->Add(
139 pref_name, base::BindRepeating(&CaptionController::UpdateCaptionStyle,
140 base::Unretained(this)));
141 }
142 UpdateCaptionStyle();
Abigail Klein4a4ac272020-04-07 17:47:15143 } else {
Abigail Klein4a4ac272020-04-07 17:47:15144 // Destroy caption bubble controllers.
145 caption_bubble_controllers_.clear();
146
147 // Remove observers.
148 BrowserList::GetInstance()->RemoveObserver(this);
Abigail Kleina81f2e22020-05-04 14:32:41149
150 // Remove prefs to observe.
151 for (const char* const pref_name : kCaptionStylePrefsToObserve) {
152 pref_change_registrar_->Remove(pref_name);
153 }
Abigail Klein4a4ac272020-04-07 17:47:15154 }
155}
156
Katie D31f377f32020-05-05 19:22:04157void CaptionController::UpdateAccessibilityCaptionHistograms() {
evliu5ac40382020-08-31 20:55:26158 base::UmaHistogramBoolean("Accessibility.LiveCaption", enabled_);
Katie D31f377f32020-05-05 19:22:04159}
160
Abigail Klein4a4ac272020-04-07 17:47:15161void CaptionController::OnBrowserAdded(Browser* browser) {
Abigail Klein212966a2020-06-22 22:50:39162 if (browser->profile() != profile_ &&
163 browser->profile()->GetOriginalProfile() != profile_) {
Abigail Klein4a4ac272020-04-07 17:47:15164 return;
Abigail Klein212966a2020-06-22 22:50:39165 }
Abigail Klein4a4ac272020-04-07 17:47:15166
Abigail Klein212966a2020-06-22 22:50:39167 DCHECK(!caption_bubble_controllers_.count(browser));
Abigail Klein4a4ac272020-04-07 17:47:15168 caption_bubble_controllers_[browser] =
169 CaptionBubbleController::Create(browser);
Abigail Kleina81f2e22020-05-04 14:32:41170 caption_bubble_controllers_[browser]->UpdateCaptionStyle(caption_style_);
Abigail Klein4a4ac272020-04-07 17:47:15171}
172
173void CaptionController::OnBrowserRemoved(Browser* browser) {
Abigail Klein212966a2020-06-22 22:50:39174 if (browser->profile() != profile_ &&
175 browser->profile()->GetOriginalProfile() != profile_) {
Abigail Klein4a4ac272020-04-07 17:47:15176 return;
Abigail Klein212966a2020-06-22 22:50:39177 }
Abigail Klein4a4ac272020-04-07 17:47:15178
179 DCHECK(caption_bubble_controllers_.count(browser));
180 caption_bubble_controllers_.erase(browser);
181}
182
Abigail Klein80f9ca12020-06-08 17:06:33183bool CaptionController::DispatchTranscription(
Abigail Klein4c51ac42020-05-06 19:45:02184 content::WebContents* web_contents,
Abigail Klein29037612020-05-04 23:59:45185 const chrome::mojom::TranscriptionResultPtr& transcription_result) {
Abigail Klein4c51ac42020-05-06 19:45:02186 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
Katie Dde318c32020-05-21 18:09:34187 if (!browser || !caption_bubble_controllers_.count(browser))
Abigail Klein80f9ca12020-06-08 17:06:33188 return false;
189 return caption_bubble_controllers_[browser]->OnTranscription(
190 transcription_result, web_contents);
Abigail Klein22b06332020-04-30 20:57:18191}
192
Abigail Klein8dc47fe62020-08-13 18:46:17193void CaptionController::OnError(content::WebContents* web_contents) {
194 Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
195 if (!browser || !caption_bubble_controllers_.count(browser))
196 return;
197 return caption_bubble_controllers_[browser]->OnError(web_contents);
198}
199
Katie Dde318c32020-05-21 18:09:34200CaptionBubbleController*
201CaptionController::GetCaptionBubbleControllerForBrowser(Browser* browser) {
202 if (!browser || !caption_bubble_controllers_.count(browser))
203 return nullptr;
204 return caption_bubble_controllers_[browser].get();
205}
206
Abigail Kleina81f2e22020-05-04 14:32:41207void CaptionController::UpdateCaptionStyle() {
208 PrefService* profile_prefs = profile_->GetPrefs();
209 // Metrics are recorded when passing the caption prefs to the browser, so do
210 // not duplicate them here.
211 caption_style_ = GetCaptionStyleFromUserSettings(profile_prefs,
212 false /* record_metrics */);
213
214 for (const auto& item : caption_bubble_controllers_) {
215 caption_bubble_controllers_[item.first]->UpdateCaptionStyle(caption_style_);
216 }
217}
218
Abigail Klein4a4ac272020-04-07 17:47:15219} // namespace captions