Chromium Code Reviews| 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 25 matching lines...) Expand all Loading... | |
| 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 using base::RecordAction; | 39 using base::RecordAction; |
| 40 using base::UserMetricsAction; | 40 using base::UserMetricsAction; |
| 41 | 41 |
| 42 namespace app_list { | 42 namespace app_list { |
| 43 | 43 |
| 44 namespace { | 44 namespace { |
| 45 | 45 |
| 46 bool IsVoiceSearchEnabled() { | |
|
tapted
2014/11/25 05:03:10
It's a bit confusing having standalone `IsVoiceSea
Jun Mukai
2014/11/26 01:39:21
Done to rename it to CanListen.
Not so sure about
| |
| 47 if (!app_list::switches::IsVoiceSearchEnabled()) | |
| 48 return false; | |
| 49 #if defined(OS_CHROMEOS) | |
| 50 if (!chromeos::CrasAudioHandler::IsInitialized()) | |
| 51 return false; | |
| 52 chromeos::CrasAudioHandler* audio_handler = chromeos::CrasAudioHandler::Get(); | |
| 53 if (!audio_handler->GetPrimaryActiveInputNode()) | |
| 54 return false; | |
| 55 if (audio_handler->IsInputMuted()) | |
| 56 return false; | |
| 57 #endif | |
| 58 return true; | |
| 59 } | |
| 60 | |
| 46 bool InSpeechRecognition(SpeechRecognitionState state) { | 61 bool InSpeechRecognition(SpeechRecognitionState state) { |
| 47 return state == SPEECH_RECOGNITION_RECOGNIZING || | 62 return state == SPEECH_RECOGNITION_RECOGNIZING || |
| 48 state == SPEECH_RECOGNITION_IN_SPEECH; | 63 state == SPEECH_RECOGNITION_IN_SPEECH; |
| 49 } | 64 } |
| 50 | 65 |
| 51 } | 66 } // namespace |
| 52 | 67 |
| 53 class StartPageService::ProfileDestroyObserver | 68 class StartPageService::ProfileDestroyObserver |
| 54 : public content::NotificationObserver { | 69 : public content::NotificationObserver { |
| 55 public: | 70 public: |
| 56 explicit ProfileDestroyObserver(StartPageService* service) | 71 explicit ProfileDestroyObserver(StartPageService* service) |
| 57 : service_(service) { | 72 : service_(service) { |
| 58 registrar_.Add(this, | 73 registrar_.Add(this, |
| 59 chrome::NOTIFICATION_PROFILE_DESTROYED, | 74 chrome::NOTIFICATION_PROFILE_DESTROYED, |
| 60 content::Source<Profile>(service_->profile())); | 75 content::Source<Profile>(service_->profile())); |
| 61 } | 76 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 112 profile_destroy_observer_(new ProfileDestroyObserver(this)), | 127 profile_destroy_observer_(new ProfileDestroyObserver(this)), |
| 113 recommended_apps_(new RecommendedApps(profile)), | 128 recommended_apps_(new RecommendedApps(profile)), |
| 114 state_(app_list::SPEECH_RECOGNITION_OFF), | 129 state_(app_list::SPEECH_RECOGNITION_OFF), |
| 115 speech_button_toggled_manually_(false), | 130 speech_button_toggled_manually_(false), |
| 116 speech_result_obtained_(false), | 131 speech_result_obtained_(false), |
| 117 webui_finished_loading_(false), | 132 webui_finished_loading_(false), |
| 118 weak_factory_(this) { | 133 weak_factory_(this) { |
| 119 // If experimental hotwording is enabled, then we're always "ready". | 134 // If experimental hotwording is enabled, then we're always "ready". |
| 120 // Transitioning into the "hotword recognizing" state is handled by the | 135 // Transitioning into the "hotword recognizing" state is handled by the |
| 121 // hotword extension. | 136 // hotword extension. |
| 122 if (HotwordService::IsExperimentalHotwordingEnabled()) | 137 if (IsVoiceSearchEnabled() && |
| 138 HotwordService::IsExperimentalHotwordingEnabled()) { | |
| 123 state_ = app_list::SPEECH_RECOGNITION_READY; | 139 state_ = app_list::SPEECH_RECOGNITION_READY; |
| 140 } | |
| 124 | 141 |
| 125 if (app_list::switches::IsExperimentalAppListEnabled()) | 142 if (app_list::switches::IsExperimentalAppListEnabled()) |
| 126 LoadContents(); | 143 LoadContents(); |
| 127 } | 144 } |
| 128 | 145 |
| 129 StartPageService::~StartPageService() {} | 146 StartPageService::~StartPageService() {} |
| 130 | 147 |
| 131 void StartPageService::AddObserver(StartPageObserver* observer) { | 148 void StartPageService::AddObserver(StartPageObserver* observer) { |
| 132 observers_.AddObserver(observer); | 149 observers_.AddObserver(observer); |
| 133 } | 150 } |
| 134 | 151 |
| 135 void StartPageService::RemoveObserver(StartPageObserver* observer) { | 152 void StartPageService::RemoveObserver(StartPageObserver* observer) { |
| 136 observers_.RemoveObserver(observer); | 153 observers_.RemoveObserver(observer); |
| 137 } | 154 } |
| 138 | 155 |
| 139 void StartPageService::AppListShown() { | 156 void StartPageService::AppListShown() { |
| 140 if (!contents_) { | 157 if (!contents_) { |
| 141 LoadContents(); | 158 LoadContents(); |
| 142 } else if (contents_->GetWebUI() && | 159 } else if (contents_->GetWebUI() && |
| 143 !HotwordService::IsExperimentalHotwordingEnabled()) { | 160 !HotwordService::IsExperimentalHotwordingEnabled()) { |
| 144 // If experimental hotwording is enabled, don't call onAppListShown. | 161 // If experimental hotwording is enabled, don't call onAppListShown. |
| 145 // onAppListShown() initializes the web speech API, which is not used with | 162 // onAppListShown() initializes the web speech API, which is not used with |
| 146 // experimental hotwording. | 163 // experimental hotwording. |
| 147 contents_->GetWebUI()->CallJavascriptFunction( | 164 contents_->GetWebUI()->CallJavascriptFunction( |
| 148 "appList.startPage.onAppListShown", | 165 "appList.startPage.onAppListShown", |
| 149 base::FundamentalValue(HotwordEnabled())); | 166 base::FundamentalValue(HotwordEnabled())); |
| 150 } | 167 } |
| 168 #if defined(OS_CHROMEOS) | |
| 169 chromeos::CrasAudioHandler::Get()->AddAudioObserver(this); | |
|
tapted
2014/11/25 11:07:52
Also, what are the implications for always-on-hotw
Jun Mukai
2014/11/26 01:39:21
If that flag is specified, indeed it attempts to r
tapted
2014/11/26 02:05:58
So long as always-on isn't worse with it like this
Anand Mistry (off Chromium)
2014/11/26 10:49:58
If I understand this change correctly, under the n
Jun Mukai
2014/11/26 21:59:44
That is right. But I guess the hotworder will stop
Jun Mukai
2014/11/26 23:29:50
After thinking again, I've realized that this is s
| |
| 170 #endif | |
| 151 } | 171 } |
| 152 | 172 |
| 153 void StartPageService::AppListHidden() { | 173 void StartPageService::AppListHidden() { |
| 154 if (contents_->GetWebUI()) { | 174 if (contents_->GetWebUI()) { |
| 155 contents_->GetWebUI()->CallJavascriptFunction( | 175 contents_->GetWebUI()->CallJavascriptFunction( |
| 156 "appList.startPage.onAppListHidden"); | 176 "appList.startPage.onAppListHidden"); |
| 157 } | 177 } |
| 158 if (!app_list::switches::IsExperimentalAppListEnabled()) | 178 if (!app_list::switches::IsExperimentalAppListEnabled()) |
| 159 UnloadContents(); | 179 UnloadContents(); |
| 160 | 180 |
| 161 if (HotwordService::IsExperimentalHotwordingEnabled() && | 181 if (HotwordService::IsExperimentalHotwordingEnabled() && |
| 162 speech_recognizer_) { | 182 speech_recognizer_) { |
| 163 speech_recognizer_->Stop(); | 183 speech_recognizer_->Stop(); |
| 164 } | 184 } |
| 185 #if defined(OS_CHROMEOS) | |
| 186 chromeos::CrasAudioHandler::Get()->RemoveAudioObserver(this); | |
| 187 #endif | |
| 165 } | 188 } |
| 166 | 189 |
| 167 void StartPageService::ToggleSpeechRecognition() { | 190 void StartPageService::ToggleSpeechRecognition() { |
| 168 DCHECK(contents_); | 191 DCHECK(contents_); |
| 169 speech_button_toggled_manually_ = true; | 192 speech_button_toggled_manually_ = true; |
| 170 if (!contents_->GetWebUI()) | 193 if (!contents_->GetWebUI()) |
| 171 return; | 194 return; |
| 172 | 195 |
| 173 if (!webui_finished_loading_) { | 196 if (!webui_finished_loading_) { |
| 174 pending_webui_callbacks_.push_back( | 197 pending_webui_callbacks_.push_back( |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 return false; | 241 return false; |
| 219 #endif | 242 #endif |
| 220 } | 243 } |
| 221 | 244 |
| 222 content::WebContents* StartPageService::GetStartPageContents() { | 245 content::WebContents* StartPageService::GetStartPageContents() { |
| 223 return app_list::switches::IsExperimentalAppListEnabled() ? contents_.get() | 246 return app_list::switches::IsExperimentalAppListEnabled() ? contents_.get() |
| 224 : NULL; | 247 : NULL; |
| 225 } | 248 } |
| 226 | 249 |
| 227 content::WebContents* StartPageService::GetSpeechRecognitionContents() { | 250 content::WebContents* StartPageService::GetSpeechRecognitionContents() { |
| 228 if (app_list::switches::IsVoiceSearchEnabled()) { | 251 if (IsVoiceSearchEnabled()) { |
|
tapted
2014/11/25 05:03:10
Why this change? It doesn't seem robust to return
Jun Mukai
2014/11/26 01:39:21
Reverted back to the original. The original motiv
| |
| 229 if (!contents_) | 252 if (!contents_) |
| 230 LoadContents(); | 253 LoadContents(); |
| 231 return contents_.get(); | 254 return contents_.get(); |
| 232 } | 255 } |
| 233 return NULL; | 256 return NULL; |
| 234 } | 257 } |
| 235 | 258 |
| 236 void StartPageService::OnSpeechResult( | 259 void StartPageService::OnSpeechResult( |
| 237 const base::string16& query, bool is_final) { | 260 const base::string16& query, bool is_final) { |
| 238 if (is_final) { | 261 if (is_final) { |
| 239 speech_result_obtained_ = true; | 262 speech_result_obtained_ = true; |
| 240 RecordAction(UserMetricsAction("AppList_SearchedBySpeech")); | 263 RecordAction(UserMetricsAction("AppList_SearchedBySpeech")); |
| 241 } | 264 } |
| 242 FOR_EACH_OBSERVER(StartPageObserver, | 265 FOR_EACH_OBSERVER(StartPageObserver, |
| 243 observers_, | 266 observers_, |
| 244 OnSpeechResult(query, is_final)); | 267 OnSpeechResult(query, is_final)); |
| 245 } | 268 } |
| 246 | 269 |
| 247 void StartPageService::OnSpeechSoundLevelChanged(int16_t level) { | 270 void StartPageService::OnSpeechSoundLevelChanged(int16_t level) { |
| 248 FOR_EACH_OBSERVER(StartPageObserver, | 271 FOR_EACH_OBSERVER(StartPageObserver, |
| 249 observers_, | 272 observers_, |
| 250 OnSpeechSoundLevelChanged(level)); | 273 OnSpeechSoundLevelChanged(level)); |
| 251 } | 274 } |
| 252 | 275 |
| 253 void StartPageService::OnSpeechRecognitionStateChanged( | 276 void StartPageService::OnSpeechRecognitionStateChanged( |
| 254 SpeechRecognitionState new_state) { | 277 SpeechRecognitionState new_state) { |
| 278 // Sometimes this can be called even though there are no audio input devices. | |
| 279 if (!IsVoiceSearchEnabled()) | |
| 280 new_state = SPEECH_RECOGNITION_OFF; | |
|
tapted
2014/11/25 05:03:10
This can leave new_state == state_ -- should that
Jun Mukai
2014/11/26 01:39:21
Done.
| |
| 255 | 281 |
| 256 if (HotwordService::IsExperimentalHotwordingEnabled() && | 282 if (HotwordService::IsExperimentalHotwordingEnabled() && |
| 257 new_state == SPEECH_RECOGNITION_READY && | 283 new_state == SPEECH_RECOGNITION_READY && |
| 258 speech_recognizer_) { | 284 speech_recognizer_) { |
| 259 speech_recognizer_->Stop(); | 285 speech_recognizer_->Stop(); |
| 260 } | 286 } |
| 261 | 287 |
| 262 if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) { | 288 if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) { |
| 263 if (!speech_button_toggled_manually_ && | 289 if (!speech_button_toggled_manually_ && |
| 264 state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) { | 290 state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 279 } | 305 } |
| 280 | 306 |
| 281 content::WebContents* StartPageService::GetSpeechContents() { | 307 content::WebContents* StartPageService::GetSpeechContents() { |
| 282 return GetSpeechRecognitionContents(); | 308 return GetSpeechRecognitionContents(); |
| 283 } | 309 } |
| 284 | 310 |
| 285 void StartPageService::Shutdown() { | 311 void StartPageService::Shutdown() { |
| 286 UnloadContents(); | 312 UnloadContents(); |
| 287 } | 313 } |
| 288 | 314 |
| 315 #if defined(OS_CHROMEOS) | |
| 316 void StartPageService::OnInputMuteChanged() { | |
| 317 if (IsVoiceSearchEnabled()) | |
| 318 OnSpeechRecognitionStateChanged(SPEECH_RECOGNITION_READY); | |
| 319 else | |
| 320 OnSpeechRecognitionStateChanged(SPEECH_RECOGNITION_OFF); | |
| 321 } | |
| 322 | |
| 323 void StartPageService::OnActiveInputNodeChanged() { | |
| 324 OnInputMuteChanged(); | |
| 325 } | |
| 326 #endif | |
| 327 | |
| 289 void StartPageService::WebUILoaded() { | 328 void StartPageService::WebUILoaded() { |
| 290 // There's a race condition between the WebUI loading, and calling its JS | 329 // There's a race condition between the WebUI loading, and calling its JS |
| 291 // functions. Specifically, calling LoadContents() doesn't mean that the page | 330 // functions. Specifically, calling LoadContents() doesn't mean that the page |
| 292 // has loaded, but several code paths make this assumption. This function | 331 // has loaded, but several code paths make this assumption. This function |
| 293 // allows us to defer calling JS functions until after the page has finished | 332 // allows us to defer calling JS functions until after the page has finished |
| 294 // loading. | 333 // loading. |
| 295 webui_finished_loading_ = true; | 334 webui_finished_loading_ = true; |
| 296 for (const auto& cb : pending_webui_callbacks_) | 335 for (const auto& cb : pending_webui_callbacks_) |
| 297 cb.Run(); | 336 cb.Run(); |
| 298 pending_webui_callbacks_.clear(); | 337 pending_webui_callbacks_.clear(); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 317 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | 356 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
| 318 std::string()); | 357 std::string()); |
| 319 } | 358 } |
| 320 | 359 |
| 321 void StartPageService::UnloadContents() { | 360 void StartPageService::UnloadContents() { |
| 322 contents_.reset(); | 361 contents_.reset(); |
| 323 webui_finished_loading_ = false; | 362 webui_finished_loading_ = false; |
| 324 } | 363 } |
| 325 | 364 |
| 326 } // namespace app_list | 365 } // namespace app_list |
| OLD | NEW |