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 kDefaultDoodleRecheckDelayMinutes = 30; |
| 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*. |
| 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); |
| 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, nullptr)); |
| 551 |
| 552 base::TimeDelta recheck_delay = |
| 553 base::TimeDelta::FromMinutes(kDefaultDoodleRecheckDelayMinutes); |
| 554 |
| 555 if (error_code == 0) { |
| 556 base::DictionaryValue* doodle_dictionary = nullptr; |
| 557 // Use the supplied TTL as the recheck delay if available. |
| 558 if (doodle_json->GetAsDictionary(&doodle_dictionary)) { |
| 559 int time_to_live = 0; |
| 560 if (doodle_dictionary->GetInteger("ddljson.time_to_live_ms", |
| 561 &time_to_live)) { |
| 562 recheck_delay = base::TimeDelta::FromMilliseconds(time_to_live); |
| 563 } |
| 564 } |
| 565 |
| 566 contents_->GetWebUI()->CallJavascriptFunction( |
| 567 "appList.startPage.onAppListDoodleUpdated", *doodle_json, |
| 568 base::StringValue(GetGoogleBaseURL(profile_).spec())); |
| 569 } |
| 570 |
| 571 // Check for a new doodle. |
| 572 content::BrowserThread::PostDelayedTask( |
| 573 content::BrowserThread::UI, FROM_HERE, |
| 574 base::Bind(&StartPageService::FetchDoodleJson, |
| 575 weak_factory_.GetWeakPtr()), |
| 576 recheck_delay); |
| 577 } |
| 578 |
501 } // namespace app_list | 579 } // namespace app_list |
OLD | NEW |