start_page_handler.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Copyright 2013 The Chromium Authors. All rights reserved.
230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// Use of this source code is governed by a BSD-style license that can be
330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun// found in the LICENSE file.
430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/webui/app_list/start_page_handler.h"
630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include <string>
830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "base/bind.h"
1030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "base/memory/scoped_ptr.h"
1130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "base/values.h"
1230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "base/version.h"
1330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/omaha_query_params/omaha_query_params.h"
1430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/profiles/profile.h"
1530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/search/hotword_service.h"
1630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
1730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/app_list/app_list_service.h"
1830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/app_list/recommended_apps.h"
1930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/app_list/start_page_service.h"
2030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/host_desktop.h"
2130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
2230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "chrome/common/pref_names.h"
2330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "content/public/browser/web_ui.h"
2430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "extensions/browser/extension_registry.h"
2530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "extensions/browser/extension_system.h"
2630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "extensions/common/constants.h"
2730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "extensions/common/extension.h"
2830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "extensions/common/extension_icon_set.h"
2930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "ui/app_list/app_list_switches.h"
3030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "ui/app_list/speech_ui_model_observer.h"
3130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "ui/events/event_constants.h"
3230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
3330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunnamespace app_list {
3430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
3530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunnamespace {
3630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
3730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if defined(OS_CHROMEOS)
3830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunconst char kOldHotwordExtensionVersionString[] = "0.1.1.5014_0";
3930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif
4030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun
4130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunscoped_ptr<base::DictionaryValue> CreateAppInfo(
42    const extensions::Extension* app) {
43  scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
44  dict->SetString("appId", app->id());
45  dict->SetString("textTitle", app->short_name());
46  dict->SetString("title", app->name());
47
48  const bool grayscale = false;
49  bool icon_exists = true;
50  GURL icon_url = extensions::ExtensionIconSource::GetIconURL(
51      app,
52      extension_misc::EXTENSION_ICON_MEDIUM,
53      ExtensionIconSet::MATCH_BIGGER,
54      grayscale,
55      &icon_exists);
56  dict->SetString("iconUrl", icon_url.spec());
57
58  return dict.Pass();
59}
60
61}  // namespace
62
63StartPageHandler::StartPageHandler()
64    : recommended_apps_(NULL),
65      extension_registry_observer_(this) {
66}
67
68StartPageHandler::~StartPageHandler() {
69  if (recommended_apps_)
70    recommended_apps_->RemoveObserver(this);
71}
72
73void StartPageHandler::RegisterMessages() {
74  web_ui()->RegisterMessageCallback(
75      "initialize",
76      base::Bind(&StartPageHandler::HandleInitialize, base::Unretained(this)));
77  web_ui()->RegisterMessageCallback(
78      "launchApp",
79      base::Bind(&StartPageHandler::HandleLaunchApp, base::Unretained(this)));
80  web_ui()->RegisterMessageCallback(
81      "speechResult",
82      base::Bind(&StartPageHandler::HandleSpeechResult,
83                 base::Unretained(this)));
84  web_ui()->RegisterMessageCallback(
85      "speechSoundLevel",
86      base::Bind(&StartPageHandler::HandleSpeechSoundLevel,
87                 base::Unretained(this)));
88  web_ui()->RegisterMessageCallback(
89      "setSpeechRecognitionState",
90      base::Bind(&StartPageHandler::HandleSpeechRecognition,
91                 base::Unretained(this)));
92}
93
94void StartPageHandler::OnExtensionLoaded(
95    content::BrowserContext* browser_context,
96    const extensions::Extension* extension) {
97#if defined(OS_CHROMEOS)
98  DCHECK_EQ(Profile::FromWebUI(web_ui()),
99            Profile::FromBrowserContext(browser_context));
100  if (extension->id() == extension_misc::kHotwordExtensionId)
101    OnHotwordEnabledChanged();
102#endif
103}
104
105void StartPageHandler::OnExtensionUnloaded(
106    content::BrowserContext* browser_context,
107    const extensions::Extension* extension,
108    extensions::UnloadedExtensionInfo::Reason reason) {
109#if defined(OS_CHROMEOS)
110  DCHECK_EQ(Profile::FromWebUI(web_ui()),
111            Profile::FromBrowserContext(browser_context));
112  if (extension->id() == extension_misc::kHotwordExtensionId)
113    OnHotwordEnabledChanged();
114#endif
115}
116
117void StartPageHandler::OnRecommendedAppsChanged() {
118  SendRecommendedApps();
119}
120
121void StartPageHandler::SendRecommendedApps() {
122  const RecommendedApps::Apps& recommends = recommended_apps_->apps();
123
124  base::ListValue recommended_list;
125  for (size_t i = 0; i < recommends.size(); ++i) {
126    recommended_list.Append(CreateAppInfo(recommends[i].get()).release());
127  }
128
129  web_ui()->CallJavascriptFunction("appList.startPage.setRecommendedApps",
130                                   recommended_list);
131}
132
133#if defined(OS_CHROMEOS)
134void StartPageHandler::OnHotwordEnabledChanged() {
135  // If the hotword extension is new enough, we should use the new
136  // hotwordPrivate API to provide the feature.
137  // TODO(mukai): remove this after everything gets stable.
138  Profile* profile = Profile::FromWebUI(web_ui());
139
140  extensions::ExtensionRegistry* registry =
141      extensions::ExtensionRegistry::Get(profile);
142  const extensions::Extension* hotword_extension =
143      registry->GetExtensionById(extension_misc::kHotwordExtensionId,
144                                 extensions::ExtensionRegistry::ENABLED);
145  if (hotword_extension &&
146      hotword_extension->version()->CompareTo(
147          base::Version(kOldHotwordExtensionVersionString)) <= 0) {
148    StartPageService* service = StartPageService::Get(profile);
149    web_ui()->CallJavascriptFunction(
150        "appList.startPage.setHotwordEnabled",
151        base::FundamentalValue(service->HotwordEnabled()));
152  }
153}
154#endif
155
156void StartPageHandler::HandleInitialize(const base::ListValue* args) {
157  Profile* profile = Profile::FromWebUI(web_ui());
158  StartPageService* service = StartPageService::Get(profile);
159  if (!service)
160    return;
161
162  recommended_apps_ = service->recommended_apps();
163  recommended_apps_->AddObserver(this);
164
165  SendRecommendedApps();
166
167#if defined(OS_CHROMEOS)
168  if (app_list::switches::IsVoiceSearchEnabled() &&
169      HotwordService::DoesHotwordSupportLanguage(profile)) {
170    OnHotwordEnabledChanged();
171    pref_change_registrar_.Init(profile->GetPrefs());
172    pref_change_registrar_.Add(
173        prefs::kHotwordSearchEnabled,
174        base::Bind(&StartPageHandler::OnHotwordEnabledChanged,
175                   base::Unretained(this)));
176
177    extension_registry_observer_.Add(
178        extensions::ExtensionRegistry::Get(profile));
179  }
180#endif
181
182  web_ui()->CallJavascriptFunction(
183      "appList.startPage.setNaclArch",
184      base::StringValue(chrome::OmahaQueryParams::GetNaclArch()));
185
186  if (!app_list::switches::IsExperimentalAppListEnabled()) {
187    web_ui()->CallJavascriptFunction(
188        "appList.startPage.onAppListShown",
189        base::FundamentalValue(service->HotwordEnabled()));
190  }
191}
192
193void StartPageHandler::HandleLaunchApp(const base::ListValue* args) {
194  std::string app_id;
195  CHECK(args->GetString(0, &app_id));
196
197  Profile* profile = Profile::FromWebUI(web_ui());
198  const extensions::Extension* app =
199      extensions::ExtensionRegistry::Get(profile)
200          ->GetExtensionById(app_id, extensions::ExtensionRegistry::EVERYTHING);
201  if (!app) {
202    NOTREACHED();
203    return;
204  }
205
206  AppListControllerDelegate* controller = AppListService::Get(
207      chrome::GetHostDesktopTypeForNativeView(
208          web_ui()->GetWebContents()->GetNativeView()))->
209              GetControllerDelegate();
210  controller->ActivateApp(profile,
211                          app,
212                          AppListControllerDelegate::LAUNCH_FROM_APP_LIST,
213                          ui::EF_NONE);
214}
215
216void StartPageHandler::HandleSpeechResult(const base::ListValue* args) {
217  base::string16 query;
218  bool is_final = false;
219  CHECK(args->GetString(0, &query));
220  CHECK(args->GetBoolean(1, &is_final));
221
222  StartPageService::Get(Profile::FromWebUI(web_ui()))->OnSpeechResult(
223      query, is_final);
224}
225
226void StartPageHandler::HandleSpeechSoundLevel(const base::ListValue* args) {
227  double level;
228  CHECK(args->GetDouble(0, &level));
229
230  StartPageService* service =
231      StartPageService::Get(Profile::FromWebUI(web_ui()));
232  if (service)
233    service->OnSpeechSoundLevelChanged(static_cast<int16>(level));
234}
235
236void StartPageHandler::HandleSpeechRecognition(const base::ListValue* args) {
237  std::string state_string;
238  CHECK(args->GetString(0, &state_string));
239
240  SpeechRecognitionState new_state = SPEECH_RECOGNITION_OFF;
241  if (state_string == "READY")
242    new_state = SPEECH_RECOGNITION_READY;
243  else if (state_string == "HOTWORD_RECOGNIZING")
244    new_state = SPEECH_RECOGNITION_HOTWORD_LISTENING;
245  else if (state_string == "RECOGNIZING")
246    new_state = SPEECH_RECOGNITION_RECOGNIZING;
247  else if (state_string == "IN_SPEECH")
248    new_state = SPEECH_RECOGNITION_IN_SPEECH;
249  else if (state_string == "STOPPING")
250    new_state = SPEECH_RECOGNITION_STOPPING;
251
252  StartPageService* service =
253      StartPageService::Get(Profile::FromWebUI(web_ui()));
254  if (service)
255    service->OnSpeechRecognitionStateChanged(new_state);
256}
257
258}  // namespace app_list
259