14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
24e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
34e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// found in the LICENSE file.
44e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/start_page_service.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/command_line.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/singleton.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/user_metrics.h"
12c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/prefs/pref_service.h"
134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/media/media_stream_infobar_delegate.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/search/hotword_service.h"
17c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/search/hotword_service_factory.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/recommended_apps.h"
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/app_list/start_page_observer.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/app_list/start_page_service_factory.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
22c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/common/pref_names.h"
234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/url_constants.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_details.h"
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_observer.h"
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_registrar.h"
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/notification_service.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/notification_source.h"
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/web_contents.h"
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/web_contents_delegate.h"
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system_provider.h"
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/app_list/app_list_switches.h"
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::RecordAction;
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UserMetricsAction;
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace app_list {
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool InSpeechRecognition(SpeechRecognitionState state) {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return state == SPEECH_RECOGNITION_RECOGNIZING ||
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      state == SPEECH_RECOGNITION_IN_SPEECH;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class StartPageService::ProfileDestroyObserver
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : public content::NotificationObserver {
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) public:
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  explicit ProfileDestroyObserver(StartPageService* service)
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      : service_(service) {
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    registrar_.Add(this,
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   chrome::NOTIFICATION_PROFILE_DESTROYED,
57f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                   content::Source<Profile>(service_->profile()));
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~ProfileDestroyObserver() {}
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // content::NotificationObserver
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual void Observe(int type,
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       const content::NotificationSource& source,
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                       const content::NotificationDetails& details) OVERRIDE {
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK_EQ(service_->profile(), content::Source<Profile>(source).ptr());
684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    service_->Shutdown();
694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  StartPageService* service_;  // Owner of this class.
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  content::NotificationRegistrar registrar_;
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ProfileDestroyObserver);
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class StartPageService::StartPageWebContentsDelegate
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    : public content::WebContentsDelegate {
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public:
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  StartPageWebContentsDelegate() {}
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~StartPageWebContentsDelegate() {}
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void RequestMediaAccessPermission(
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      content::WebContents* web_contents,
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const content::MediaStreamRequest& request,
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const content::MediaResponseCallback& callback) OVERRIDE {
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (MediaStreamInfoBarDelegate::Create(web_contents, request, callback))
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      NOTREACHED() << "Media stream not allowed for WebUI";
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual bool CheckMediaAccessPermission(
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::WebContents* web_contents,
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const GURL& security_origin,
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::MediaStreamType type) OVERRIDE {
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return MediaCaptureDevicesDispatcher::GetInstance()
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ->CheckMediaAccessPermission(web_contents, security_origin, type);
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) private:
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(StartPageWebContentsDelegate);
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// static
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StartPageService* StartPageService::Get(Profile* profile) {
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return StartPageServiceFactory::GetForProfile(profile);
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StartPageService::StartPageService(Profile* profile)
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : profile_(profile),
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      profile_destroy_observer_(new ProfileDestroyObserver(this)),
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      recommended_apps_(new RecommendedApps(profile)),
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      state_(app_list::SPEECH_RECOGNITION_OFF),
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      speech_button_toggled_manually_(false),
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      speech_result_obtained_(false) {
11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // If experimental hotwording is enabled, then we're always "ready".
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Transitioning into the "hotword recognizing" state is handled by the
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // hotword extension.
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (HotwordService::IsExperimentalHotwordingEnabled())
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    state_ = app_list::SPEECH_RECOGNITION_READY;
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (app_list::switches::IsExperimentalAppListEnabled())
122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LoadContents();
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StartPageService::~StartPageService() {}
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void StartPageService::AddObserver(StartPageObserver* observer) {
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  observers_.AddObserver(observer);
129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void StartPageService::RemoveObserver(StartPageObserver* observer) {
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  observers_.RemoveObserver(observer);
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid StartPageService::AppListShown() {
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!contents_) {
137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    LoadContents();
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  } else {
13903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // If experimental hotwording is enabled, don't enable hotwording in the
14003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    // start page, since the hotword extension is taking care of this.
14103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    bool hotword_enabled = HotwordEnabled() &&
14203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        !HotwordService::IsExperimentalHotwordingEnabled();
143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    contents_->GetWebUI()->CallJavascriptFunction(
144c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "appList.startPage.onAppListShown",
14503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        base::FundamentalValue(hotword_enabled));
146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid StartPageService::AppListHidden() {
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  contents_->GetWebUI()->CallJavascriptFunction(
151c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      "appList.startPage.onAppListHidden");
152c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!app_list::switches::IsExperimentalAppListEnabled())
153c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    UnloadContents();
154c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void StartPageService::ToggleSpeechRecognition() {
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  speech_button_toggled_manually_ = true;
158f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  contents_->GetWebUI()->CallJavascriptFunction(
159f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      "appList.startPage.toggleSpeechRecognition");
160f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
161f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
162c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool StartPageService::HotwordEnabled() {
16303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (HotwordService::IsExperimentalHotwordingEnabled()) {
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    return HotwordServiceFactory::IsServiceAvailable(profile_) &&
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled);
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#if defined(OS_CHROMEOS)
168010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return HotwordServiceFactory::IsServiceAvailable(profile_) &&
169010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled);
170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#else
171c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return false;
172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#endif
173c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)content::WebContents* StartPageService::GetStartPageContents() {
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return app_list::switches::IsExperimentalAppListEnabled() ? contents_.get()
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                                            : NULL;
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)content::WebContents* StartPageService::GetSpeechRecognitionContents() {
181c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (app_list::switches::IsVoiceSearchEnabled()) {
182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    if (!contents_)
183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      LoadContents();
184c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return contents_.get();
185c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
186c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return NULL;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StartPageService::OnSpeechResult(
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& query, bool is_final) {
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (is_final) {
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    speech_result_obtained_ = true;
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RecordAction(UserMetricsAction("AppList_SearchedBySpeech"));
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  FOR_EACH_OBSERVER(StartPageObserver,
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    observers_,
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    OnSpeechResult(query, is_final));
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StartPageService::OnSpeechSoundLevelChanged(int16 level) {
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  FOR_EACH_OBSERVER(StartPageObserver,
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    observers_,
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    OnSpeechSoundLevelChanged(level));
204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StartPageService::OnSpeechRecognitionStateChanged(
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    SpeechRecognitionState new_state) {
208c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (!InSpeechRecognition(state_) && InSpeechRecognition(new_state)) {
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!speech_button_toggled_manually_ &&
210c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        state_ == SPEECH_RECOGNITION_HOTWORD_LISTENING) {
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RecordAction(UserMetricsAction("AppList_HotwordRecognized"));
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    } else {
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      RecordAction(UserMetricsAction("AppList_VoiceSearchStartedManually"));
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  } else if (InSpeechRecognition(state_) && !InSpeechRecognition(new_state) &&
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             !speech_result_obtained_) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RecordAction(UserMetricsAction("AppList_VoiceSearchCanceled"));
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  speech_button_toggled_manually_ = false;
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  speech_result_obtained_ = false;
221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_ = new_state;
222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  FOR_EACH_OBSERVER(StartPageObserver,
223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    observers_,
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    OnSpeechRecognitionStateChanged(new_state));
225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StartPageService::Shutdown() {
228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  UnloadContents();
229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid StartPageService::LoadContents() {
232c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  contents_.reset(content::WebContents::Create(
233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      content::WebContents::CreateParams(profile_)));
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  contents_delegate_.reset(new StartPageWebContentsDelegate());
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  contents_->SetDelegate(contents_delegate_.get());
236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GURL url(chrome::kChromeUIAppListStartPageURL);
238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CommandLine* command_line = CommandLine::ForCurrentProcess();
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (command_line->HasSwitch(::switches::kAppListStartPageURL)) {
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    url = GURL(
241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        command_line->GetSwitchValueASCII(::switches::kAppListStartPageURL));
242c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
243c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
244c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  contents_->GetController().LoadURL(
245c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      url,
246c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      content::Referrer(),
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
248c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      std::string());
249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
250c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
251c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid StartPageService::UnloadContents() {
2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  contents_.reset();
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace app_list
256