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.
5 #include "chrome/browser/ui/app_list/start_page_service.h"
9 #include "base/command_line.h"
10 #include "base/memory/singleton.h"
11 #include "base/metrics/user_metrics.h"
12 #include "base/prefs/pref_service.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/media/media_stream_infobar_delegate.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search/hotword_service_factory.h"
17 #include "chrome/browser/ui/app_list/recommended_apps.h"
18 #include "chrome/browser/ui/app_list/start_page_observer.h"
19 #include "chrome/browser/ui/app_list/start_page_service_factory.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/common/url_constants.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_observer.h"
25 #include "content/public/browser/notification_registrar.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_source.h"
28 #include "content/public/browser/web_contents.h"
29 #include "content/public/browser/web_contents_delegate.h"
30 #include "extensions/browser/extension_system_provider.h"
31 #include "extensions/browser/extensions_browser_client.h"
32 #include "extensions/common/extension.h"
33 #include "ui/app_list/app_list_switches.h"
35 using base::RecordAction;
36 using base::UserMetricsAction;
42 bool InSpeechRecognition(SpeechRecognitionState state) {
43 return state == SPEECH_RECOGNITION_RECOGNIZING ||
44 state == SPEECH_RECOGNITION_IN_SPEECH;
49 class StartPageService::ProfileDestroyObserver
50 : public content::NotificationObserver {
52 explicit ProfileDestroyObserver(StartPageService* service)
55 chrome::NOTIFICATION_PROFILE_DESTROYED,
56 content::Source<Profile>(service_->profile()));
58 virtual ~ProfileDestroyObserver() {}
61 // content::NotificationObserver
62 virtual void Observe(int type,
63 const content::NotificationSource& source,
64 const content::NotificationDetails& details) OVERRIDE {
65 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
66 DCHECK_EQ(service_->profile(), content::Source<Profile>(source).ptr());
70 StartPageService* service_; // Owner of this class.
71 content::NotificationRegistrar registrar_;
73 DISALLOW_COPY_AND_ASSIGN(ProfileDestroyObserver);
76 class StartPageService::StartPageWebContentsDelegate
77 : public content::WebContentsDelegate {
79 StartPageWebContentsDelegate() {}
80 virtual ~StartPageWebContentsDelegate() {}
82 virtual void RequestMediaAccessPermission(
83 content::WebContents* web_contents,
84 const content::MediaStreamRequest& request,
85 const content::MediaResponseCallback& callback) OVERRIDE {
86 if (MediaStreamInfoBarDelegate::Create(web_contents, request, callback))
87 NOTREACHED() << "Media stream not allowed for WebUI";
91 DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate);
95 StartPageService* StartPageService::Get(Profile* profile) {
96 return StartPageServiceFactory::GetForProfile(profile);
99 StartPageService::StartPageService(Profile* profile)
101 profile_destroy_observer_(new ProfileDestroyObserver(this)),
102 recommended_apps_(new RecommendedApps(profile)),
103 state_(app_list::SPEECH_RECOGNITION_OFF),
104 speech_button_toggled_manually_(false),
105 speech_result_obtained_(false) {
106 if (app_list::switches::IsExperimentalAppListEnabled())
110 StartPageService::~StartPageService() {}
112 void StartPageService::AddObserver(StartPageObserver* observer) {
113 observers_.AddObserver(observer);
116 void StartPageService::RemoveObserver(StartPageObserver* observer) {
117 observers_.RemoveObserver(observer);
120 void StartPageService::AppListShown() {
124 contents_->GetWebUI()->CallJavascriptFunction(
125 "appList.startPage.onAppListShown",
126 base::FundamentalValue(HotwordEnabled()));
130 void StartPageService::AppListHidden() {
131 contents_->GetWebUI()->CallJavascriptFunction(
132 "appList.startPage.onAppListHidden");
133 if (!app_list::switches::IsExperimentalAppListEnabled())
137 void StartPageService::ToggleSpeechRecognition() {
138 speech_button_toggled_manually_ = true;
139 contents_->GetWebUI()->CallJavascriptFunction(
140 "appList.startPage.toggleSpeechRecognition");
143 bool StartPageService::HotwordEnabled() {
144 #if defined(OS_CHROMEOS)
145 return HotwordServiceFactory::IsServiceAvailable(profile_) &&
146 profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled);
152 content::WebContents* StartPageService::GetStartPageContents() {
153 return app_list::switches::IsExperimentalAppListEnabled() ? contents_.get()
157 content::WebContents* StartPageService::GetSpeechRecognitionContents() {
158 if (app_list::switches::IsVoiceSearchEnabled()) {
161 return contents_.get();
166 void StartPageService::OnSpeechResult(
167 const base::string16& query, bool is_final) {
169 speech_result_obtained_ = true;
170 RecordAction(UserMetricsAction("AppList_SearchedBySpeech"));
172 FOR_EACH_OBSERVER(StartPageObserver,
174 OnSpeechResult(query, is_final));
177 void StartPageService::OnSpeechSoundLevelChanged(int16 level) {
178 FOR_EACH_OBSERVER(StartPageObserver,
180 OnSpeechSoundLevelChanged(level));
183 void StartPageService::OnSpeechRecognitionStateChanged(
184 SpeechRecognitionState new_state) {
185 if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) {
186 if (!speech_button_toggled_manually_ &&
187 state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) {
188 RecordAction(UserMetricsAction("AppList_HotwordRecognized"));
190 RecordAction(UserMetricsAction("AppList_VoiceSearchStartedManually"));
192 } else if (InSpeechRecognition(state_) && !InSpeechRecognition(new_state) &&
193 !speech_result_obtained_) {
194 RecordAction(UserMetricsAction("AppList_VoiceSearchCanceled"));
196 speech_button_toggled_manually_ = false;
197 speech_result_obtained_ = false;
199 FOR_EACH_OBSERVER(StartPageObserver,
201 OnSpeechRecognitionStateChanged(new_state));
204 void StartPageService::Shutdown() {
208 void StartPageService::LoadContents() {
209 contents_.reset(content::WebContents::Create(
210 content::WebContents::CreateParams(profile_)));
211 contents_delegate_.reset(new StartPageWebContentsDelegate());
212 contents_->SetDelegate(contents_delegate_.get());
214 GURL url(chrome::kChromeUIAppListStartPageURL);
215 CommandLine* command_line = CommandLine::ForCurrentProcess();
216 if (command_line->HasSwitch(::switches::kAppListStartPageURL)) {
218 command_line->GetSwitchValueASCII(::switches::kAppListStartPageURL));
221 contents_->GetController().LoadURL(
224 content::PAGE_TRANSITION_AUTO_TOPLEVEL,
228 void StartPageService::UnloadContents() {
232 } // namespace app_list