Chromium Code Reviews| 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 |