15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/customization_document.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include <algorithm>
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_reader.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/memory/weak_ptr.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/metrics/histogram.h"
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/path_service.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_split.h"
215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/strings/stringprintf.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/chromeos/customization_wallpaper_downloader.h"
27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/chromeos/extensions/default_app_order.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/login/wizard_controller.h"
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/chromeos/net/delay_network_call.h"
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/extensions/external_loader.h"
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/extensions/external_provider_impl.h"
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/common/chrome_paths.h"
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/common/pref_names.h"
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chromeos/system/statistics_provider.h"
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension_urls.h"
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/load_flags.h"
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/http/http_response_headers.h"
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "net/http/http_status_code.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/base/l10n/l10n_util.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace chromeos {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Manifest attributes names.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kVersionAttr[] = "version";
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDefaultAttr[] = "default";
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInitialLocaleAttr[] = "initial_locale";
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kInitialTimezoneAttr[] = "initial_timezone";
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kKeyboardLayoutAttr[] = "keyboard_layout";
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHwidMapAttr[] = "hwid_map";
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kHwidMaskAttr[] = "hwid_mask";
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kSetupContentAttr[] = "setup_content";
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kEulaPageAttr[] = "eula_page";
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kDefaultWallpaperAttr[] = "default_wallpaper";
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kDefaultAppsAttr[] = "default_apps";
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kLocalizedContent[] = "localized_content";
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kDefaultAppsFolderName[] = "default_apps_folder_name";
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAcceptedManifestVersion[] = "1.0";
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Path to OEM partner startup customization manifest.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kStartupCustomizationManifestPath[] =
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "/opt/oem/etc/startup_manifest.json";
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// This is subdirectory relative to PathService(DIR_CHROMEOS_CUSTOM_WALLPAPERS),
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// where downloaded (and resized) wallpaper is stored.
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kCustomizationDefaultWallpaperDir[] = "customization";
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// The original downloaded image file is stored under this name.
790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochconst char kCustomizationDefaultWallpaperDownloadedFile[] =
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    "default_downloaded_wallpaper.bin";
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Name of local state option that tracks if services customization has been
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// applied.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kServicesCustomizationAppliedPref[] = "ServicesCustomizationApplied";
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of retries to fetch file if network is not available.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxFetchRetries = 3;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delay between file fetch retries if network is not available.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kRetriesDelayInSec = 2;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Name of profile option that tracks cached version of service customization.
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char kServicesCustomizationKey[] = "customization.manifest_cache";
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Empty customization document that doesn't customize anything.
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochconst char kEmptyServicesCustomizationManifest[] = "{ \"version\": \"1.0\" }";
97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Global overrider for ServicesCustomizationDocument for tests.
99effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochServicesCustomizationDocument* g_test_services_customization_document = NULL;
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Services customization document load results reported via the
102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// "ServicesCustomization.LoadResult" histogram.
103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// It is append-only enum due to use in a histogram!
104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochenum HistogramServicesCustomizationLoadResult {
105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  HISTOGRAM_LOAD_RESULT_SUCCESS = 0,
106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  HISTOGRAM_LOAD_RESULT_FILE_NOT_FOUND = 1,
107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  HISTOGRAM_LOAD_RESULT_PARSING_ERROR = 2,
108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  HISTOGRAM_LOAD_RESULT_RETRIES_FAIL = 3,
109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  HISTOGRAM_LOAD_RESULT_MAX_VALUE = 4
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch};
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid LogManifestLoadResult(HistogramServicesCustomizationLoadResult result) {
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  UMA_HISTOGRAM_ENUMERATION("ServicesCustomization.LoadResult",
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            result,
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            HISTOGRAM_LOAD_RESULT_MAX_VALUE);
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string GetLocaleSpecificStringImpl(
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const base::DictionaryValue* root,
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& locale,
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& dictionary_name,
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& entry_name) {
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const base::DictionaryValue* dictionary_content = NULL;
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!root || !root->GetDictionary(dictionary_name, &dictionary_content))
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return std::string();
126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const base::DictionaryValue* locale_dictionary = NULL;
128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (dictionary_content->GetDictionary(locale, &locale_dictionary)) {
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string result;
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (locale_dictionary->GetString(entry_name, &result))
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return result;
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const base::DictionaryValue* default_dictionary = NULL;
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (dictionary_content->GetDictionary(kDefaultAttr, &default_dictionary)) {
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string result;
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (default_dictionary->GetString(entry_name, &result))
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return result;
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return std::string();
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid CheckWallpaperCacheExists(const base::FilePath& path, bool* exists) {
1450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
1460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(exists);
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  *exists = base::PathExists(path);
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // anonymous namespace
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Template URL where to fetch OEM services customization manifest from.
153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)const char ServicesCustomizationDocument::kManifestUrl[] =
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    "https://ssl.gstatic.com/chrome/chromeos-customization/%s.json";
155a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A custom extensions::ExternalLoader that the ServicesCustomizationDocument
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// creates and uses to publish OEM default apps to the extensions system.
158a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ServicesCustomizationExternalLoader
159a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : public extensions::ExternalLoader,
160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      public base::SupportsWeakPtr<ServicesCustomizationExternalLoader> {
161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public:
162a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  explicit ServicesCustomizationExternalLoader(Profile* profile)
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      : is_apps_set_(false), profile_(profile) {}
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Profile* profile() { return profile_; }
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Used by the ServicesCustomizationDocument to update the current apps.
168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void SetCurrentApps(scoped_ptr<base::DictionaryValue> prefs) {
169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    apps_.Swap(prefs.get());
170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    is_apps_set_ = true;
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    StartLoading();
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Implementation of extensions::ExternalLoader:
175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void StartLoading() OVERRIDE {
176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (!is_apps_set_) {
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ServicesCustomizationDocument::GetInstance()->StartFetching();
178a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      // In case of missing customization ID, SetCurrentApps will be called
179a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      // synchronously from StartFetching and this function will be called
1800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // recursively so we need to return to avoid calling LoadFinished twice.
181a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      // In case of async load it is safe to return empty list because this
182a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      // provider didn't install any app yet so no app can be removed due to
183a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      // returning empty list.
184a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      if (is_apps_set_)
185a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        return;
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    prefs_.reset(apps_.DeepCopy());
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "ServicesCustomization extension loader publishing "
190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << apps_.size() << " apps.";
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LoadFinished();
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) protected:
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual ~ServicesCustomizationExternalLoader() {}
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool is_apps_set_;
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::DictionaryValue apps_;
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Profile* profile_;
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ServicesCustomizationExternalLoader);
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CustomizationDocument implementation. ---------------------------------------
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CustomizationDocument::CustomizationDocument(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& accepted_version)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : accepted_version_(accepted_version) {}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CustomizationDocument::~CustomizationDocument() {}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CustomizationDocument::LoadManifestFromFile(
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& manifest_path) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string manifest;
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (!base::ReadFileToString(manifest_path, &manifest))
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return LoadManifestFromString(manifest);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CustomizationDocument::LoadManifestFromString(
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& manifest) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int error_code = 0;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error;
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> root(base::JSONReader::ReadAndReturnError(manifest,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::JSON_ALLOW_TRAILING_COMMAS, &error_code, &error));
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_code != base::JSONReader::JSON_NO_ERROR)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << error;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(root.get() != NULL);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (root.get() == NULL)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(root->GetType() == base::Value::TYPE_DICTIONARY);
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (root->GetType() == base::Value::TYPE_DICTIONARY) {
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    root_.reset(static_cast<base::DictionaryValue*>(root.release()));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string result;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (root_->GetString(kVersionAttr, &result) &&
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result == accepted_version_)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Wrong customization manifest version";
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_.reset(NULL);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string CustomizationDocument::GetLocaleSpecificString(
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& locale,
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& dictionary_name,
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& entry_name) const {
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return GetLocaleSpecificStringImpl(
251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      root_.get(), locale, dictionary_name, entry_name);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// StartupCustomizationDocument implementation. --------------------------------
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupCustomizationDocument::StartupCustomizationDocument()
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : CustomizationDocument(kAcceptedManifestVersion) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Loading manifest causes us to do blocking IO on UI thread.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Temporarily allow it until we fix http://crosbug.com/11103
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::ThreadRestrictions::ScopedAllowIO allow_io;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LoadManifestFromFile(base::FilePath(kStartupCustomizationManifestPath));
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Init(system::StatisticsProvider::GetInstance());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupCustomizationDocument::StartupCustomizationDocument(
268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    system::StatisticsProvider* statistics_provider,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& manifest)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : CustomizationDocument(kAcceptedManifestVersion) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadManifestFromString(manifest);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Init(statistics_provider);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupCustomizationDocument::~StartupCustomizationDocument() {}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StartupCustomizationDocument* StartupCustomizationDocument::GetInstance() {
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Singleton<StartupCustomizationDocument,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DefaultSingletonTraits<StartupCustomizationDocument> >::get();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StartupCustomizationDocument::Init(
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    system::StatisticsProvider* statistics_provider) {
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsReady()) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_->GetString(kInitialLocaleAttr, &initial_locale_);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_->GetString(kInitialTimezoneAttr, &initial_timezone_);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root_->GetString(kKeyboardLayoutAttr, &keyboard_layout_);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string hwid;
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (statistics_provider->GetMachineStatistic(
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            system::kHardwareClassKey, &hwid)) {
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::ListValue* hwid_list = NULL;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (root_->GetList(kHwidMapAttr, &hwid_list)) {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        for (size_t i = 0; i < hwid_list->GetSize(); ++i) {
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::DictionaryValue* hwid_dictionary = NULL;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          std::string hwid_mask;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if (hwid_list->GetDictionary(i, &hwid_dictionary) &&
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              hwid_dictionary->GetString(kHwidMaskAttr, &hwid_mask)) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (MatchPattern(hwid, hwid_mask)) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // If HWID for this machine matches some mask, use HWID specific
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              // settings.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              std::string result;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if (hwid_dictionary->GetString(kInitialLocaleAttr, &result))
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                initial_locale_ = result;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if (hwid_dictionary->GetString(kInitialTimezoneAttr, &result))
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                initial_timezone_ = result;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if (hwid_dictionary->GetString(kKeyboardLayoutAttr, &result))
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                keyboard_layout_ = result;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Don't break here to allow other entires to be applied if match.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          } else {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            LOG(ERROR) << "Syntax error in customization manifest";
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "HWID is missing in machine statistics";
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If manifest doesn't exist still apply values from VPD.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statistics_provider->GetMachineStatistic(kInitialLocaleAttr,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &initial_locale_);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statistics_provider->GetMachineStatistic(kInitialTimezoneAttr,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &initial_timezone_);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  statistics_provider->GetMachineStatistic(kKeyboardLayoutAttr,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           &keyboard_layout_);
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  configured_locales_.resize(0);
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::SplitString(initial_locale_, ',', &configured_locales_);
332c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
333c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Convert ICU locale to chrome ("en_US" to "en-US", etc.).
334c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  std::for_each(configured_locales_.begin(),
335c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                configured_locales_.end(),
336c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                l10n_util::GetCanonicalLocale);
337c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Let's always have configured_locales_.front() a valid entry.
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (configured_locales_.size() == 0)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    configured_locales_.push_back(std::string());
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const std::vector<std::string>&
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)StartupCustomizationDocument::configured_locales() const {
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return configured_locales_;
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const std::string& StartupCustomizationDocument::initial_locale_default()
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const {
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(configured_locales_.size() > 0);
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return configured_locales_.front();
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string StartupCustomizationDocument::GetEULAPage(
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& locale) const {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetLocaleSpecificString(locale, kSetupContentAttr, kEulaPageAttr);
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ServicesCustomizationDocument implementation. -------------------------------
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochclass ServicesCustomizationDocument::ApplyingTask {
3620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch public:
3630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Registers in ServicesCustomizationDocument;
3640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  explicit ApplyingTask(ServicesCustomizationDocument* document);
3650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Do not automatically deregister as we might be called on invalid thread.
3670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ~ApplyingTask();
3680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Mark task finished and check for customization applied.
3700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  void Finished(bool success);
3710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch private:
3730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ServicesCustomizationDocument* document_;
3740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // This is error-checking flag to prevent destroying unfinished task
3760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // or double finish.
3770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bool engaged_;
3780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch};
3790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3800529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochServicesCustomizationDocument::ApplyingTask::ApplyingTask(
3810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ServicesCustomizationDocument* document)
3820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : document_(document), engaged_(true) {
3830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  document->ApplyingTaskStarted();
3840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3860529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochServicesCustomizationDocument::ApplyingTask::~ApplyingTask() {
3870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(!engaged_);
3880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::ApplyingTask::Finished(bool success) {
3910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(engaged_);
3920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (engaged_) {
3930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    engaged_ = false;
3940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    document_->ApplyingTaskFinished(success);
3950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
3960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
3970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServicesCustomizationDocument::ServicesCustomizationDocument()
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : CustomizationDocument(kAcceptedManifestVersion),
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      num_retries_(0),
401effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      fetch_started_(false),
4020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      network_delay_(
4030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)),
4040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      apply_tasks_started_(0),
4050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      apply_tasks_finished_(0),
4060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      apply_tasks_success_(0),
407effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      weak_ptr_factory_(this) {
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServicesCustomizationDocument::ServicesCustomizationDocument(
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& manifest)
412effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : CustomizationDocument(kAcceptedManifestVersion),
4130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      network_delay_(
4140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)),
4150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      apply_tasks_started_(0),
4160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      apply_tasks_finished_(0),
4170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      apply_tasks_success_(0),
418effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      weak_ptr_factory_(this) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LoadManifestFromString(manifest);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServicesCustomizationDocument::~ServicesCustomizationDocument() {}
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ServicesCustomizationDocument* ServicesCustomizationDocument::GetInstance() {
426effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (g_test_services_customization_document)
427effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return g_test_services_customization_document;
428effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Singleton<ServicesCustomizationDocument,
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DefaultSingletonTraits<ServicesCustomizationDocument> >::get();
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ServicesCustomizationDocument::RegisterPrefs(
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PrefRegistrySimple* registry) {
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterBooleanPref(kServicesCustomizationAppliedPref, false);
4370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  registry->RegisterStringPref(prefs::kCustomizationDefaultWallpaperURL,
4380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                               std::string());
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
442a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ServicesCustomizationDocument::RegisterProfilePrefs(
443a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    user_prefs::PrefRegistrySyncable* registry) {
444a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  registry->RegisterDictionaryPref(
445a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      kServicesCustomizationKey,
446a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
447a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
449a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// static
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ServicesCustomizationDocument::WasOOBECustomizationApplied() {
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* prefs = g_browser_process->local_state();
452a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // prefs can be NULL in some tests.
453a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (prefs)
454a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return prefs->GetBoolean(kServicesCustomizationAppliedPref);
455a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  else
456a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return false;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServicesCustomizationDocument::SetApplied(bool val) {
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* prefs = g_browser_process->local_state();
462a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // prefs can be NULL in some tests.
463a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (prefs)
464a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    prefs->SetBoolean(kServicesCustomizationAppliedPref, val);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// static
4680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::FilePath ServicesCustomizationDocument::GetCustomizedWallpaperCacheDir() {
4690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::FilePath custom_wallpaper_dir;
4700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!PathService::Get(chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS,
4710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                        &custom_wallpaper_dir)) {
4720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(DFATAL) << "Unable to get custom wallpaper dir.";
4730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return base::FilePath();
4740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
4750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return custom_wallpaper_dir.Append(kCustomizationDefaultWallpaperDir);
4760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// static
4790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::FilePath
4800529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochServicesCustomizationDocument::GetCustomizedWallpaperDownloadedFileName() {
4810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const base::FilePath dir = GetCustomizedWallpaperCacheDir();
4820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (dir.empty()) {
4830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    NOTREACHED();
4840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return dir;
4850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
4860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return dir.Append(kCustomizationDefaultWallpaperDownloadedFile);
4870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::EnsureCustomizationApplied() {
4900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (WasOOBECustomizationApplied())
4910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
4920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // When customization manifest is fetched, applying will start automatically.
4940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (IsReady())
4950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
4960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
4970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  StartFetching();
4980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
4990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
5000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbase::Closure
5010529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochServicesCustomizationDocument::EnsureCustomizationAppliedClosure() {
5020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return base::Bind(&ServicesCustomizationDocument::EnsureCustomizationApplied,
5030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                    weak_ptr_factory_.GetWeakPtr());
5040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
5050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServicesCustomizationDocument::StartFetching() {
507effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (IsReady() || fetch_started_)
508effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
509effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
510effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!url_.is_valid()) {
511effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    std::string customization_id;
512effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    chromeos::system::StatisticsProvider* provider =
513effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        chromeos::system::StatisticsProvider::GetInstance();
514effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (provider->GetMachineStatistic(system::kCustomizationIdKey,
515effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                      &customization_id) &&
516effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        !customization_id.empty()) {
517effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      url_ = GURL(base::StringPrintf(
5186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          kManifestUrl, base::StringToLowerASCII(customization_id).c_str()));
519a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    } else {
5200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // Remember that there is no customization ID in VPD.
521a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      OnCustomizationNotFound();
522a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return;
523a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
524effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
525a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
526effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (url_.is_valid()) {
527effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    fetch_started_ = true;
528effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (url_.SchemeIsFile()) {
529effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
530effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          base::Bind(&ServicesCustomizationDocument::ReadFileInBackground,
531effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     weak_ptr_factory_.GetWeakPtr(),
532effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     base::FilePath(url_.path())));
533effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    } else {
534effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      StartFileFetch();
535a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
539effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ServicesCustomizationDocument::ReadFileInBackground(
541effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    base::WeakPtr<ServicesCustomizationDocument> self,
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& file) {
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string manifest;
546a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!base::ReadFileToString(file, &manifest)) {
547a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    manifest.clear();
548a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Failed to load services customization manifest from: "
549a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               << file.value();
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
551a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
552a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
553a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&ServicesCustomizationDocument::OnManifesteRead,
554effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 self,
555a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 manifest));
556a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
557a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
558a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ServicesCustomizationDocument::OnManifesteRead(
559a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& manifest) {
560a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!manifest.empty())
561a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LoadManifestFromString(manifest);
562a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
563a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  fetch_started_ = false;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServicesCustomizationDocument::StartFileFetch() {
567effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DelayNetworkCall(base::Bind(&ServicesCustomizationDocument::DoStartFileFetch,
568effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                              weak_ptr_factory_.GetWeakPtr()),
569effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      network_delay_);
570effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
571effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
572effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ServicesCustomizationDocument::DoStartFileFetch() {
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_fetcher_.reset(net::URLFetcher::Create(
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url_, net::URLFetcher::GET, this));
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  url_fetcher_->SetRequestContext(g_browser_process->system_request_context());
576a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  url_fetcher_->AddExtraRequestHeader("Accept: application/json");
577a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
578a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             net::LOAD_DO_NOT_SAVE_COOKIES |
579a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             net::LOAD_DISABLE_CACHE |
580a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                             net::LOAD_DO_NOT_SEND_AUTH_DATA);
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_fetcher_->Start();
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
584a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ServicesCustomizationDocument::LoadManifestFromString(
585a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& manifest) {
586a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (CustomizationDocument::LoadManifestFromString(manifest)) {
587effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LogManifestLoadResult(HISTOGRAM_LOAD_RESULT_SUCCESS);
588a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    OnManifestLoaded();
589a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
590a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
591effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
592effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LogManifestLoadResult(HISTOGRAM_LOAD_RESULT_PARSING_ERROR);
593a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
594a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
595a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
596a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ServicesCustomizationDocument::OnManifestLoaded() {
5970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!WasOOBECustomizationApplied())
598a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    ApplyOOBECustomization();
599a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
600a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> prefs =
601a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      GetDefaultAppsInProviderFormat(*root_);
602a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (ExternalLoaders::iterator it = external_loaders_.begin();
603a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       it != external_loaders_.end(); ++it) {
604a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (*it) {
605a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      UpdateCachedManifest((*it)->profile());
606a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      (*it)->SetCurrentApps(
607a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          scoped_ptr<base::DictionaryValue>(prefs->DeepCopy()));
608effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      SetOemFolderName((*it)->profile(), *root_);
609a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
610a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
611a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
612a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ServicesCustomizationDocument::OnURLFetchComplete(
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLFetcher* source) {
615a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string mime_type;
616a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string data;
617a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (source->GetStatus().is_success() &&
618effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      source->GetResponseCode() == net::HTTP_OK &&
619a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      source->GetResponseHeaders()->GetMimeType(&mime_type) &&
620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      mime_type == "application/json" &&
621a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      source->GetResponseAsString(&data)) {
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LoadManifestFromString(data);
623effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  } else if (source->GetResponseCode() == net::HTTP_NOT_FOUND) {
624effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LOG(ERROR) << "Customization manifest is missing on server: "
625effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch               << source->GetURL().spec();
626effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    OnCustomizationNotFound();
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
628effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (num_retries_ < kMaxFetchRetries) {
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      num_retries_++;
630effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      content::BrowserThread::PostDelayedTask(
631effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          content::BrowserThread::UI,
632effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          FROM_HERE,
633effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          base::Bind(&ServicesCustomizationDocument::StartFileFetch,
634effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     weak_ptr_factory_.GetWeakPtr()),
635effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          base::TimeDelta::FromSeconds(kRetriesDelayInSec));
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
638effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // This doesn't stop fetching manifest on next restart.
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "URL fetch for services customization failed:"
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " response code = " << source->GetResponseCode()
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " URL = " << source->GetURL().spec();
642effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
643effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    LogManifestLoadResult(HISTOGRAM_LOAD_RESULT_RETRIES_FAIL);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
645effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  fetch_started_ = false;
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ServicesCustomizationDocument::ApplyOOBECustomization() {
6490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (apply_tasks_started_)
6500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
6510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CheckAndApplyWallpaper();
6530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return false;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool ServicesCustomizationDocument::GetDefaultWallpaperUrl(
6570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    GURL* out_url) const {
658a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsReady())
6590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
660a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
661a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string url;
6620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!root_->GetString(kDefaultWallpaperAttr, &url))
6630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return false;
6640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
6650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  *out_url = GURL(url);
6660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return true;
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
669a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ServicesCustomizationDocument::GetDefaultApps(
670a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::vector<std::string>* ids) const {
671a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ids->clear();
672a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!IsReady())
673a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
674a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
675a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::ListValue* apps_list = NULL;
676a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!root_->GetList(kDefaultAppsAttr, &apps_list))
677a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
678a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
679a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < apps_list->GetSize(); ++i) {
680a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string app_id;
681a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (apps_list->GetString(i, &app_id)) {
682a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ids->push_back(app_id);
683a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
684a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      LOG(ERROR) << "Wrong format of default application list";
685a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return false;
686a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
687a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
688a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
689a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
690a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
691a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
692effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string ServicesCustomizationDocument::GetOemAppsFolderName(
693effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& locale) const {
694effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!IsReady())
695effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return std::string();
696effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
697effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return GetOemAppsFolderNameImpl(locale, *root_);
698effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
699effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
700a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)scoped_ptr<base::DictionaryValue>
701a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ServicesCustomizationDocument::GetDefaultAppsInProviderFormat(
702a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::DictionaryValue& root) {
703a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
704a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const base::ListValue* apps_list = NULL;
705a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (root.GetList(kDefaultAppsAttr, &apps_list)) {
706a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for (size_t i = 0; i < apps_list->GetSize(); ++i) {
707a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      std::string app_id;
708a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (apps_list->GetString(i, &app_id)) {
709a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::DictionaryValue* entry = new base::DictionaryValue;
710a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        entry->SetString(extensions::ExternalProviderImpl::kExternalUpdateUrl,
711a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                         extension_urls::GetWebstoreUpdateUrl().spec());
712a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        prefs->Set(app_id, entry);
713a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      } else {
714a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        LOG(ERROR) << "Wrong format of default application list";
715a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        prefs->Clear();
716a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        break;
717a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
718a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
719a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
720a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
721a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return prefs.Pass();
722a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
723a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
724a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void ServicesCustomizationDocument::UpdateCachedManifest(Profile* profile) {
725a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  profile->GetPrefs()->Set(kServicesCustomizationKey, *root_);
726a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
727a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
728a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)extensions::ExternalLoader* ServicesCustomizationDocument::CreateExternalLoader(
729a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    Profile* profile) {
730a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  ServicesCustomizationExternalLoader* loader =
731a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new ServicesCustomizationExternalLoader(profile);
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  external_loaders_.push_back(loader->AsWeakPtr());
733a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
734a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (IsReady()) {
735a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    UpdateCachedManifest(profile);
736a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    loader->SetCurrentApps(GetDefaultAppsInProviderFormat(*root_));
737effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    SetOemFolderName(profile, *root_);
738a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
739a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const base::DictionaryValue* root =
740a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        profile->GetPrefs()->GetDictionary(kServicesCustomizationKey);
741a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    std::string version;
742a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (root && root->GetString(kVersionAttr, &version)) {
743a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // If version exists, profile has cached version of customization.
744a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      loader->SetCurrentApps(GetDefaultAppsInProviderFormat(*root));
745effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      SetOemFolderName(profile, *root);
746a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
747a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // StartFetching will be called from ServicesCustomizationExternalLoader
748a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // when StartLoading is called. We can't initiate manifest fetch here
749a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      // because caller may never call StartLoading for the provider.
750a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
751a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
752a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
753a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return loader;
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
756effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ServicesCustomizationDocument::OnCustomizationNotFound() {
757effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LogManifestLoadResult(HISTOGRAM_LOAD_RESULT_FILE_NOT_FOUND);
758effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  LoadManifestFromString(kEmptyServicesCustomizationManifest);
759effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
760effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
761effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ServicesCustomizationDocument::SetOemFolderName(
762effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    Profile* profile,
763effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const base::DictionaryValue& root) {
764effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string locale = g_browser_process->GetApplicationLocale();
765effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::string name = GetOemAppsFolderNameImpl(locale, root);
766c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (name.empty())
767c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    name = default_app_order::GetOemAppsFolderName();
768effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!name.empty()) {
769effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    app_list::AppListSyncableService* service =
770effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        app_list::AppListSyncableServiceFactory::GetForProfile(profile);
771effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (!service) {
772effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      LOG(WARNING) << "AppListSyncableService is not ready for setting OEM "
773effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                      "folder name";
774effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      return;
775effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
776effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    service->SetOemFolderName(name);
777effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
778effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
779effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
780effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string ServicesCustomizationDocument::GetOemAppsFolderNameImpl(
781effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& locale,
782effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const base::DictionaryValue& root) const {
783effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return GetLocaleSpecificStringImpl(
784effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      &root, locale, kLocalizedContent, kDefaultAppsFolderName);
785effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
786effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
787effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
788effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ServicesCustomizationDocument::InitializeForTesting() {
789effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  g_test_services_customization_document = new ServicesCustomizationDocument;
790effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  g_test_services_customization_document->network_delay_ = base::TimeDelta();
791effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
792effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
793effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
794effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid ServicesCustomizationDocument::ShutdownForTesting() {
795effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  delete g_test_services_customization_document;
796effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  g_test_services_customization_document = NULL;
797effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
798effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::StartOEMWallpaperDownload(
8000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& wallpaper_url,
8010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying) {
8020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(wallpaper_url.is_valid());
8030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const base::FilePath dir = GetCustomizedWallpaperCacheDir();
8050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const base::FilePath file = GetCustomizedWallpaperDownloadedFileName();
8060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (dir.empty() || file.empty()) {
8070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    NOTREACHED();
8080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    applying->Finished(false);
8090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
8100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
8110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  wallpaper_downloader_.reset(new CustomizationWallpaperDownloader(
8130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      g_browser_process->system_request_context(),
8140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      wallpaper_url,
8150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      dir,
8160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      file,
8170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Bind(&ServicesCustomizationDocument::OnOEMWallpaperDownloaded,
8180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 weak_ptr_factory_.GetWeakPtr(),
8190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 base::Passed(applying.Pass()))));
8200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  wallpaper_downloader_->Start();
8220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
8230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::CheckAndApplyWallpaper() {
8250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (wallpaper_downloader_.get()) {
8260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    VLOG(1) << "CheckAndApplyWallpaper(): download has already started.";
8270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
8280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
8290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying(
8300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      new ServicesCustomizationDocument::ApplyingTask(this));
8310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  GURL wallpaper_url;
8330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!GetDefaultWallpaperUrl(&wallpaper_url)) {
8340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    PrefService* pref_service = g_browser_process->local_state();
8350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::string current_url =
8360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        pref_service->GetString(prefs::kCustomizationDefaultWallpaperURL);
8370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!current_url.empty()) {
8380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      VLOG(1) << "ServicesCustomizationDocument::CheckAndApplyWallpaper() : "
8390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "No wallpaper URL attribute in customization document, "
8400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "but current value is non-empty: '" << current_url
8410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "'. Ignored.";
8420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
8430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    applying->Finished(true);
8440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
8450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
8460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Should fail if this ever happens in tests.
8480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(wallpaper_url.is_valid());
8490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!wallpaper_url.is_valid()) {
8500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (!wallpaper_url.is_empty()) {
8510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      LOG(WARNING) << "Invalid Customized Wallpaper URL '"
8520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                   << wallpaper_url.spec() << "'.";
8530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
8540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    applying->Finished(false);
8550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
8560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
8570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<bool> exists(new bool(false));
8590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::Closure check_file_exists =
8610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Bind(&CheckWallpaperCacheExists,
8620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 GetCustomizedWallpaperDownloadedFileName(),
8630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 base::Unretained(exists.get()));
8640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::Closure on_checked_closure =
8650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Bind(&ServicesCustomizationDocument::OnCheckedWallpaperCacheExists,
8660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 weak_ptr_factory_.GetWeakPtr(),
8670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 base::Passed(exists.Pass()),
8680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 base::Passed(applying.Pass()));
8690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
8700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          FROM_HERE, check_file_exists, on_checked_closure)) {
8710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    LOG(WARNING) << "Failed to start check Wallpaper cache exists.";
8720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
8730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
8740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::OnCheckedWallpaperCacheExists(
8760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_ptr<bool> exists,
8770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying) {
8780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
8790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(exists);
8800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(applying);
8810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ApplyWallpaper(*exists, applying.Pass());
8830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
8840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::ApplyWallpaper(
8860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    bool default_wallpaper_file_exists,
8870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying) {
8880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  GURL wallpaper_url;
8890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const bool wallpaper_url_present = GetDefaultWallpaperUrl(&wallpaper_url);
8900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  PrefService* pref_service = g_browser_process->local_state();
8920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
8930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  std::string current_url =
8940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      pref_service->GetString(prefs::kCustomizationDefaultWallpaperURL);
8950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (current_url != wallpaper_url.spec()) {
8960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (wallpaper_url_present) {
8970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      VLOG(1) << "ServicesCustomizationDocument::ApplyWallpaper() : "
8980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "Wallpaper URL in customization document '"
8990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << wallpaper_url.spec() << "' differs from current '"
9000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << current_url << "'."
9010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << (GURL(current_url).is_valid() && default_wallpaper_file_exists
9020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      ? " Ignored."
9030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                      : " Will refetch.");
9040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    } else {
9050529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      VLOG(1) << "ServicesCustomizationDocument::ApplyWallpaper() : "
9060529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "No wallpaper URL attribute in customization document, "
9070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "but current value is non-empty: '" << current_url
9080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch              << "'. Ignored.";
9090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
9100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
9110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!wallpaper_url_present) {
9120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    applying->Finished(true);
9130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
9140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
9150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK(wallpaper_url.is_valid());
9170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Never update system-wide wallpaper (i.e. do not check
9190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // current_url == wallpaper_url.spec() )
9200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (GURL(current_url).is_valid() && default_wallpaper_file_exists) {
9210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    VLOG(1)
9220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        << "ServicesCustomizationDocument::ApplyWallpaper() : reuse existing";
9230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    OnOEMWallpaperDownloaded(applying.Pass(), true, GURL(current_url));
9240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  } else {
9250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    VLOG(1)
9260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        << "ServicesCustomizationDocument::ApplyWallpaper() : start download";
9270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    StartOEMWallpaperDownload(wallpaper_url, applying.Pass());
9280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
9290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
9300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::OnOEMWallpaperDownloaded(
9320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying,
9330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    bool success,
9340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const GURL& wallpaper_url) {
9350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (success) {
9360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DCHECK(wallpaper_url.is_valid());
9370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    VLOG(1) << "Setting default wallpaper to '"
9390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            << GetCustomizedWallpaperDownloadedFileName().value() << "' ('"
9400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch            << wallpaper_url.spec() << "')";
9410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    WallpaperManager::Get()->SetCustomizedDefaultWallpaper(
9420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        wallpaper_url,
9430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        GetCustomizedWallpaperDownloadedFileName(),
9440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        GetCustomizedWallpaperCacheDir());
9450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
9460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  wallpaper_downloader_.reset();
9470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  applying->Finished(success);
9480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
9490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::ApplyingTaskStarted() {
9510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ++apply_tasks_started_;
9520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
9530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ServicesCustomizationDocument::ApplyingTaskFinished(bool success) {
9550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DCHECK_GT(apply_tasks_started_, apply_tasks_finished_);
9560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ++apply_tasks_finished_;
9570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  apply_tasks_success_ += success;
9590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (apply_tasks_started_ != apply_tasks_finished_)
9610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
9620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (apply_tasks_success_ == apply_tasks_finished_)
9640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    SetApplied(true);
9650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
9660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
968