OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/app_list/start_page_service.h" | 5 #include "chrome/browser/ui/app_list/start_page_service.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/json/json_string_value_serializer.h" | |
11 #include "base/memory/singleton.h" | 12 #include "base/memory/singleton.h" |
12 #include "base/metrics/user_metrics.h" | 13 #include "base/metrics/user_metrics.h" |
13 #include "base/prefs/pref_service.h" | 14 #include "base/prefs/pref_service.h" |
14 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
15 #include "chrome/browser/chrome_notification_types.h" | 16 #include "chrome/browser/chrome_notification_types.h" |
17 #include "chrome/browser/google/google_profile_helper.h" | |
16 #include "chrome/browser/media/media_stream_infobar_delegate.h" | 18 #include "chrome/browser/media/media_stream_infobar_delegate.h" |
17 #include "chrome/browser/profiles/profile.h" | 19 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/browser/search/hotword_service.h" | 20 #include "chrome/browser/search/hotword_service.h" |
19 #include "chrome/browser/search/hotword_service_factory.h" | 21 #include "chrome/browser/search/hotword_service_factory.h" |
20 #include "chrome/browser/ui/app_list/speech_auth_helper.h" | 22 #include "chrome/browser/ui/app_list/speech_auth_helper.h" |
21 #include "chrome/browser/ui/app_list/speech_recognizer.h" | 23 #include "chrome/browser/ui/app_list/speech_recognizer.h" |
22 #include "chrome/browser/ui/app_list/start_page_observer.h" | 24 #include "chrome/browser/ui/app_list/start_page_observer.h" |
23 #include "chrome/browser/ui/app_list/start_page_service_factory.h" | 25 #include "chrome/browser/ui/app_list/start_page_service_factory.h" |
24 #include "chrome/common/chrome_switches.h" | 26 #include "chrome/common/chrome_switches.h" |
25 #include "chrome/common/pref_names.h" | 27 #include "chrome/common/pref_names.h" |
26 #include "chrome/common/url_constants.h" | 28 #include "chrome/common/url_constants.h" |
29 #include "components/google/core/browser/google_util.h" | |
27 #include "components/ui/zoom/zoom_controller.h" | 30 #include "components/ui/zoom/zoom_controller.h" |
28 #include "content/public/browser/browser_thread.h" | 31 #include "content/public/browser/browser_thread.h" |
29 #include "content/public/browser/notification_details.h" | 32 #include "content/public/browser/notification_details.h" |
30 #include "content/public/browser/notification_observer.h" | 33 #include "content/public/browser/notification_observer.h" |
31 #include "content/public/browser/notification_registrar.h" | 34 #include "content/public/browser/notification_registrar.h" |
32 #include "content/public/browser/notification_service.h" | 35 #include "content/public/browser/notification_service.h" |
33 #include "content/public/browser/notification_source.h" | 36 #include "content/public/browser/notification_source.h" |
34 #include "content/public/browser/speech_recognition_session_preamble.h" | 37 #include "content/public/browser/speech_recognition_session_preamble.h" |
35 #include "content/public/browser/web_contents.h" | 38 #include "content/public/browser/web_contents.h" |
36 #include "content/public/browser/web_contents_delegate.h" | 39 #include "content/public/browser/web_contents_delegate.h" |
37 #include "extensions/browser/extension_system_provider.h" | 40 #include "extensions/browser/extension_system_provider.h" |
38 #include "extensions/browser/extensions_browser_client.h" | 41 #include "extensions/browser/extensions_browser_client.h" |
39 #include "extensions/common/extension.h" | 42 #include "extensions/common/extension.h" |
43 #include "net/base/load_flags.h" | |
40 #include "net/base/network_change_notifier.h" | 44 #include "net/base/network_change_notifier.h" |
45 #include "net/url_request/url_fetcher.h" | |
41 #include "ui/app_list/app_list_switches.h" | 46 #include "ui/app_list/app_list_switches.h" |
42 | 47 |
43 #if defined(OS_CHROMEOS) | 48 #if defined(OS_CHROMEOS) |
44 #include "chromeos/audio/cras_audio_handler.h" | 49 #include "chromeos/audio/cras_audio_handler.h" |
45 #endif | 50 #endif |
46 | 51 |
47 using base::RecordAction; | 52 using base::RecordAction; |
48 using base::UserMetricsAction; | 53 using base::UserMetricsAction; |
49 | 54 |
50 namespace app_list { | 55 namespace app_list { |
51 | 56 |
52 namespace { | 57 namespace { |
53 | 58 |
59 // Path to google.com's doodle JSON. | |
60 const char kDoodleJsonPath[] = "async/ddljson"; | |
61 | |
62 // Delay between checking for a new doodle when no doodle is found. | |
63 const int kDefaultDoodleRecheckDelayMs = 30 * 60 * 1000; // 30 minutes. | |
Matt Giuca
2015/01/29 08:00:53
Not a fan of these hard-coded constants (even if t
calamity
2015/01/30 05:09:14
Done.
| |
64 | |
54 bool InSpeechRecognition(SpeechRecognitionState state) { | 65 bool InSpeechRecognition(SpeechRecognitionState state) { |
55 return state == SPEECH_RECOGNITION_RECOGNIZING || | 66 return state == SPEECH_RECOGNITION_RECOGNIZING || |
56 state == SPEECH_RECOGNITION_IN_SPEECH; | 67 state == SPEECH_RECOGNITION_IN_SPEECH; |
57 } | 68 } |
58 | 69 |
70 GURL GetGoogleBaseURL(Profile* profile) { | |
71 GURL base_url(google_util::CommandLineGoogleBaseURL()); | |
72 if (!base_url.is_valid()) | |
73 base_url = google_profile_helper::GetGoogleHomePageURL(profile); | |
74 | |
75 return base_url; | |
76 } | |
77 | |
59 } // namespace | 78 } // namespace |
60 | 79 |
61 class StartPageService::ProfileDestroyObserver | 80 class StartPageService::ProfileDestroyObserver |
62 : public content::NotificationObserver { | 81 : public content::NotificationObserver { |
63 public: | 82 public: |
64 explicit ProfileDestroyObserver(StartPageService* service) | 83 explicit ProfileDestroyObserver(StartPageService* service) |
65 : service_(service) { | 84 : service_(service) { |
66 registrar_.Add(this, | 85 registrar_.Add(this, |
67 chrome::NOTIFICATION_PROFILE_DESTROYED, | 86 chrome::NOTIFICATION_PROFILE_DESTROYED, |
68 content::Source<Profile>(service_->profile())); | 87 content::Source<Profile>(service_->profile())); |
(...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
465 void StartPageService::WebUILoaded() { | 484 void StartPageService::WebUILoaded() { |
466 // There's a race condition between the WebUI loading, and calling its JS | 485 // There's a race condition between the WebUI loading, and calling its JS |
467 // functions. Specifically, calling LoadContents() doesn't mean that the page | 486 // functions. Specifically, calling LoadContents() doesn't mean that the page |
468 // has loaded, but several code paths make this assumption. This function | 487 // has loaded, but several code paths make this assumption. This function |
469 // allows us to defer calling JS functions until after the page has finished | 488 // allows us to defer calling JS functions until after the page has finished |
470 // loading. | 489 // loading. |
471 webui_finished_loading_ = true; | 490 webui_finished_loading_ = true; |
472 for (const auto& cb : pending_webui_callbacks_) | 491 for (const auto& cb : pending_webui_callbacks_) |
473 cb.Run(); | 492 cb.Run(); |
474 pending_webui_callbacks_.clear(); | 493 pending_webui_callbacks_.clear(); |
494 | |
495 FetchDoodleJson(); | |
475 } | 496 } |
476 | 497 |
477 void StartPageService::LoadContents() { | 498 void StartPageService::LoadContents() { |
478 contents_.reset(content::WebContents::Create( | 499 contents_.reset(content::WebContents::Create( |
479 content::WebContents::CreateParams(profile_))); | 500 content::WebContents::CreateParams(profile_))); |
480 contents_delegate_.reset(new StartPageWebContentsDelegate()); | 501 contents_delegate_.reset(new StartPageWebContentsDelegate()); |
481 contents_->SetDelegate(contents_delegate_.get()); | 502 contents_->SetDelegate(contents_delegate_.get()); |
482 | 503 |
483 // The ZoomController needs to be created before the web contents is observed | 504 // The ZoomController needs to be created before the web contents is observed |
484 // by this object. Otherwise it will react to DidNavigateMainFrame after this | 505 // by this object. Otherwise it will react to DidNavigateMainFrame after this |
485 // object does, resetting the zoom mode in the process. | 506 // object does, resetting the zoom mode in the process. |
486 ui_zoom::ZoomController::CreateForWebContents(contents_.get()); | 507 ui_zoom::ZoomController::CreateForWebContents(contents_.get()); |
487 Observe(contents_.get()); | 508 Observe(contents_.get()); |
488 | 509 |
489 contents_->GetController().LoadURL( | 510 contents_->GetController().LoadURL( |
490 GURL(chrome::kChromeUIAppListStartPageURL), | 511 GURL(chrome::kChromeUIAppListStartPageURL), |
491 content::Referrer(), | 512 content::Referrer(), |
492 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | 513 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, |
493 std::string()); | 514 std::string()); |
494 } | 515 } |
495 | 516 |
496 void StartPageService::UnloadContents() { | 517 void StartPageService::UnloadContents() { |
497 contents_.reset(); | 518 contents_.reset(); |
498 webui_finished_loading_ = false; | 519 webui_finished_loading_ = false; |
499 } | 520 } |
500 | 521 |
522 void StartPageService::FetchDoodleJson() { | |
523 // SetPathStr() requires its argument to stay in scope as long as | |
524 // |replacements| is, so a std::string is needed, instead of a char*. | |
Matt Giuca
2015/01/29 08:00:53
But kDoodleJsonPath has global lifetime and thus s
calamity
2015/01/30 05:09:14
const char[] != std::string. The autoconverted str
Matt Giuca
2015/02/02 06:23:14
Acknowledged.
(Lol... it's funny that GURL::Repla
| |
525 std::string path = kDoodleJsonPath; | |
526 GURL::Replacements replacements; | |
527 replacements.SetPathStr(path); | |
528 | |
529 GURL doodle_url = GetGoogleBaseURL(profile_).ReplaceComponents(replacements); | |
530 doodle_fetcher_.reset( | |
531 net::URLFetcher::Create(0, doodle_url, net::URLFetcher::GET, this)); | |
532 doodle_fetcher_->SetRequestContext(profile_->GetRequestContext()); | |
533 doodle_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES); | |
534 doodle_fetcher_->Start(); | |
535 } | |
536 | |
537 void StartPageService::OnURLFetchComplete(const net::URLFetcher* source) { | |
538 std::string json_data; | |
539 source->GetResponseAsString(&json_data); | |
540 | |
541 // Remove XSSI guard for JSON parsing. | |
542 size_t json_start_index = json_data.find("{"); | |
543 if (json_start_index != std::string::npos) | |
544 json_data.erase(0, json_start_index); | |
Matt Giuca
2015/01/29 08:00:53
I think the preferred strategy these days is to us
calamity
2015/01/30 05:09:14
As discussed, this is more complicated that it's w
Matt Giuca
2015/02/02 06:23:14
Acknowledged.
| |
545 | |
546 JSONStringValueSerializer deserializer(json_data); | |
547 deserializer.set_allow_trailing_comma(true); | |
548 int error_code = 0; | |
549 scoped_ptr<base::Value> doodle_json( | |
550 deserializer.Deserialize(&error_code, NULL)); | |
Matt Giuca
2015/01/29 08:00:53
nullptrs (everywhere)
calamity
2015/01/30 05:09:14
Done.
| |
551 | |
552 int recheck_delay_ms = kDefaultDoodleRecheckDelayMs; | |
553 | |
554 if (error_code == 0) { | |
555 base::DictionaryValue* doodle_dictionary = NULL; | |
556 // Use the supplied TTL as the recheck delay if available. | |
557 if (doodle_json->GetAsDictionary(&doodle_dictionary)) { | |
558 doodle_dictionary->GetInteger("ddljson.time_to_live_ms", | |
559 &recheck_delay_ms); | |
560 } | |
561 | |
562 contents_->GetWebUI()->CallJavascriptFunction( | |
563 "appList.startPage.onAppListDoodleUpdated", *doodle_json, | |
564 base::StringValue(GetGoogleBaseURL(profile_).spec())); | |
565 } | |
566 | |
567 // Check for a new doodle. | |
568 content::BrowserThread::PostDelayedTask( | |
569 content::BrowserThread::UI, FROM_HERE, | |
570 base::Bind(&StartPageService::FetchDoodleJson, | |
571 weak_factory_.GetWeakPtr()), | |
572 base::TimeDelta::FromMilliseconds(recheck_delay_ms)); | |
573 } | |
574 | |
501 } // namespace app_list | 575 } // namespace app_list |
OLD | NEW |