start_page_handler.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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/webui/app_list/start_page_handler.h"
64e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <string>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/bind.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/prefs/pref_service.h"
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/values.h"
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/chrome_notification_types.h"
144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/search/hotword_service.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/search/hotword_service_factory.h"
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/app_list_service.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/app_list/hotword_background_activity_monitor.h"
214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/recommended_apps.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/start_page_service.h"
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/ui/host_desktop.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/extensions/extension_icon_set.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/pref_names.h"
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/notification_details.h"
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/notification_source.h"
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/render_process_host.h"
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/web_contents.h"
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "content/public/browser/web_contents_view.h"
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/browser/web_ui.h"
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/common/child_process_host.h"
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/app_list/app_list_switches.h"
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "ui/events/event_constants.h"
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace app_list {
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)namespace {
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)scoped_ptr<base::DictionaryValue> CreateAppInfo(
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const extensions::Extension* app) {
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dict->SetString("appId", app->id());
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dict->SetString("textTitle", app->short_name());
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dict->SetString("title", app->name());
494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const bool grayscale = false;
514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  bool icon_exists = true;
524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  GURL icon_url = extensions::ExtensionIconSource::GetIconURL(
534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      app,
544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      extension_misc::EXTENSION_ICON_MEDIUM,
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ExtensionIconSet::MATCH_BIGGER,
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      grayscale,
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      &icon_exists);
584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  dict->SetString("iconUrl", icon_url.spec());
594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  return dict.Pass();
614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace
644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)StartPageHandler::StartPageHandler()
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : recommended_apps_(NULL),
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      has_hotword_recognizer_(false),
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      last_state_(SPEECH_RECOGNITION_OFF) {
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)StartPageHandler::~StartPageHandler() {
724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (recommended_apps_)
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    recommended_apps_->RemoveObserver(this);
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StartPageHandler::RegisterMessages() {
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  web_ui()->RegisterMessageCallback(
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      "initialize",
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(&StartPageHandler::HandleInitialize, base::Unretained(this)));
804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  web_ui()->RegisterMessageCallback(
814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      "launchApp",
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::Bind(&StartPageHandler::HandleLaunchApp, base::Unretained(this)));
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_ui()->RegisterMessageCallback(
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "setHotwordRecognizerState",
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&StartPageHandler::HandleHotwordRecognizerState,
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::Unretained(this)));
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  web_ui()->RegisterMessageCallback(
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "speechResult",
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&StartPageHandler::HandleSpeechResult,
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 base::Unretained(this)));
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  web_ui()->RegisterMessageCallback(
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "speechSoundLevel",
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::Bind(&StartPageHandler::HandleSpeechSoundLevel,
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                 base::Unretained(this)));
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  web_ui()->RegisterMessageCallback(
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      "setSpeechRecognitionState",
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&StartPageHandler::HandleSpeechRecognition,
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 base::Unretained(this)));
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void StartPageHandler::Observe(int type,
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               const content::NotificationSource& source,
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                               const content::NotificationDetails& details) {
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_CHROMEOS)
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_EQ(Profile::FromWebUI(web_ui()),
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            content::Source<Profile>(source).ptr());
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  switch (type) {
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_LOADED: {
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::Extension* extension =
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          content::Details<extensions::Extension>(details).ptr();
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (extension->id() == extension_misc::kHotwordExtensionId)
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        OnHotwordEnabledChanged();
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::UnloadedExtensionInfo* info =
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          content::Details<extensions::UnloadedExtensionInfo>(details).ptr();
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (info->extension->id() == extension_misc::kHotwordExtensionId)
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        OnHotwordEnabledChanged();
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    default:
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      NOTREACHED();
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      break;
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)int StartPageHandler::GetRenderProcessID() {
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!web_ui())
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return content::ChildProcessHost::kInvalidUniqueID;
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  content::WebContents* web_contents = web_ui()->GetWebContents();
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return web_contents->GetRenderProcessHost()->GetID();
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void StartPageHandler::OnHotwordBackgroundActivityChanged() {
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#if defined(OS_CHROMEOS)
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (has_hotword_recognizer_ && switches::IsHotwordAlwaysOnEnabled()) {
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    web_ui()->CallJavascriptFunction(
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        (hotword_monitor_ && hotword_monitor_->IsHotwordBackgroundActive()) ?
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        "appList.startPage.startHotwordRecognition" :
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        "appList.startPage.stopHotwordRecognition");
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#endif
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StartPageHandler::OnRecommendedAppsChanged() {
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SendRecommendedApps();
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StartPageHandler::SendRecommendedApps() {
1524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const RecommendedApps::Apps& recommends = recommended_apps_->apps();
1534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::ListValue recommended_list;
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  for (size_t i = 0; i < recommends.size(); ++i) {
1564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    recommended_list.Append(CreateAppInfo(recommends[i].get()).release());
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  web_ui()->CallJavascriptFunction("appList.startPage.setRecommendedApps",
1604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                   recommended_list);
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool StartPageHandler::HotwordEnabled() {
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = Profile::FromWebUI(web_ui());
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!HotwordService::DoesHotwordSupportLanguage(profile))
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const PrefService::Preference* preference =
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      profile->GetPrefs()->FindPreference(prefs::kHotwordSearchEnabled);
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!preference)
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!HotwordServiceFactory::IsServiceAvailable(profile))
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // kHotwordSearchEnabled is off by default, but app-list is on by default.
179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // To achieve this, we'll return true if it's in the default status.
180a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (preference->IsDefaultValue())
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
183a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool isEnabled = false;
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return preference->GetValue()->GetAsBoolean(&isEnabled) && isEnabled;
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void StartPageHandler::OnHotwordEnabledChanged() {
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  web_ui()->CallJavascriptFunction(
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "appList.startPage.setHotwordEnabled",
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::FundamentalValue(HotwordEnabled()));
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StartPageHandler::HandleInitialize(const base::ListValue* args) {
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Profile* profile = Profile::FromWebUI(web_ui());
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  StartPageService* service = StartPageService::Get(profile);
1974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!service)
1984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  recommended_apps_ = service->recommended_apps();
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  recommended_apps_->AddObserver(this);
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  SendRecommendedApps();
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_CHROMEOS)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (app_list::switches::IsVoiceSearchEnabled() &&
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      HotwordService::DoesHotwordSupportLanguage(profile)) {
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OnHotwordEnabledChanged();
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pref_change_registrar_.Init(profile->GetPrefs());
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    pref_change_registrar_.Add(
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        prefs::kHotwordSearchEnabled,
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Bind(&StartPageHandler::OnHotwordEnabledChanged,
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   base::Unretained(this)));
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   content::Source<Profile>(profile));
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                   content::Source<Profile>(profile));
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    hotword_monitor_.reset(new HotwordBackgroundActivityMonitor(this));
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool StartPageHandler::ShouldRunHotwordBackground() {
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return has_hotword_recognizer_ && switches::IsHotwordAlwaysOnEnabled() &&
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      hotword_monitor_ && hotword_monitor_->IsHotwordBackgroundActive();
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void StartPageHandler::HandleLaunchApp(const base::ListValue* args) {
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  std::string app_id;
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  CHECK(args->GetString(0, &app_id));
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Profile* profile = Profile::FromWebUI(web_ui());
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionService* service =
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      extensions::ExtensionSystem::Get(profile)->extension_service();
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  const extensions::Extension* app = service->GetInstalledExtension(app_id);
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (!app) {
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    NOTREACHED();
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  AppListControllerDelegate* controller = AppListService::Get(
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      chrome::GetHostDesktopTypeForNativeView(
243f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          web_ui()->GetWebContents()->GetView()->GetNativeView()))
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ->GetControllerDelegate();
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  controller->ActivateApp(profile,
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          app,
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                          ui::EF_NONE);
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void StartPageHandler::HandleHotwordRecognizerState(
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::ListValue* args) {
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  CHECK(args->GetBoolean(0, &has_hotword_recognizer_));
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (last_state_ == SPEECH_RECOGNITION_READY && ShouldRunHotwordBackground()) {
255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    web_ui()->CallJavascriptFunction(
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        "appList.startPage.startHotwordRecognition");
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StartPageHandler::HandleSpeechResult(const base::ListValue* args) {
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::string16 query;
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool is_final = false;
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  CHECK(args->GetString(0, &query));
264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CHECK(args->GetBoolean(1, &is_final));
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  StartPageService::Get(Profile::FromWebUI(web_ui()))->OnSpeechResult(
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      query, is_final);
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void StartPageHandler::HandleSpeechSoundLevel(const base::ListValue* args) {
271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  double level;
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CHECK(args->GetDouble(0, &level));
273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  StartPageService* service =
275a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      StartPageService::Get(Profile::FromWebUI(web_ui()));
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (service)
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    service->OnSpeechSoundLevelChanged(static_cast<int16>(level));
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void StartPageHandler::HandleSpeechRecognition(const base::ListValue* args) {
281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::string state_string;
282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CHECK(args->GetString(0, &state_string));
283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SpeechRecognitionState new_state = SPEECH_RECOGNITION_OFF;
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (state_string == "READY")
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new_state = SPEECH_RECOGNITION_READY;
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (state_string == "HOTWORD_RECOGNIZING")
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new_state = SPEECH_RECOGNITION_HOTWORD_LISTENING;
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (state_string == "RECOGNIZING")
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new_state = SPEECH_RECOGNITION_RECOGNIZING;
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (state_string == "IN_SPEECH")
292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    new_state = SPEECH_RECOGNITION_IN_SPEECH;
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  else if (state_string == "STOPPING")
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    new_state = SPEECH_RECOGNITION_STOPPING;
295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  last_state_ = new_state;
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Profile* profile = Profile::FromWebUI(web_ui());
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  StartPageService* service = StartPageService::Get(profile);
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (service)
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    service->OnSpeechRecognitionStateChanged(new_state);
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (new_state == SPEECH_RECOGNITION_READY && ShouldRunHotwordBackground()) {
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    web_ui()->CallJavascriptFunction(
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        "appList.startPage.startHotwordRecognition");
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
306f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}  // namespace app_list
309