OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/webui/voicesearch_ui.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/command_line.h" | |
10 #include "base/metrics/field_trial.h" | |
11 #include "base/path_service.h" | |
12 #include "base/prefs/pref_service.h" | |
13 #include "base/strings/string_number_conversions.h" | |
14 #include "base/strings/utf_string_conversions.h" | |
15 #include "chrome/browser/browser_process.h" | |
16 #include "chrome/browser/extensions/extension_service.h" | |
17 #include "chrome/browser/plugins/plugin_prefs.h" | |
18 #include "chrome/browser/profiles/profile.h" | |
19 #include "chrome/browser/search/hotword_service.h" | |
20 #include "chrome/browser/search/hotword_service_factory.h" | |
21 #include "chrome/browser/ui/app_list/start_page_service.h" | |
22 #include "chrome/browser/ui/webui/version_handler.h" | |
23 #include "chrome/common/chrome_content_client.h" | |
24 #include "chrome/common/chrome_paths.h" | |
25 #include "chrome/common/chrome_version_info.h" | |
26 #include "chrome/common/extensions/extension_constants.h" | |
27 #include "chrome/common/pref_names.h" | |
28 #include "chrome/common/url_constants.h" | |
29 #include "chrome/grit/chromium_strings.h" | |
30 #include "chrome/grit/generated_resources.h" | |
31 #include "chrome/grit/google_chrome_strings.h" | |
32 #include "content/public/browser/plugin_service.h" | |
33 #include "content/public/browser/url_data_source.h" | |
34 #include "content/public/browser/web_ui.h" | |
35 #include "content/public/browser/web_ui_data_source.h" | |
36 #include "content/public/browser/web_ui_message_handler.h" | |
37 #include "content/public/common/user_agent.h" | |
38 #include "extensions/browser/extension_prefs.h" | |
39 #include "extensions/browser/extension_system.h" | |
40 #include "extensions/common/extension.h" | |
41 #include "grit/browser_resources.h" | |
42 #include "ui/base/l10n/l10n_util.h" | |
43 #include "v8/include/v8.h" | |
44 | |
45 #if defined(OS_WIN) | |
46 #include "base/win/windows_version.h" | |
47 #endif | |
48 | |
49 using base::ASCIIToUTF16; | |
50 using content::WebUIMessageHandler; | |
51 | |
52 namespace { | |
53 | |
54 content::WebUIDataSource* CreateVoiceSearchUiHtmlSource() { | |
55 content::WebUIDataSource* html_source = | |
56 content::WebUIDataSource::Create(chrome::kChromeUIVoiceSearchHost); | |
57 | |
58 html_source->AddLocalizedString("loadingMessage", | |
59 IDS_VOICESEARCH_LOADING_MESSAGE); | |
60 html_source->AddLocalizedString("voiceSearchLongTitle", | |
61 IDS_VOICESEARCH_TITLE_MESSAGE); | |
62 | |
63 html_source->SetJsonPath("strings.js"); | |
64 html_source->AddResourcePath("about_voicesearch.js", | |
65 IDR_ABOUT_VOICESEARCH_JS); | |
66 html_source->SetDefaultResource(IDR_ABOUT_VOICESEARCH_HTML); | |
67 return html_source; | |
68 } | |
69 | |
70 // Helper functions for collecting a list of key-value pairs that will | |
71 // be displayed. | |
72 void AddPair16(base::ListValue* list, | |
73 const base::string16& key, | |
74 const base::string16& value) { | |
75 scoped_ptr<base::DictionaryValue> results(new base::DictionaryValue()); | |
76 results->SetString("key", key); | |
77 results->SetString("value", value); | |
78 list->Append(results.release()); | |
79 } | |
80 | |
81 void AddPair(base::ListValue* list, | |
82 const base::StringPiece& key, | |
83 const base::StringPiece& value) { | |
84 AddPair16(list, UTF8ToUTF16(key), UTF8ToUTF16(value)); | |
85 } | |
86 | |
87 // Generate an empty data-pair which acts as a line break. | |
88 void AddLineBreak(base::ListValue* list) { | |
89 AddPair(list, "", ""); | |
90 } | |
91 | |
92 //////////////////////////////////////////////////////////////////////////////// | |
93 // | |
94 // VoiceSearchDomHandler | |
95 // | |
96 //////////////////////////////////////////////////////////////////////////////// | |
97 | |
98 // The handler for Javascript messages for the about:flags page. | |
99 class VoiceSearchDomHandler : public WebUIMessageHandler { | |
100 public: | |
101 explicit VoiceSearchDomHandler(Profile* profile) : profile_(profile) {} | |
102 | |
103 ~VoiceSearchDomHandler() override {} | |
104 | |
105 // WebUIMessageHandler implementation. | |
106 void RegisterMessages() override { | |
107 web_ui()->RegisterMessageCallback( | |
108 "requestVoiceSearchInfo", | |
109 base::Bind(&VoiceSearchDomHandler::HandleRequestVoiceSearchInfo, | |
110 base::Unretained(this))); | |
111 } | |
112 | |
113 private: | |
114 // Callback for the "requestVoiceSearchInfo" message. No arguments. | |
115 void HandleRequestVoiceSearchInfo(const base::ListValue* args) { | |
116 base::DictionaryValue voiceSearchInfo; | |
117 PopulatePageInformation(&voiceSearchInfo); | |
118 web_ui()->CallJavascriptFunction("returnVoiceSearchInfo", | |
119 voiceSearchInfo); | |
120 } | |
121 | |
122 // Fill in the data to be displayed on the page. | |
123 void PopulatePageInformation(base::DictionaryValue* voiceSearchInfo) { | |
124 // Store Key-Value pairs of about-information. | |
125 scoped_ptr<base::ListValue> list(new base::ListValue()); | |
126 | |
127 // Populate information. | |
128 AddOperatingSystemInfo(list.get()); | |
129 AddAudioInfo(list.get()); | |
130 AddLanguageInfo(list.get()); | |
131 AddHotwordInfo(list.get()); | |
132 | |
133 std::string extension_id = extension_misc::kHotwordExtensionId; | |
134 HotwordService* hotword_service = | |
135 HotwordServiceFactory::GetForProfile(profile_); | |
136 if (hotword_service && hotword_service->IsExperimentalHotwordingEnabled()) | |
137 extension_id = extension_misc::kHotwordNewExtensionId; | |
138 AddExtensionInfo(extension_id, "Extension", list.get()); | |
139 | |
140 AddExtensionInfo(extension_misc::kHotwordSharedModuleId, | |
141 "Shared Module", | |
142 list.get()); | |
143 AddAppListInfo(list.get()); | |
144 | |
145 // voiceSearchInfo will take ownership of list, and clean it up on | |
146 // destruction. | |
147 voiceSearchInfo->Set("voiceSearchInfo", list.release()); | |
148 } | |
149 | |
150 // Adds information regarding the system and chrome version info to list. | |
151 void AddOperatingSystemInfo(base::ListValue* list) { | |
152 // Obtain the Chrome version info. | |
153 chrome::VersionInfo version_info; | |
154 AddPair(list, | |
155 l10n_util::GetStringUTF8(IDS_PRODUCT_NAME), | |
156 version_info.Version() + " (" + | |
157 chrome::VersionInfo::GetVersionStringModifier() + ")"); | |
158 | |
159 // OS version information. | |
160 std::string os_label = version_info.OSType(); | |
161 #if defined(OS_WIN) | |
162 base::win::OSInfo* os = base::win::OSInfo::GetInstance(); | |
163 switch (os->version()) { | |
164 case base::win::VERSION_XP: | |
165 os_label += " XP"; | |
166 break; | |
167 case base::win::VERSION_SERVER_2003: | |
168 os_label += " Server 2003 or XP Pro 64 bit"; | |
169 break; | |
170 case base::win::VERSION_VISTA: | |
171 os_label += " Vista or Server 2008"; | |
172 break; | |
173 case base::win::VERSION_WIN7: | |
174 os_label += " 7 or Server 2008 R2"; | |
175 break; | |
176 case base::win::VERSION_WIN8: | |
177 os_label += " 8 or Server 2012"; | |
178 break; | |
179 default: | |
180 os_label += " UNKNOWN"; | |
181 break; | |
182 } | |
183 os_label += " SP" + base::IntToString(os->service_pack().major); | |
184 | |
185 if (os->service_pack().minor > 0) | |
186 os_label += "." + base::IntToString(os->service_pack().minor); | |
187 | |
188 if (os->architecture() == base::win::OSInfo::X64_ARCHITECTURE) | |
189 os_label += " 64 bit"; | |
190 #endif | |
191 AddPair(list, l10n_util::GetStringUTF8(IDS_ABOUT_VERSION_OS), os_label); | |
192 | |
193 AddLineBreak(list); | |
194 } | |
195 | |
196 // Adds information regarding audio to the list. | |
197 void AddAudioInfo(base::ListValue* list) { | |
198 // NaCl and its associated functions are not available on most mobile | |
199 // platforms. ENABLE_EXTENSIONS covers those platforms and hey would not | |
200 // allow Hotwording anyways since it is an extension. | |
201 std::string nacl_enabled = "not available"; | |
202 #if defined(ENABLE_EXTENSIONS) | |
203 nacl_enabled = "No"; | |
204 // Determine if NaCl is available. | |
205 base::FilePath path; | |
206 if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path)) { | |
207 content::WebPluginInfo info; | |
208 PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile_).get(); | |
209 if (content::PluginService::GetInstance()->GetPluginInfoByPath(path, | |
210 &info) && | |
211 plugin_prefs->IsPluginEnabled(info)) { | |
212 nacl_enabled = "Yes"; | |
213 } | |
214 } | |
215 #endif | |
216 | |
217 AddPair(list, "NaCl Enabled", nacl_enabled); | |
218 | |
219 AddPair(list, | |
220 "Microphone", | |
221 HotwordServiceFactory::IsMicrophoneAvailable() ? "Yes" : "No"); | |
222 | |
223 std::string audio_capture = "No"; | |
224 if (profile_->GetPrefs()->GetBoolean(prefs::kAudioCaptureAllowed)) | |
225 audio_capture = "Yes"; | |
226 AddPair(list, "Audio Capture Allowed", audio_capture); | |
227 | |
228 AddLineBreak(list); | |
229 } | |
230 | |
231 // Adds information regarding languages to the list. | |
232 void AddLanguageInfo(base::ListValue* list) { | |
233 std::string locale = | |
234 #if defined(OS_CHROMEOS) | |
235 // On ChromeOS locale is per-profile. | |
236 profile_->GetPrefs()->GetString(prefs::kApplicationLocale); | |
237 #else | |
238 g_browser_process->GetApplicationLocale(); | |
239 #endif | |
240 AddPair(list, "Current Language", locale); | |
241 | |
242 AddPair(list, | |
243 "Hotword Previous Language", | |
244 profile_->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage)); | |
245 | |
246 AddLineBreak(list); | |
247 } | |
248 | |
249 // Adds information specific to the hotword configuration to the list. | |
250 void AddHotwordInfo(base::ListValue* list) { | |
251 std::string search_enabled = "No"; | |
252 if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) | |
253 search_enabled = "Yes"; | |
254 AddPair(list, "Hotword Search Enabled", search_enabled); | |
255 | |
256 std::string always_on_search_enabled = "No"; | |
257 if (profile_->GetPrefs()->GetBoolean(prefs::kHotwordAlwaysOnSearchEnabled)) | |
258 always_on_search_enabled = "Yes"; | |
259 AddPair(list, "Always-on Hotword Search Enabled", always_on_search_enabled); | |
260 | |
261 std::string audio_logging_enabled = "No"; | |
262 HotwordService* hotword_service = | |
263 HotwordServiceFactory::GetForProfile(profile_); | |
264 if (hotword_service && hotword_service->IsOptedIntoAudioLogging()) | |
265 audio_logging_enabled = "Yes"; | |
266 AddPair(list, "Hotword Audio Logging Enabled", audio_logging_enabled); | |
267 | |
268 std::string group = base::FieldTrialList::FindFullName( | |
269 hotword_internal::kHotwordFieldTrialName); | |
270 AddPair(list, "Field trial", group); | |
271 | |
272 std::string new_hotwording_enabled = "No"; | |
273 if (hotword_service && hotword_service->IsExperimentalHotwordingEnabled()) | |
274 new_hotwording_enabled = "Yes"; | |
275 AddPair(list, "New Hotwording Enabled", new_hotwording_enabled); | |
276 | |
277 AddLineBreak(list); | |
278 } | |
279 | |
280 // Adds information specific to an extension to the list. | |
281 void AddExtensionInfo(const std::string& extension_id, | |
282 const std::string& name_prefix, | |
283 base::ListValue* list) { | |
284 DCHECK(!name_prefix.empty()); | |
285 std::string version("undefined"); | |
286 std::string id("undefined"); | |
287 base::FilePath path; | |
288 | |
289 extensions::ExtensionSystem* extension_system = | |
290 extensions::ExtensionSystem::Get(profile_); | |
291 if (extension_system) { | |
292 ExtensionService* extension_service = | |
293 extension_system->extension_service(); | |
294 const extensions::Extension* extension = | |
295 extension_service->GetExtensionById(extension_id, true); | |
296 if (extension) { | |
297 id = extension->id(); | |
298 version = extension->VersionString(); | |
299 path = extension->path(); | |
300 } | |
301 } | |
302 AddPair(list, name_prefix + " Id", id); | |
303 AddPair(list, name_prefix + " Version", version); | |
304 AddPair16(list, | |
305 ASCIIToUTF16(name_prefix + " Path"), | |
306 path.empty() ? | |
307 ASCIIToUTF16("undefined") : path.LossyDisplayName()); | |
308 | |
309 extensions::ExtensionPrefs* extension_prefs = | |
310 extensions::ExtensionPrefs::Get(profile_); | |
311 int pref_state = -1; | |
312 extension_prefs->ReadPrefAsInteger(extension_id, "state", &pref_state); | |
313 std::string state; | |
314 switch (pref_state) { | |
315 case extensions::Extension::DISABLED: | |
316 state = "DISABLED"; | |
317 break; | |
318 case extensions::Extension::ENABLED: | |
319 state = "ENABLED"; | |
320 break; | |
321 case extensions::Extension::EXTERNAL_EXTENSION_UNINSTALLED: | |
322 state = "EXTERNAL_EXTENSION_UNINSTALLED"; | |
323 break; | |
324 default: | |
325 state = "undefined"; | |
326 } | |
327 | |
328 AddPair(list, name_prefix + " State", state); | |
329 | |
330 AddLineBreak(list); | |
331 } | |
332 | |
333 // Adds information specific to voice search in the app launcher to the list. | |
334 void AddAppListInfo(base::ListValue* list) { | |
335 #if defined (ENABLE_APP_LIST) | |
336 std::string state = "No Start Page Service"; | |
337 app_list::StartPageService* start_page_service = | |
338 app_list::StartPageService::Get(profile_); | |
339 if (start_page_service) { | |
340 app_list::SpeechRecognitionState speech_state = | |
341 start_page_service->state(); | |
342 switch (speech_state) { | |
343 case app_list::SPEECH_RECOGNITION_OFF: | |
344 state = "SPEECH_RECOGNITION_OFF"; | |
345 break; | |
346 case app_list::SPEECH_RECOGNITION_READY: | |
347 state = "SPEECH_RECOGNITION_READY"; | |
348 break; | |
349 case app_list::SPEECH_RECOGNITION_HOTWORD_LISTENING: | |
350 state = "SPEECH_RECOGNITION_HOTWORD_LISTENING"; | |
351 break; | |
352 case app_list::SPEECH_RECOGNITION_RECOGNIZING: | |
353 state = "SPEECH_RECOGNITION_RECOGNIZING"; | |
354 break; | |
355 case app_list::SPEECH_RECOGNITION_IN_SPEECH: | |
356 state = "SPEECH_RECOGNITION_IN_SPEECH"; | |
357 break; | |
358 case app_list::SPEECH_RECOGNITION_STOPPING: | |
359 state = "SPEECH_RECOGNITION_STOPPING"; | |
360 break; | |
361 case app_list::SPEECH_RECOGNITION_NETWORK_ERROR: | |
362 state = "SPEECH_RECOGNITION_NETWORK_ERROR"; | |
363 break; | |
364 default: | |
365 state = "undefined"; | |
366 } | |
367 } | |
368 AddPair(list, "Start Page State", state); | |
369 #endif | |
370 } | |
371 | |
372 Profile* profile_; | |
373 | |
374 DISALLOW_COPY_AND_ASSIGN(VoiceSearchDomHandler); | |
375 }; | |
376 | |
377 } // namespace | |
378 | |
379 /////////////////////////////////////////////////////////////////////////////// | |
380 // | |
381 // VoiceSearchUI | |
382 // | |
383 /////////////////////////////////////////////////////////////////////////////// | |
384 | |
385 VoiceSearchUI::VoiceSearchUI(content::WebUI* web_ui) | |
386 : content::WebUIController(web_ui) { | |
387 Profile* profile = Profile::FromWebUI(web_ui); | |
388 web_ui->AddMessageHandler(new VoiceSearchDomHandler(profile)); | |
389 | |
390 // Set up the about:voicesearch source. | |
391 content::WebUIDataSource::Add(profile, CreateVoiceSearchUiHtmlSource()); | |
392 } | |
393 | |
394 VoiceSearchUI::~VoiceSearchUI() {} | |
OLD | NEW |