| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/app_list/start_page_service.h" | 5 #include "chrome/browser/ui/app_list/start_page_service.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 #include "content/public/browser/notification_registrar.h" | 29 #include "content/public/browser/notification_registrar.h" |
| 30 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
| 31 #include "content/public/browser/notification_source.h" | 31 #include "content/public/browser/notification_source.h" |
| 32 #include "content/public/browser/web_contents.h" | 32 #include "content/public/browser/web_contents.h" |
| 33 #include "content/public/browser/web_contents_delegate.h" | 33 #include "content/public/browser/web_contents_delegate.h" |
| 34 #include "extensions/browser/extension_system_provider.h" | 34 #include "extensions/browser/extension_system_provider.h" |
| 35 #include "extensions/browser/extensions_browser_client.h" | 35 #include "extensions/browser/extensions_browser_client.h" |
| 36 #include "extensions/common/extension.h" | 36 #include "extensions/common/extension.h" |
| 37 #include "ui/app_list/app_list_switches.h" | 37 #include "ui/app_list/app_list_switches.h" |
| 38 | 38 |
| 39 #if defined(OS_CHROMEOS) | |
| 40 #include "chromeos/audio/cras_audio_handler.h" | |
| 41 #endif | |
| 42 | |
| 43 using base::RecordAction; | 39 using base::RecordAction; |
| 44 using base::UserMetricsAction; | 40 using base::UserMetricsAction; |
| 45 | 41 |
| 46 namespace app_list { | 42 namespace app_list { |
| 47 | 43 |
| 48 namespace { | 44 namespace { |
| 49 | 45 |
| 50 bool InSpeechRecognition(SpeechRecognitionState state) { | 46 bool InSpeechRecognition(SpeechRecognitionState state) { |
| 51 return state == SPEECH_RECOGNITION_RECOGNIZING || | 47 return state == SPEECH_RECOGNITION_RECOGNIZING || |
| 52 state == SPEECH_RECOGNITION_IN_SPEECH; | 48 state == SPEECH_RECOGNITION_IN_SPEECH; |
| 53 } | 49 } |
| 54 | 50 |
| 55 } // namespace | 51 } |
| 56 | 52 |
| 57 class StartPageService::ProfileDestroyObserver | 53 class StartPageService::ProfileDestroyObserver |
| 58 : public content::NotificationObserver { | 54 : public content::NotificationObserver { |
| 59 public: | 55 public: |
| 60 explicit ProfileDestroyObserver(StartPageService* service) | 56 explicit ProfileDestroyObserver(StartPageService* service) |
| 61 : service_(service) { | 57 : service_(service) { |
| 62 registrar_.Add(this, | 58 registrar_.Add(this, |
| 63 chrome::NOTIFICATION_PROFILE_DESTROYED, | 59 chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 64 content::Source<Profile>(service_->profile())); | 60 content::Source<Profile>(service_->profile())); |
| 65 } | 61 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 const GURL& security_origin, | 95 const GURL& security_origin, |
| 100 content::MediaStreamType type) override { | 96 content::MediaStreamType type) override { |
| 101 return MediaCaptureDevicesDispatcher::GetInstance() | 97 return MediaCaptureDevicesDispatcher::GetInstance() |
| 102 ->CheckMediaAccessPermission(web_contents, security_origin, type); | 98 ->CheckMediaAccessPermission(web_contents, security_origin, type); |
| 103 } | 99 } |
| 104 | 100 |
| 105 private: | 101 private: |
| 106 DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate); | 102 DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate); |
| 107 }; | 103 }; |
| 108 | 104 |
| 109 #if defined(OS_CHROMEOS) | |
| 110 | |
| 111 class StartPageService::AudioStatus | |
| 112 : public chromeos::CrasAudioHandler::AudioObserver { | |
| 113 public: | |
| 114 explicit AudioStatus(StartPageService* start_page_service) | |
| 115 : start_page_service_(start_page_service) { | |
| 116 chromeos::CrasAudioHandler::Get()->AddAudioObserver(this); | |
| 117 CheckAndUpdate(); | |
| 118 } | |
| 119 | |
| 120 ~AudioStatus() override { | |
| 121 chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this); | |
| 122 } | |
| 123 | |
| 124 bool CanListen() { | |
| 125 chromeos::CrasAudioHandler* audio_handler = | |
| 126 chromeos::CrasAudioHandler::Get(); | |
| 127 return (audio_handler->GetPrimaryActiveInputNode() != 0) && | |
| 128 !audio_handler->IsInputMuted(); | |
| 129 } | |
| 130 | |
| 131 private: | |
| 132 void CheckAndUpdate() { | |
| 133 // TODO(mukai): If the system can listen, this should also restart the | |
| 134 // hotword recognition. | |
| 135 start_page_service_->OnSpeechRecognitionStateChanged( | |
| 136 CanListen() ? SPEECH_RECOGNITION_READY : SPEECH_RECOGNITION_OFF); | |
| 137 } | |
| 138 | |
| 139 // chromeos::CrasAudioHandler::AudioObserver: | |
| 140 void OnInputMuteChanged() override { CheckAndUpdate(); } | |
| 141 | |
| 142 void OnActiveInputNodeChanged() override { CheckAndUpdate(); } | |
| 143 | |
| 144 StartPageService* start_page_service_; | |
| 145 | |
| 146 DISALLOW_COPY_AND_ASSIGN(AudioStatus); | |
| 147 }; | |
| 148 | |
| 149 #endif // OS_CHROMEOS | |
| 150 | |
| 151 // static | 105 // static |
| 152 StartPageService* StartPageService::Get(Profile* profile) { | 106 StartPageService* StartPageService::Get(Profile* profile) { |
| 153 return StartPageServiceFactory::GetForProfile(profile); | 107 return StartPageServiceFactory::GetForProfile(profile); |
| 154 } | 108 } |
| 155 | 109 |
| 156 StartPageService::StartPageService(Profile* profile) | 110 StartPageService::StartPageService(Profile* profile) |
| 157 : profile_(profile), | 111 : profile_(profile), |
| 158 profile_destroy_observer_(new ProfileDestroyObserver(this)), | 112 profile_destroy_observer_(new ProfileDestroyObserver(this)), |
| 159 recommended_apps_(new RecommendedApps(profile)), | 113 recommended_apps_(new RecommendedApps(profile)), |
| 160 state_(app_list::SPEECH_RECOGNITION_OFF), | 114 state_(app_list::SPEECH_RECOGNITION_OFF), |
| 161 speech_button_toggled_manually_(false), | 115 speech_button_toggled_manually_(false), |
| 162 speech_result_obtained_(false), | 116 speech_result_obtained_(false), |
| 163 webui_finished_loading_(false), | 117 webui_finished_loading_(false), |
| 164 weak_factory_(this) { | 118 weak_factory_(this) { |
| 165 // If experimental hotwording is enabled, then we're always "ready". | 119 // If experimental hotwording is enabled, then we're always "ready". |
| 166 // Transitioning into the "hotword recognizing" state is handled by the | 120 // Transitioning into the "hotword recognizing" state is handled by the |
| 167 // hotword extension. | 121 // hotword extension. |
| 168 if (HotwordService::IsExperimentalHotwordingEnabled()) { | 122 if (HotwordService::IsExperimentalHotwordingEnabled()) |
| 169 state_ = app_list::SPEECH_RECOGNITION_READY; | 123 state_ = app_list::SPEECH_RECOGNITION_READY; |
| 170 } | |
| 171 | 124 |
| 172 if (app_list::switches::IsExperimentalAppListEnabled()) | 125 if (app_list::switches::IsExperimentalAppListEnabled()) |
| 173 LoadContents(); | 126 LoadContents(); |
| 174 } | 127 } |
| 175 | 128 |
| 176 StartPageService::~StartPageService() {} | 129 StartPageService::~StartPageService() {} |
| 177 | 130 |
| 178 void StartPageService::AddObserver(StartPageObserver* observer) { | 131 void StartPageService::AddObserver(StartPageObserver* observer) { |
| 179 observers_.AddObserver(observer); | 132 observers_.AddObserver(observer); |
| 180 } | 133 } |
| 181 | 134 |
| 182 void StartPageService::RemoveObserver(StartPageObserver* observer) { | 135 void StartPageService::RemoveObserver(StartPageObserver* observer) { |
| 183 observers_.RemoveObserver(observer); | 136 observers_.RemoveObserver(observer); |
| 184 } | 137 } |
| 185 | 138 |
| 186 void StartPageService::AppListShown() { | 139 void StartPageService::AppListShown() { |
| 187 if (!contents_) { | 140 if (!contents_) { |
| 188 LoadContents(); | 141 LoadContents(); |
| 189 } else if (contents_->GetWebUI() && | 142 } else if (contents_->GetWebUI() && |
| 190 !HotwordService::IsExperimentalHotwordingEnabled()) { | 143 !HotwordService::IsExperimentalHotwordingEnabled()) { |
| 191 // If experimental hotwording is enabled, don't call onAppListShown. | 144 // If experimental hotwording is enabled, don't call onAppListShown. |
| 192 // onAppListShown() initializes the web speech API, which is not used with | 145 // onAppListShown() initializes the web speech API, which is not used with |
| 193 // experimental hotwording. | 146 // experimental hotwording. |
| 194 contents_->GetWebUI()->CallJavascriptFunction( | 147 contents_->GetWebUI()->CallJavascriptFunction( |
| 195 "appList.startPage.onAppListShown", | 148 "appList.startPage.onAppListShown", |
| 196 base::FundamentalValue(HotwordEnabled())); | 149 base::FundamentalValue(HotwordEnabled())); |
| 197 } | 150 } |
| 198 | |
| 199 #if defined(OS_CHROMEOS) | |
| 200 audio_status_.reset(new AudioStatus(this)); | |
| 201 #endif | |
| 202 } | 151 } |
| 203 | 152 |
| 204 void StartPageService::AppListHidden() { | 153 void StartPageService::AppListHidden() { |
| 205 if (contents_->GetWebUI()) { | 154 if (contents_->GetWebUI()) { |
| 206 contents_->GetWebUI()->CallJavascriptFunction( | 155 contents_->GetWebUI()->CallJavascriptFunction( |
| 207 "appList.startPage.onAppListHidden"); | 156 "appList.startPage.onAppListHidden"); |
| 208 } | 157 } |
| 209 if (!app_list::switches::IsExperimentalAppListEnabled()) | 158 if (!app_list::switches::IsExperimentalAppListEnabled()) |
| 210 UnloadContents(); | 159 UnloadContents(); |
| 211 | 160 |
| 212 if (HotwordService::IsExperimentalHotwordingEnabled() && | 161 if (HotwordService::IsExperimentalHotwordingEnabled() && |
| 213 speech_recognizer_) { | 162 speech_recognizer_) { |
| 214 speech_recognizer_->Stop(); | 163 speech_recognizer_->Stop(); |
| 215 } | 164 } |
| 216 | |
| 217 #if defined(OS_CHROMEOS) | |
| 218 audio_status_.reset(); | |
| 219 #endif | |
| 220 } | 165 } |
| 221 | 166 |
| 222 void StartPageService::ToggleSpeechRecognition() { | 167 void StartPageService::ToggleSpeechRecognition() { |
| 223 DCHECK(contents_); | 168 DCHECK(contents_); |
| 224 speech_button_toggled_manually_ = true; | 169 speech_button_toggled_manually_ = true; |
| 225 if (!contents_->GetWebUI()) | 170 if (!contents_->GetWebUI()) |
| 226 return; | 171 return; |
| 227 | 172 |
| 228 if (!webui_finished_loading_) { | 173 if (!webui_finished_loading_) { |
| 229 pending_webui_callbacks_.push_back( | 174 pending_webui_callbacks_.push_back( |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 } | 244 } |
| 300 | 245 |
| 301 void StartPageService::OnSpeechSoundLevelChanged(int16_t level) { | 246 void StartPageService::OnSpeechSoundLevelChanged(int16_t level) { |
| 302 FOR_EACH_OBSERVER(StartPageObserver, | 247 FOR_EACH_OBSERVER(StartPageObserver, |
| 303 observers_, | 248 observers_, |
| 304 OnSpeechSoundLevelChanged(level)); | 249 OnSpeechSoundLevelChanged(level)); |
| 305 } | 250 } |
| 306 | 251 |
| 307 void StartPageService::OnSpeechRecognitionStateChanged( | 252 void StartPageService::OnSpeechRecognitionStateChanged( |
| 308 SpeechRecognitionState new_state) { | 253 SpeechRecognitionState new_state) { |
| 309 #if defined(OS_CHROMEOS) | |
| 310 // Sometimes this can be called even though there are no audio input devices. | |
| 311 if (!audio_status_->CanListen()) | |
| 312 new_state = SPEECH_RECOGNITION_OFF; | |
| 313 #endif | |
| 314 | |
| 315 if (state_ == new_state) | |
| 316 return; | |
| 317 | 254 |
| 318 if (HotwordService::IsExperimentalHotwordingEnabled() && | 255 if (HotwordService::IsExperimentalHotwordingEnabled() && |
| 319 new_state == SPEECH_RECOGNITION_READY && | 256 new_state == SPEECH_RECOGNITION_READY && |
| 320 speech_recognizer_) { | 257 speech_recognizer_) { |
| 321 speech_recognizer_->Stop(); | 258 speech_recognizer_->Stop(); |
| 322 } | 259 } |
| 323 | 260 |
| 324 if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) { | 261 if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) { |
| 325 if (!speech_button_toggled_manually_ && | 262 if (!speech_button_toggled_manually_ && |
| 326 state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) { | 263 state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 339 observers_, | 276 observers_, |
| 340 OnSpeechRecognitionStateChanged(new_state)); | 277 OnSpeechRecognitionStateChanged(new_state)); |
| 341 } | 278 } |
| 342 | 279 |
| 343 content::WebContents* StartPageService::GetSpeechContents() { | 280 content::WebContents* StartPageService::GetSpeechContents() { |
| 344 return GetSpeechRecognitionContents(); | 281 return GetSpeechRecognitionContents(); |
| 345 } | 282 } |
| 346 | 283 |
| 347 void StartPageService::Shutdown() { | 284 void StartPageService::Shutdown() { |
| 348 UnloadContents(); | 285 UnloadContents(); |
| 349 #if defined(OS_CHROMEOS) | |
| 350 audio_status_.reset(); | |
| 351 #endif | |
| 352 } | 286 } |
| 353 | 287 |
| 354 void StartPageService::WebUILoaded() { | 288 void StartPageService::WebUILoaded() { |
| 355 // There's a race condition between the WebUI loading, and calling its JS | 289 // There's a race condition between the WebUI loading, and calling its JS |
| 356 // functions. Specifically, calling LoadContents() doesn't mean that the page | 290 // functions. Specifically, calling LoadContents() doesn't mean that the page |
| 357 // has loaded, but several code paths make this assumption. This function | 291 // has loaded, but several code paths make this assumption. This function |
| 358 // allows us to defer calling JS functions until after the page has finished | 292 // allows us to defer calling JS functions until after the page has finished |
| 359 // loading. | 293 // loading. |
| 360 webui_finished_loading_ = true; | 294 webui_finished_loading_ = true; |
| 361 for (const auto& cb : pending_webui_callbacks_) | 295 for (const auto& cb : pending_webui_callbacks_) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 375 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | 309 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
| 376 std::string()); | 310 std::string()); |
| 377 } | 311 } |
| 378 | 312 |
| 379 void StartPageService::UnloadContents() { | 313 void StartPageService::UnloadContents() { |
| 380 contents_.reset(); | 314 contents_.reset(); |
| 381 webui_finished_loading_ = false; | 315 webui_finished_loading_ = false; |
| 382 } | 316 } |
| 383 | 317 |
| 384 } // namespace app_list | 318 } // namespace app_list |
| OLD | NEW |