web_resource_service.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/web_resource/web_resource_service.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <string>
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/file_path.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_util.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/threading/thread_restrictions.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/time.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/utf_string_conversions.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
18731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "chrome/browser/browser_thread.h"
1921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/extensions/extension_service.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/platform_util.h"
2121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
22201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/browser/sync/sync_ui_util.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
24201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch#include "chrome/common/extensions/extension.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/net/url_fetcher.h"
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_service.h"
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/notification_type.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "googleurl/src/gurl.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/load_flags.h"
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/url_request/url_request_status.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochnamespace {
34201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
35201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Delay on first fetch so we don't interfere with startup.
36201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstatic const int kStartResourceFetchDelay = 5000;
37201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
38201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Delay between calls to update the cache (48 hours).
39201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochstatic const int kCacheUpdateDelay = 48 * 60 * 60 * 1000;
40201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order
4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// to be able to roll out promos slowly, or display different promos to
4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// different groups.
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic const int kNTPPromoGroupSize = 16;
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Maximum number of hours for each time slice (4 weeks).
4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic const int kMaxTimeSliceHours = 24 * 7 * 4;
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Used to determine which build type should be shown a given promo.
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenenum BuildType {
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DEV_BUILD = 1,
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BETA_BUILD = 1 << 1,
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  STABLE_BUILD = 1 << 2,
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
56201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}  // namespace
57201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char* WebResourceService::kCurrentTipPrefName = "current_tip";
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst char* WebResourceService::kTipCachePrefName = "tips";
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::WebResourceFetcher
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public URLFetcher::Delegate {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit WebResourceFetcher(WebResourceService* web_resource_service) :
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(fetcher_factory_(this)),
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_service_(web_resource_service) {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Delay initial load of resource data into cache so as not to interfere
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // with startup time.
7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  void StartAfterDelay(int64 delay_ms) {
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         delay_ms);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Initializes the fetching of data from the resource server.  Data
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // load calls OnURLFetchComplete.
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartFetch() {
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Balanced in OnURLFetchComplete.
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_resource_service_->AddRef();
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // First, put our next cache load on the MessageLoop.
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    MessageLoop::current()->PostDelayedTask(FROM_HERE,
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch),
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            web_resource_service_->cache_update_delay());
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we are still fetching data, exit.
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (web_resource_service_->in_fetch_)
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      web_resource_service_->in_fetch_ = true;
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    std::string locale = g_browser_process->GetApplicationLocale();
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    std::string web_resource_server = kDefaultWebResourceServer;
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    web_resource_server.append(locale);
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_.reset(new URLFetcher(GURL(
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        web_resource_server),
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        URLFetcher::GET, this));
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Do not let url fetcher affect existing state in profile (by setting
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // cookies, for example.
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE |
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      net::LOAD_DO_NOT_SAVE_COOKIES);
10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    URLRequestContextGetter* url_request_context_getter =
10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        web_resource_service_->profile()->GetRequestContext();
10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    url_fetcher_->set_request_context(url_request_context_getter);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    url_fetcher_->Start();
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // From URLFetcher::Delegate.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void OnURLFetchComplete(const URLFetcher* source,
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const GURL& url,
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                          const net::URLRequestStatus& status,
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          int response_code,
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const ResponseCookies& cookies,
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          const std::string& data) {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Delete the URLFetcher when this function exits.
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    scoped_ptr<URLFetcher> clean_up_fetcher(url_fetcher_.release());
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Don't parse data if attempt to download was unsuccessful.
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Stop loading new web resource data, and silently exit.
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!status.is_success() || (response_code != 200))
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->UpdateResourceCache(data);
1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    web_resource_service_->Release();
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // So that we can delay our start so as not to affect start-up time; also,
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // so that we can schedule future cache updates.
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedRunnableMethodFactory<WebResourceFetcher> fetcher_factory_;
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tool that fetches the url data from the server.
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<URLFetcher> url_fetcher_;
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Our owner and creator. Ref counted.
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  WebResourceService* web_resource_service_;
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class coordinates a web resource unpack and parse task which is run in
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a separate process.  Results are sent back to this class and routed to
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// the WebResourceService.
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass WebResourceService::UnpackerClient
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : public UtilityProcessHost::Client {
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnpackerClient(WebResourceService* web_resource_service,
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 const std::string& json_data)
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : web_resource_service_(web_resource_service),
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      json_data_(json_data), got_response_(false) {
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Start() {
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    AddRef();  // balanced in Cleanup.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we don't have a resource_dispatcher_host_, assume we're in
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // a test and run the unpacker directly in-process.
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool use_utility_process =
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_service_->resource_dispatcher_host_ != NULL &&
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        !CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess);
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (use_utility_process) {
161731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::ID thread_id;
162731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      CHECK(BrowserThread::GetCurrentThreadIdentifier(&thread_id));
163731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::PostTask(
164731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          BrowserThread::IO, FROM_HERE,
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            web_resource_service_->resource_dispatcher_host_,
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            thread_id));
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WebResourceUnpacker unpacker(json_data_);
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (unpacker.Run()) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceSucceeded(*unpacker.parsed_json());
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      } else {
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnUnpackWebResourceFailed(unpacker.error_message());
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~UnpackerClient() {}
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // UtilityProcessHost::Client
18221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  virtual void OnProcessCrashed(int exit_code) {
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    OnUnpackWebResourceFailed(
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        "Chrome crashed while trying to retrieve web resources.");
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceSucceeded(
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const DictionaryValue& parsed_json) {
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->OnWebResourceUnpacked(parsed_json);
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  virtual void OnUnpackWebResourceFailed(const std::string& error_message) {
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    web_resource_service_->EndFetch();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cleanup();
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Release reference and set got_response_.
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Cleanup() {
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (got_response_)
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    got_response_ = true;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Release();
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void StartProcessOnIOThread(ResourceDispatcherHost* rdh,
211731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                              BrowserThread::ID thread_id) {
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UtilityProcessHost* host = new UtilityProcessHost(rdh, this, thread_id);
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(mrc): get proper file path when we start using web resources
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // that need to be unpacked.
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    host->StartWebResourceUnpacker(json_data_);
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_refptr<WebResourceService> web_resource_service_;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Holds raw JSON string.
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string& json_data_;
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // True if we got a response from the utility process and have cleaned up
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // already.
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool got_response_;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// Server for dynamically loaded NTP HTML elements. TODO(mirandac): append
229201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// locale for future usage, when we're serving localizable strings.
230201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochconst char* WebResourceService::kDefaultWebResourceServer =
23172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    "https://www.google.com/support/chrome/bin/topic/1142433/inproduct?hl=";
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::WebResourceService(Profile* profile)
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : prefs_(profile->GetPrefs()),
235201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      profile_(profile),
236201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(service_factory_(this)),
237201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      in_fetch_(false),
238201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      web_resource_update_scheduled_(false) {
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Init();
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochWebResourceService::~WebResourceService() { }
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::Init() {
245201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  cache_update_delay_ = kCacheUpdateDelay;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host();
2473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  web_resource_fetcher_.reset(new WebResourceFetcher(this));
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->RegisterStringPref(prefs::kNTPWebResourceCacheUpdate, "0");
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterDoublePref(prefs::kNTPCustomLogoStart, 0);
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterDoublePref(prefs::kNTPCustomLogoEnd, 0);
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterDoublePref(prefs::kNTPPromoStart, 0);
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterDoublePref(prefs::kNTPPromoEnd, 0);
253201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  prefs_->RegisterStringPref(prefs::kNTPPromoLine, std::string());
254201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  prefs_->RegisterBooleanPref(prefs::kNTPPromoClosed, false);
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterIntegerPref(prefs::kNTPPromoGroup, -1);
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterIntegerPref(prefs::kNTPPromoBuild,
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                              DEV_BUILD | BETA_BUILD | STABLE_BUILD);
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prefs_->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, 0);
259201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
260201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // If the promo start is in the future, set a notification task to invalidate
261201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // the NTP cache at the time of the promo start.
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  double promo_start = prefs_->GetDouble(prefs::kNTPPromoStart);
26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  double promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd);
264201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ScheduleNotification(promo_start, promo_end);
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::EndFetch() {
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  in_fetch_ = false;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid WebResourceService::OnWebResourceUnpacked(
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const DictionaryValue& parsed_json) {
2733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UnpackLogoSignal(parsed_json);
27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  UnpackPromoSignal(parsed_json);
2753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  EndFetch();
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
278201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid WebResourceService::WebResourceStateChange() {
279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  web_resource_update_scheduled_ = false;
280201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  NotificationService* service = NotificationService::current();
281201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  service->Notify(NotificationType::WEB_RESOURCE_STATE_CHANGED,
282201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  Source<WebResourceService>(this),
283201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                  NotificationService::NoDetails());
284201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
285201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
286201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid WebResourceService::ScheduleNotification(double promo_start,
287201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                              double promo_end) {
288201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (promo_start > 0 && promo_end > 0 && !web_resource_update_scheduled_) {
28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int64 ms_until_start =
29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        static_cast<int64>((base::Time::FromDoubleT(
291201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            promo_start) - base::Time::Now()).InMilliseconds());
29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int64 ms_until_end =
29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        static_cast<int64>((base::Time::FromDoubleT(
294201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            promo_end) - base::Time::Now()).InMilliseconds());
295201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (ms_until_start > 0) {
296201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      web_resource_update_scheduled_ = true;
297201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      MessageLoop::current()->PostDelayedTask(FROM_HERE,
298201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          service_factory_.NewRunnableMethod(
299201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              &WebResourceService::WebResourceStateChange),
300201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              ms_until_start);
301201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
302201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (ms_until_end > 0) {
303201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      web_resource_update_scheduled_ = true;
304201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      MessageLoop::current()->PostDelayedTask(FROM_HERE,
305201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          service_factory_.NewRunnableMethod(
306201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              &WebResourceService::WebResourceStateChange),
307201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch              ms_until_end);
308201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      if (ms_until_start <= 0) {
309201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        // Notify immediately if time is between start and end.
310201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        WebResourceStateChange();
311201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      }
312201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
313201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
314201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
315201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::StartAfterDelay() {
31772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int64 delay = kStartResourceFetchDelay;
3183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check whether we have ever put a value in the web resource cache;
3193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // if so, pull it out and see if it's time to update again.
3203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (prefs_->HasPrefPath(prefs::kNTPWebResourceCacheUpdate)) {
3213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    std::string last_update_pref =
3223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        prefs_->GetString(prefs::kNTPWebResourceCacheUpdate);
3233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!last_update_pref.empty()) {
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      double last_update_value;
3253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::StringToDouble(last_update_pref, &last_update_value);
32672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      int64 ms_until_update = cache_update_delay_ -
32772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          static_cast<int64>((base::Time::Now() - base::Time::FromDoubleT(
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          last_update_value)).InMilliseconds());
329201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      delay = ms_until_update > cache_update_delay_ ?
330201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          cache_update_delay_ : (ms_until_update < kStartResourceFetchDelay ?
331201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                                kStartResourceFetchDelay : ms_until_update);
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Start fetch and wait for UpdateResourceCache.
33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  web_resource_fetcher_->StartAfterDelay(delay);
3363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UpdateResourceCache(const std::string& json_data) {
3393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UnpackerClient* client = new UnpackerClient(this, json_data);
3403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  client->Start();
3413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
342201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Set cache update time in preferences.
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  prefs_->SetString(prefs::kNTPWebResourceCacheUpdate,
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      base::DoubleToString(base::Time::Now().ToDoubleT()));
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UnpackTips(const DictionaryValue& parsed_json) {
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get dictionary of cached preferences.
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_cache_ =
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      prefs_->GetMutableDictionary(prefs::kNTPWebResourceCache);
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The list of individual tips.
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* tip_holder = new ListValue();
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  web_resource_cache_->Set(WebResourceService::kTipCachePrefName, tip_holder);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DictionaryValue* topic_dict;
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* answer_list;
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string topic_id;
3593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string answer_id;
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::string inproduct;
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tip_counter = 0;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parsed_json.GetDictionary("topic", &topic_dict)) {
3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (topic_dict->GetString("topic_id", &topic_id))
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      web_resource_cache_->SetString("topic_id", topic_id);
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (topic_dict->GetList("answers", &answer_list)) {
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (ListValue::const_iterator tip_iter = answer_list->begin();
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           tip_iter != answer_list->end(); ++tip_iter) {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          continue;
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DictionaryValue* a_dic =
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            static_cast<DictionaryValue*>(*tip_iter);
3733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (a_dic->GetString("inproduct", &inproduct)) {
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          tip_holder->Append(Value::CreateStringValue(inproduct));
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        tip_counter++;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // If tips exist, set current index to 0.
3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!inproduct.empty()) {
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        web_resource_cache_->SetInteger(
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          WebResourceService::kCurrentTipPrefName, 0);
3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochvoid WebResourceService::UnpackPromoSignal(const DictionaryValue& parsed_json) {
388201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DictionaryValue* topic_dict;
389201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  ListValue* answer_list;
390201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  double old_promo_start = 0;
391201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  double old_promo_end = 0;
392201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  double promo_start = 0;
393201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  double promo_end = 0;
394201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
395201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Check for preexisting start and end values.
396201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (prefs_->HasPrefPath(prefs::kNTPPromoStart) &&
397201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      prefs_->HasPrefPath(prefs::kNTPPromoEnd)) {
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    old_promo_start = prefs_->GetDouble(prefs::kNTPPromoStart);
39972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    old_promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd);
400201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
401201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
402201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Check for newly received start and end values.
403201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (parsed_json.GetDictionary("topic", &topic_dict)) {
404201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (topic_dict->GetList("answers", &answer_list)) {
405201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      std::string promo_start_string = "";
406201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      std::string promo_end_string = "";
407201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      std::string promo_string = "";
40872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      std::string promo_build = "";
40972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      int promo_build_type = 0;
41072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      int time_slice_hrs = 0;
411201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      for (ListValue::const_iterator tip_iter = answer_list->begin();
412201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch           tip_iter != answer_list->end(); ++tip_iter) {
413201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
414201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          continue;
415201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        DictionaryValue* a_dic =
416201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            static_cast<DictionaryValue*>(*tip_iter);
417201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        std::string promo_signal;
418201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        if (a_dic->GetString("name", &promo_signal)) {
419201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          if (promo_signal == "promo_start") {
42072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            a_dic->GetString("question", &promo_build);
42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            size_t split = promo_build.find(":");
42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            if (split != std::string::npos &&
42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                base::StringToInt(promo_build.substr(0, split),
42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                  &promo_build_type) &&
42572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                base::StringToInt(promo_build.substr(split+1),
42672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                  &time_slice_hrs) &&
42772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                promo_build_type >= 0 &&
42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                promo_build_type <= (DEV_BUILD | BETA_BUILD | STABLE_BUILD) &&
42972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                time_slice_hrs >= 0 &&
43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                time_slice_hrs <= kMaxTimeSliceHours) {
43172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              prefs_->SetInteger(prefs::kNTPPromoBuild, promo_build_type);
43272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice,
43372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                 time_slice_hrs);
43472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            } else {
43572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              // If no time data or bad time data are set, show promo on all
43672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              // builds with no time slicing.
43772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              prefs_->SetInteger(prefs::kNTPPromoBuild,
43872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                 DEV_BUILD | BETA_BUILD | STABLE_BUILD);
43972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, 0);
44072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            }
441201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            a_dic->GetString("inproduct", &promo_start_string);
442201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            a_dic->GetString("tooltip", &promo_string);
443201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            prefs_->SetString(prefs::kNTPPromoLine, promo_string);
44472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            srand(static_cast<uint32>(time(NULL)));
44572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            prefs_->SetInteger(prefs::kNTPPromoGroup,
44672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                               rand() % kNTPPromoGroupSize);
447201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          } else if (promo_signal == "promo_end") {
448201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            a_dic->GetString("inproduct", &promo_end_string);
449201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          }
450201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        }
451201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      }
452201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      if (!promo_start_string.empty() &&
453201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          promo_start_string.length() > 0 &&
454201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          !promo_end_string.empty() &&
455201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          promo_end_string.length() > 0) {
456201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        base::Time start_time;
457201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        base::Time end_time;
458201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        if (base::Time::FromString(
459201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                ASCIIToWide(promo_start_string).c_str(), &start_time) &&
460201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch            base::Time::FromString(
461201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch                ASCIIToWide(promo_end_string).c_str(), &end_time)) {
46272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          // Add group time slice, adjusted from hours to seconds.
46372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          promo_start = start_time.ToDoubleT() +
46472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              (prefs_->FindPreference(prefs::kNTPPromoGroup) ?
46572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                  prefs_->GetInteger(prefs::kNTPPromoGroup) *
46672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                      time_slice_hrs * 60 * 60 : 0);
467201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          promo_end = end_time.ToDoubleT();
468201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch        }
469201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      }
470201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
471201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
472201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
473201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // If start or end times have changed, trigger a new web resource
474201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // notification, so that the logo on the NTP is updated. This check is
475201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // outside the reading of the web resource data, because the absence of
476201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // dates counts as a triggering change if there were dates before.
47772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Also reset the promo closed preference, to signal a new promo.
478201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!(old_promo_start == promo_start) ||
479201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      !(old_promo_end == promo_end)) {
48072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefs_->SetDouble(prefs::kNTPPromoStart, promo_start);
48172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end);
48272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefs_->SetBoolean(prefs::kNTPPromoClosed, false);
483201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    ScheduleNotification(promo_start, promo_end);
484201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
485201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
486201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
4873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid WebResourceService::UnpackLogoSignal(const DictionaryValue& parsed_json) {
4883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DictionaryValue* topic_dict;
4893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ListValue* answer_list;
4903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double old_logo_start = 0;
4913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double old_logo_end = 0;
4923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double logo_start = 0;
4933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  double logo_end = 0;
4943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check for preexisting start and end values.
4963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (prefs_->HasPrefPath(prefs::kNTPCustomLogoStart) &&
4973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      prefs_->HasPrefPath(prefs::kNTPCustomLogoEnd)) {
49872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    old_logo_start = prefs_->GetDouble(prefs::kNTPCustomLogoStart);
49972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    old_logo_end = prefs_->GetDouble(prefs::kNTPCustomLogoEnd);
5003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Check for newly received start and end values.
5033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parsed_json.GetDictionary("topic", &topic_dict)) {
5043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (topic_dict->GetList("answers", &answer_list)) {
5053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string logo_start_string = "";
5063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      std::string logo_end_string = "";
5073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      for (ListValue::const_iterator tip_iter = answer_list->begin();
5083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick           tip_iter != answer_list->end(); ++tip_iter) {
5093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY))
5103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          continue;
5113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        DictionaryValue* a_dic =
5123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            static_cast<DictionaryValue*>(*tip_iter);
5133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        std::string logo_signal;
5143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (a_dic->GetString("name", &logo_signal)) {
5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          if (logo_signal == "custom_logo_start") {
5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            a_dic->GetString("inproduct", &logo_start_string);
5173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          } else if (logo_signal == "custom_logo_end") {
5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            a_dic->GetString("inproduct", &logo_end_string);
5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          }
5203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (!logo_start_string.empty() &&
5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_start_string.length() > 0 &&
5243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          !logo_end_string.empty() &&
5253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_end_string.length() > 0) {
5263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        base::Time start_time;
5273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        base::Time end_time;
5283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        if (base::Time::FromString(
5293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                ASCIIToWide(logo_start_string).c_str(), &start_time) &&
5303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick            base::Time::FromString(
5313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                ASCIIToWide(logo_end_string).c_str(), &end_time)) {
5323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_start = start_time.ToDoubleT();
5333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          logo_end = end_time.ToDoubleT();
5343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
5353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
539731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // If logo start or end times have changed, trigger a new web resource
540731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // notification, so that the logo on the NTP is updated. This check is
541731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // outside the reading of the web resource data, because the absence of
542731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // dates counts as a triggering change if there were dates before.
5433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!(old_logo_start == logo_start) ||
5443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      !(old_logo_end == logo_end)) {
54572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefs_->SetDouble(prefs::kNTPCustomLogoStart, logo_start);
54672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    prefs_->SetDouble(prefs::kNTPCustomLogoEnd, logo_end);
5473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    NotificationService* service = NotificationService::current();
548201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    service->Notify(NotificationType::WEB_RESOURCE_STATE_CHANGED,
5493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                    Source<WebResourceService>(this),
5503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                    NotificationService::NoDetails());
5513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
553201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
554201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochnamespace WebResourceServiceUtil {
555201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
556201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool CanShowPromo(Profile* profile) {
557201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  bool promo_closed = false;
558201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  PrefService* prefs = profile->GetPrefs();
559201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (prefs->HasPrefPath(prefs::kNTPPromoClosed))
560201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed);
561201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
56272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Only show if not synced.
56372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool is_synced =
564201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      (profile->HasProfileSyncService() &&
565201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch          sync_ui_util::GetStatus(
56672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen              profile->GetProfileSyncService()) == sync_ui_util::SYNCED);
56772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // GetVersionStringModifier hits the registry. See http://crbug.com/70898.
56972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::ThreadRestrictions::ScopedAllowIO allow_io;
57072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const std::string channel = platform_util::GetVersionStringModifier();
57172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool is_promo_build = false;
57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) {
57372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int builds_allowed = prefs->GetInteger(prefs::kNTPPromoBuild);
57472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (channel == "dev") {
57572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      is_promo_build = (DEV_BUILD & builds_allowed) != 0;
57672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (channel == "beta") {
57772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      is_promo_build = (BETA_BUILD & builds_allowed) != 0;
57872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (channel == "stable") {
57972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      is_promo_build = (STABLE_BUILD & builds_allowed) != 0;
58072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else {
58172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      is_promo_build = true;
58272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
58372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
584201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
58572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return !promo_closed && !is_synced && is_promo_build;
586201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
587201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
588201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}  // namespace WebResourceService
589201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
590