| Index: chrome/browser/ui/app_list/start_page_service.cc
 | 
| diff --git a/chrome/browser/ui/app_list/start_page_service.cc b/chrome/browser/ui/app_list/start_page_service.cc
 | 
| index e08d8ef3dc09362871d901161c94110e1ca2b8b0..de3a1c33baabc09a621dff434926b8357f7743d4 100644
 | 
| --- a/chrome/browser/ui/app_list/start_page_service.cc
 | 
| +++ b/chrome/browser/ui/app_list/start_page_service.cc
 | 
| @@ -8,11 +8,13 @@
 | 
|  
 | 
|  #include "base/bind.h"
 | 
|  #include "base/command_line.h"
 | 
| +#include "base/json/json_string_value_serializer.h"
 | 
|  #include "base/memory/singleton.h"
 | 
|  #include "base/metrics/user_metrics.h"
 | 
|  #include "base/prefs/pref_service.h"
 | 
|  #include "chrome/browser/browser_process.h"
 | 
|  #include "chrome/browser/chrome_notification_types.h"
 | 
| +#include "chrome/browser/google/google_profile_helper.h"
 | 
|  #include "chrome/browser/media/media_stream_infobar_delegate.h"
 | 
|  #include "chrome/browser/profiles/profile.h"
 | 
|  #include "chrome/browser/search/hotword_service.h"
 | 
| @@ -24,6 +26,7 @@
 | 
|  #include "chrome/common/chrome_switches.h"
 | 
|  #include "chrome/common/pref_names.h"
 | 
|  #include "chrome/common/url_constants.h"
 | 
| +#include "components/google/core/browser/google_util.h"
 | 
|  #include "components/ui/zoom/zoom_controller.h"
 | 
|  #include "content/public/browser/browser_thread.h"
 | 
|  #include "content/public/browser/notification_details.h"
 | 
| @@ -37,7 +40,9 @@
 | 
|  #include "extensions/browser/extension_system_provider.h"
 | 
|  #include "extensions/browser/extensions_browser_client.h"
 | 
|  #include "extensions/common/extension.h"
 | 
| +#include "net/base/load_flags.h"
 | 
|  #include "net/base/network_change_notifier.h"
 | 
| +#include "net/url_request/url_fetcher.h"
 | 
|  #include "ui/app_list/app_list_switches.h"
 | 
|  
 | 
|  #if defined(OS_CHROMEOS)
 | 
| @@ -51,11 +56,25 @@ namespace app_list {
 | 
|  
 | 
|  namespace {
 | 
|  
 | 
| +// Path to google.com's doodle JSON.
 | 
| +const char kDoodleJsonPath[] = "async/ddljson";
 | 
| +
 | 
| +// Delay between checking for a new doodle when no doodle is found.
 | 
| +const int kDefaultDoodleRecheckDelayMinutes = 30;
 | 
| +
 | 
|  bool InSpeechRecognition(SpeechRecognitionState state) {
 | 
|    return state == SPEECH_RECOGNITION_RECOGNIZING ||
 | 
|        state == SPEECH_RECOGNITION_IN_SPEECH;
 | 
|  }
 | 
|  
 | 
| +GURL GetGoogleBaseURL(Profile* profile) {
 | 
| +  GURL base_url(google_util::CommandLineGoogleBaseURL());
 | 
| +  if (!base_url.is_valid())
 | 
| +    base_url = google_profile_helper::GetGoogleHomePageURL(profile);
 | 
| +
 | 
| +  return base_url;
 | 
| +}
 | 
| +
 | 
|  }  // namespace
 | 
|  
 | 
|  class StartPageService::ProfileDestroyObserver
 | 
| @@ -472,6 +491,8 @@ void StartPageService::WebUILoaded() {
 | 
|    for (const auto& cb : pending_webui_callbacks_)
 | 
|      cb.Run();
 | 
|    pending_webui_callbacks_.clear();
 | 
| +
 | 
| +  FetchDoodleJson();
 | 
|  }
 | 
|  
 | 
|  void StartPageService::LoadContents() {
 | 
| @@ -498,4 +519,61 @@ void StartPageService::UnloadContents() {
 | 
|    webui_finished_loading_ = false;
 | 
|  }
 | 
|  
 | 
| +void StartPageService::FetchDoodleJson() {
 | 
| +  // SetPathStr() requires its argument to stay in scope as long as
 | 
| +  // |replacements| is, so a std::string is needed, instead of a char*.
 | 
| +  std::string path = kDoodleJsonPath;
 | 
| +  GURL::Replacements replacements;
 | 
| +  replacements.SetPathStr(path);
 | 
| +
 | 
| +  GURL doodle_url = GetGoogleBaseURL(profile_).ReplaceComponents(replacements);
 | 
| +  doodle_fetcher_.reset(
 | 
| +      net::URLFetcher::Create(0, doodle_url, net::URLFetcher::GET, this));
 | 
| +  doodle_fetcher_->SetRequestContext(profile_->GetRequestContext());
 | 
| +  doodle_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES);
 | 
| +  doodle_fetcher_->Start();
 | 
| +}
 | 
| +
 | 
| +void StartPageService::OnURLFetchComplete(const net::URLFetcher* source) {
 | 
| +  std::string json_data;
 | 
| +  source->GetResponseAsString(&json_data);
 | 
| +
 | 
| +  // Remove XSSI guard for JSON parsing.
 | 
| +  size_t json_start_index = json_data.find("{");
 | 
| +  if (json_start_index != std::string::npos)
 | 
| +    json_data.erase(0, json_start_index);
 | 
| +
 | 
| +  JSONStringValueSerializer deserializer(json_data);
 | 
| +  deserializer.set_allow_trailing_comma(true);
 | 
| +  int error_code = 0;
 | 
| +  scoped_ptr<base::Value> doodle_json(
 | 
| +      deserializer.Deserialize(&error_code, nullptr));
 | 
| +
 | 
| +  base::TimeDelta recheck_delay =
 | 
| +      base::TimeDelta::FromMinutes(kDefaultDoodleRecheckDelayMinutes);
 | 
| +
 | 
| +  if (error_code == 0) {
 | 
| +    base::DictionaryValue* doodle_dictionary = nullptr;
 | 
| +    // Use the supplied TTL as the recheck delay if available.
 | 
| +    if (doodle_json->GetAsDictionary(&doodle_dictionary)) {
 | 
| +      int time_to_live = 0;
 | 
| +      if (doodle_dictionary->GetInteger("ddljson.time_to_live_ms",
 | 
| +                                        &time_to_live)) {
 | 
| +        recheck_delay = base::TimeDelta::FromMilliseconds(time_to_live);
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    contents_->GetWebUI()->CallJavascriptFunction(
 | 
| +        "appList.startPage.onAppListDoodleUpdated", *doodle_json,
 | 
| +        base::StringValue(GetGoogleBaseURL(profile_).spec()));
 | 
| +  }
 | 
| +
 | 
| +  // Check for a new doodle.
 | 
| +  content::BrowserThread::PostDelayedTask(
 | 
| +      content::BrowserThread::UI, FROM_HERE,
 | 
| +      base::Bind(&StartPageService::FetchDoodleJson,
 | 
| +                 weak_factory_.GetWeakPtr()),
 | 
| +      recheck_delay);
 | 
| +}
 | 
| +
 | 
|  }  // namespace app_list
 | 
| 
 |