start_page_service.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/app_list/start_page_service.h" 6 7#include <string> 8 9#include "base/command_line.h" 10#include "base/memory/singleton.h" 11#include "base/metrics/user_metrics.h" 12#include "chrome/browser/chrome_notification_types.h" 13#include "chrome/browser/media/media_stream_infobar_delegate.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/ui/app_list/recommended_apps.h" 16#include "chrome/browser/ui/app_list/start_page_observer.h" 17#include "chrome/browser/ui/app_list/start_page_service_factory.h" 18#include "chrome/common/chrome_switches.h" 19#include "chrome/common/url_constants.h" 20#include "content/public/browser/notification_details.h" 21#include "content/public/browser/notification_observer.h" 22#include "content/public/browser/notification_registrar.h" 23#include "content/public/browser/notification_service.h" 24#include "content/public/browser/notification_source.h" 25#include "content/public/browser/web_contents.h" 26#include "content/public/browser/web_contents_delegate.h" 27#include "extensions/browser/extension_system_provider.h" 28#include "extensions/browser/extensions_browser_client.h" 29#include "extensions/common/extension.h" 30#include "ui/app_list/app_list_switches.h" 31 32using base::RecordAction; 33using base::UserMetricsAction; 34 35namespace app_list { 36 37namespace { 38 39bool InSpeechRecognition(SpeechRecognitionState state) { 40 return state == SPEECH_RECOGNITION_RECOGNIZING || 41 state == SPEECH_RECOGNITION_IN_SPEECH; 42} 43 44} 45 46class StartPageService::ProfileDestroyObserver 47 : public content::NotificationObserver { 48 public: 49 explicit ProfileDestroyObserver(StartPageService* service) 50 : service_(service) { 51 registrar_.Add(this, 52 chrome::NOTIFICATION_PROFILE_DESTROYED, 53 content::Source<Profile>(service_->profile())); 54 } 55 virtual ~ProfileDestroyObserver() {} 56 57 private: 58 // content::NotificationObserver 59 virtual void Observe(int type, 60 const content::NotificationSource& source, 61 const content::NotificationDetails& details) OVERRIDE { 62 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 63 DCHECK_EQ(service_->profile(), content::Source<Profile>(source).ptr()); 64 service_->Shutdown(); 65 } 66 67 StartPageService* service_; // Owner of this class. 68 content::NotificationRegistrar registrar_; 69 70 DISALLOW_COPY_AND_ASSIGN(ProfileDestroyObserver); 71}; 72 73class StartPageService::StartPageWebContentsDelegate 74 : public content::WebContentsDelegate { 75 public: 76 StartPageWebContentsDelegate() {} 77 virtual ~StartPageWebContentsDelegate() {} 78 79 virtual void RequestMediaAccessPermission( 80 content::WebContents* web_contents, 81 const content::MediaStreamRequest& request, 82 const content::MediaResponseCallback& callback) OVERRIDE { 83 if (MediaStreamInfoBarDelegate::Create(web_contents, request, callback)) 84 NOTREACHED() << "Media stream not allowed for WebUI"; 85 } 86 87 private: 88 DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate); 89}; 90 91// static 92StartPageService* StartPageService::Get(Profile* profile) { 93 return StartPageServiceFactory::GetForProfile(profile); 94} 95 96StartPageService::StartPageService(Profile* profile) 97 : profile_(profile), 98 profile_destroy_observer_(new ProfileDestroyObserver(this)), 99 recommended_apps_(new RecommendedApps(profile)), 100 state_(app_list::SPEECH_RECOGNITION_OFF), 101 speech_button_toggled_manually_(false), 102 speech_result_obtained_(false) { 103#if defined(OS_CHROMEOS) 104 // Updates the default state to hotword listening, because this is 105 // the default behavior. This will be updated when the page is loaded and 106 // the nacl module is loaded. 107 if (app_list::switches::IsVoiceSearchEnabled()) 108 state_ = app_list::SPEECH_RECOGNITION_HOTWORD_LISTENING; 109#endif 110 111 contents_.reset(content::WebContents::Create( 112 content::WebContents::CreateParams(profile_))); 113 contents_delegate_.reset(new StartPageWebContentsDelegate()); 114 contents_->SetDelegate(contents_delegate_.get()); 115 116 GURL url(chrome::kChromeUIAppListStartPageURL); 117 CommandLine* command_line = CommandLine::ForCurrentProcess(); 118 if (command_line->HasSwitch(::switches::kAppListStartPageURL)) { 119 url = GURL( 120 command_line->GetSwitchValueASCII(::switches::kAppListStartPageURL)); 121 } 122 123 contents_->GetController().LoadURL( 124 url, 125 content::Referrer(), 126 content::PAGE_TRANSITION_AUTO_TOPLEVEL, 127 std::string()); 128} 129 130StartPageService::~StartPageService() {} 131 132void StartPageService::AddObserver(StartPageObserver* observer) { 133 observers_.AddObserver(observer); 134} 135 136void StartPageService::RemoveObserver(StartPageObserver* observer) { 137 observers_.RemoveObserver(observer); 138} 139 140void StartPageService::ToggleSpeechRecognition() { 141 speech_button_toggled_manually_ = true; 142 contents_->GetWebUI()->CallJavascriptFunction( 143 "appList.startPage.toggleSpeechRecognition"); 144} 145 146content::WebContents* StartPageService::GetStartPageContents() { 147 return CommandLine::ForCurrentProcess()->HasSwitch( 148 ::switches::kShowAppListStartPage) ? contents_.get() : NULL; 149} 150 151content::WebContents* StartPageService::GetSpeechRecognitionContents() { 152 return app_list::switches::IsVoiceSearchEnabled() ? contents_.get() : NULL; 153} 154 155void StartPageService::OnSpeechResult( 156 const base::string16& query, bool is_final) { 157 if (is_final) { 158 speech_result_obtained_ = true; 159 RecordAction(UserMetricsAction("AppList_SearchedBySpeech")); 160 } 161 FOR_EACH_OBSERVER(StartPageObserver, 162 observers_, 163 OnSpeechResult(query, is_final)); 164} 165 166void StartPageService::OnSpeechSoundLevelChanged(int16 level) { 167 FOR_EACH_OBSERVER(StartPageObserver, 168 observers_, 169 OnSpeechSoundLevelChanged(level)); 170} 171 172void StartPageService::OnSpeechRecognitionStateChanged( 173 SpeechRecognitionState new_state) { 174 if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) { 175 if (!speech_button_toggled_manually_ && 176 state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) { 177 RecordAction(UserMetricsAction("AppList_HotwordRecognized")); 178 } else { 179 RecordAction(UserMetricsAction("AppList_VoiceSearchStartedManually")); 180 } 181 } else if (InSpeechRecognition(state_) && !InSpeechRecognition(new_state) && 182 !speech_result_obtained_) { 183 RecordAction(UserMetricsAction("AppList_VoiceSearchCanceled")); 184 } 185 speech_button_toggled_manually_ = false; 186 speech_result_obtained_ = false; 187 state_ = new_state; 188 FOR_EACH_OBSERVER(StartPageObserver, 189 observers_, 190 OnSpeechRecognitionStateChanged(new_state)); 191} 192 193void StartPageService::Shutdown() { 194 contents_.reset(); 195} 196 197} // namespace app_list 198