| Index: chrome/browser/chromeos/customization_document.cc
|
| diff --git a/chrome/browser/chromeos/customization_document.cc b/chrome/browser/chromeos/customization_document.cc
|
| index f6edd9863bc1f445a48f1b0a2a82738d6365ddb0..07304d529ef01c3012ba616065d8d300a40c94fe 100644
|
| --- a/chrome/browser/chromeos/customization_document.cc
|
| +++ b/chrome/browser/chromeos/customization_document.cc
|
| @@ -14,6 +14,7 @@
|
| #include "base/logging.h"
|
| #include "base/memory/weak_ptr.h"
|
| #include "base/metrics/histogram.h"
|
| +#include "base/path_service.h"
|
| #include "base/prefs/pref_registry_simple.h"
|
| #include "base/prefs/pref_service.h"
|
| #include "base/strings/string_split.h"
|
| @@ -22,7 +23,9 @@
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/time/time.h"
|
| #include "chrome/browser/browser_process.h"
|
| +#include "chrome/browser/chromeos/customization_wallpaper_downloader.h"
|
| #include "chrome/browser/chromeos/extensions/default_app_order.h"
|
| +#include "chrome/browser/chromeos/login/wallpaper_manager.h"
|
| #include "chrome/browser/chromeos/login/wizard_controller.h"
|
| #include "chrome/browser/chromeos/net/delay_network_call.h"
|
| #include "chrome/browser/extensions/external_loader.h"
|
| @@ -30,7 +33,9 @@
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
|
| #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
|
| +#include "chrome/common/chrome_paths.h"
|
| #include "chrome/common/extensions/extension_constants.h"
|
| +#include "chrome/common/pref_names.h"
|
| #include "chromeos/network/network_state.h"
|
| #include "chromeos/network/network_state_handler.h"
|
| #include "chromeos/system/statistics_provider.h"
|
| @@ -68,6 +73,14 @@ const char kAcceptedManifestVersion[] = "1.0";
|
| const char kStartupCustomizationManifestPath[] =
|
| "/opt/oem/etc/startup_manifest.json";
|
|
|
| +// This is subdirectory relative to PathService(DIR_CHROMEOS_CUSTOM_WALLPAPERS),
|
| +// where downloaded (and resized) wallpaper is stored.
|
| +const char kCustomizationDefaultWallpaperDir[] = "customization";
|
| +
|
| +// The original downloaded image file is stored under this name.
|
| +const char kCustomizationDefaultWallpaperDownloadedFile[] =
|
| + "default_downloaded_wallpaper.bin";
|
| +
|
| // Name of local state option that tracks if services customization has been
|
| // applied.
|
| const char kServicesCustomizationAppliedPref[] = "ServicesCustomizationApplied";
|
| @@ -130,6 +143,12 @@ std::string GetLocaleSpecificStringImpl(
|
| return std::string();
|
| }
|
|
|
| +void CheckWallpaperCacheExists(const base::FilePath& path, bool* exists) {
|
| + DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
|
| + DCHECK(exists);
|
| + *exists = base::PathExists(path);
|
| +}
|
| +
|
| } // anonymous namespace
|
|
|
| // Template URL where to fetch OEM services customization manifest from.
|
| @@ -160,7 +179,7 @@ class ServicesCustomizationExternalLoader
|
| ServicesCustomizationDocument::GetInstance()->StartFetching();
|
| // In case of missing customization ID, SetCurrentApps will be called
|
| // synchronously from StartFetching and this function will be called
|
| - // recursively so we need to return to don't call LoadFinished twice.
|
| + // recursively so we need to return to avoid calling LoadFinished twice.
|
| // In case of async load it is safe to return empty list because this
|
| // provider didn't install any app yet so no app can be removed due to
|
| // returning empty list.
|
| @@ -341,20 +360,63 @@ std::string StartupCustomizationDocument::GetEULAPage(
|
|
|
| // ServicesCustomizationDocument implementation. -------------------------------
|
|
|
| +class ServicesCustomizationDocument::ApplyingTask {
|
| + public:
|
| + // Registers in ServicesCustomizationDocument;
|
| + explicit ApplyingTask(ServicesCustomizationDocument* document);
|
| +
|
| + // Do not automatically deregister as we might be called on invalid thread.
|
| + ~ApplyingTask();
|
| +
|
| + // Mark task finished and check for customization applied.
|
| + void Finished(bool success);
|
| +
|
| + private:
|
| + ServicesCustomizationDocument* document_;
|
| +
|
| + // This is error-checking flag to prevent destroying unfinished task
|
| + // or double finish.
|
| + bool engaged_;
|
| +};
|
| +
|
| +ServicesCustomizationDocument::ApplyingTask::ApplyingTask(
|
| + ServicesCustomizationDocument* document)
|
| + : document_(document), engaged_(true) {
|
| + document->ApplyingTaskStarted();
|
| +}
|
| +
|
| +ServicesCustomizationDocument::ApplyingTask::~ApplyingTask() {
|
| + DCHECK(!engaged_);
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::ApplyingTask::Finished(bool success) {
|
| + DCHECK(engaged_);
|
| + if (engaged_) {
|
| + engaged_ = false;
|
| + document_->ApplyingTaskFinished(success);
|
| + }
|
| +}
|
| +
|
| ServicesCustomizationDocument::ServicesCustomizationDocument()
|
| : CustomizationDocument(kAcceptedManifestVersion),
|
| num_retries_(0),
|
| fetch_started_(false),
|
| - network_delay_(base::TimeDelta::FromMilliseconds(
|
| - kDefaultNetworkRetryDelayMS)),
|
| + network_delay_(
|
| + base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)),
|
| + apply_tasks_started_(0),
|
| + apply_tasks_finished_(0),
|
| + apply_tasks_success_(0),
|
| weak_ptr_factory_(this) {
|
| }
|
|
|
| ServicesCustomizationDocument::ServicesCustomizationDocument(
|
| const std::string& manifest)
|
| : CustomizationDocument(kAcceptedManifestVersion),
|
| - network_delay_(base::TimeDelta::FromMilliseconds(
|
| - kDefaultNetworkRetryDelayMS)),
|
| + network_delay_(
|
| + base::TimeDelta::FromMilliseconds(kDefaultNetworkRetryDelayMS)),
|
| + apply_tasks_started_(0),
|
| + apply_tasks_finished_(0),
|
| + apply_tasks_success_(0),
|
| weak_ptr_factory_(this) {
|
| LoadManifestFromString(manifest);
|
| }
|
| @@ -374,6 +436,8 @@ ServicesCustomizationDocument* ServicesCustomizationDocument::GetInstance() {
|
| void ServicesCustomizationDocument::RegisterPrefs(
|
| PrefRegistrySimple* registry) {
|
| registry->RegisterBooleanPref(kServicesCustomizationAppliedPref, false);
|
| + registry->RegisterStringPref(prefs::kCustomizationDefaultWallpaperURL,
|
| + std::string());
|
| }
|
|
|
| // static
|
| @@ -402,6 +466,45 @@ void ServicesCustomizationDocument::SetApplied(bool val) {
|
| prefs->SetBoolean(kServicesCustomizationAppliedPref, val);
|
| }
|
|
|
| +// static
|
| +base::FilePath ServicesCustomizationDocument::GetCustomizedWallpaperCacheDir() {
|
| + base::FilePath custom_wallpaper_dir;
|
| + if (!PathService::Get(chrome::DIR_CHROMEOS_CUSTOM_WALLPAPERS,
|
| + &custom_wallpaper_dir)) {
|
| + LOG(DFATAL) << "Unable to get custom wallpaper dir.";
|
| + return base::FilePath();
|
| + }
|
| + return custom_wallpaper_dir.Append(kCustomizationDefaultWallpaperDir);
|
| +}
|
| +
|
| +// static
|
| +base::FilePath
|
| +ServicesCustomizationDocument::GetCustomizedWallpaperDownloadedFileName() {
|
| + const base::FilePath dir = GetCustomizedWallpaperCacheDir();
|
| + if (dir.empty()) {
|
| + NOTREACHED();
|
| + return dir;
|
| + }
|
| + return dir.Append(kCustomizationDefaultWallpaperDownloadedFile);
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::EnsureCustomizationApplied() {
|
| + if (WasOOBECustomizationApplied())
|
| + return;
|
| +
|
| + // When customization manifest is fetched, applying will start automatically.
|
| + if (IsReady())
|
| + return;
|
| +
|
| + StartFetching();
|
| +}
|
| +
|
| +base::Closure
|
| +ServicesCustomizationDocument::EnsureCustomizationAppliedClosure() {
|
| + return base::Bind(&ServicesCustomizationDocument::EnsureCustomizationApplied,
|
| + weak_ptr_factory_.GetWeakPtr());
|
| +}
|
| +
|
| void ServicesCustomizationDocument::StartFetching() {
|
| if (IsReady() || fetch_started_)
|
| return;
|
| @@ -416,7 +519,7 @@ void ServicesCustomizationDocument::StartFetching() {
|
| url_ = GURL(base::StringPrintf(
|
| kManifestUrl, StringToLowerASCII(customization_id).c_str()));
|
| } else {
|
| - // There is no customization ID in VPD remember that.
|
| + // Remember that there is no customization ID in VPD.
|
| OnCustomizationNotFound();
|
| return;
|
| }
|
| @@ -493,7 +596,7 @@ bool ServicesCustomizationDocument::LoadManifestFromString(
|
| }
|
|
|
| void ServicesCustomizationDocument::OnManifestLoaded() {
|
| - if (!ServicesCustomizationDocument::WasOOBECustomizationApplied())
|
| + if (!WasOOBECustomizationApplied())
|
| ApplyOOBECustomization();
|
|
|
| scoped_ptr<base::DictionaryValue> prefs =
|
| @@ -545,18 +648,24 @@ void ServicesCustomizationDocument::OnURLFetchComplete(
|
| }
|
|
|
| bool ServicesCustomizationDocument::ApplyOOBECustomization() {
|
| - // TODO(dpolukhin): apply default wallpaper, crbug.com/348136.
|
| - SetApplied(true);
|
| - return true;
|
| + if (apply_tasks_started_)
|
| + return false;
|
| +
|
| + CheckAndApplyWallpaper();
|
| + return false;
|
| }
|
|
|
| -GURL ServicesCustomizationDocument::GetDefaultWallpaperUrl() const {
|
| +bool ServicesCustomizationDocument::GetDefaultWallpaperUrl(
|
| + GURL* out_url) const {
|
| if (!IsReady())
|
| - return GURL();
|
| + return false;
|
|
|
| std::string url;
|
| - root_->GetString(kDefaultWallpaperAttr, &url);
|
| - return GURL(url);
|
| + if (!root_->GetString(kDefaultWallpaperAttr, &url))
|
| + return false;
|
| +
|
| + *out_url = GURL(url);
|
| + return true;
|
| }
|
|
|
| bool ServicesCustomizationDocument::GetDefaultApps(
|
| @@ -689,4 +798,172 @@ void ServicesCustomizationDocument::ShutdownForTesting() {
|
| g_test_services_customization_document = NULL;
|
| }
|
|
|
| +void ServicesCustomizationDocument::StartOEMWallpaperDownload(
|
| + const GURL& wallpaper_url,
|
| + scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying) {
|
| + DCHECK(wallpaper_url.is_valid());
|
| +
|
| + const base::FilePath dir = GetCustomizedWallpaperCacheDir();
|
| + const base::FilePath file = GetCustomizedWallpaperDownloadedFileName();
|
| + if (dir.empty() || file.empty()) {
|
| + NOTREACHED();
|
| + applying->Finished(false);
|
| + return;
|
| + }
|
| +
|
| + wallpaper_downloader_.reset(new CustomizationWallpaperDownloader(
|
| + g_browser_process->system_request_context(),
|
| + wallpaper_url,
|
| + dir,
|
| + file,
|
| + base::Bind(&ServicesCustomizationDocument::OnOEMWallpaperDownloaded,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + base::Passed(applying.Pass()))));
|
| +
|
| + wallpaper_downloader_->Start();
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::CheckAndApplyWallpaper() {
|
| + if (wallpaper_downloader_.get()) {
|
| + VLOG(1) << "CheckAndApplyWallpaper(): download has already started.";
|
| + return;
|
| + }
|
| + scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying(
|
| + new ServicesCustomizationDocument::ApplyingTask(this));
|
| +
|
| + GURL wallpaper_url;
|
| + if (!GetDefaultWallpaperUrl(&wallpaper_url)) {
|
| + PrefService* pref_service = g_browser_process->local_state();
|
| + std::string current_url =
|
| + pref_service->GetString(prefs::kCustomizationDefaultWallpaperURL);
|
| + if (!current_url.empty()) {
|
| + VLOG(1) << "ServicesCustomizationDocument::CheckAndApplyWallpaper() : "
|
| + << "No wallpaper URL attribute in customization document, "
|
| + << "but current value is non-empty: '" << current_url
|
| + << "'. Ignored.";
|
| + }
|
| + applying->Finished(true);
|
| + return;
|
| + }
|
| +
|
| + // Should fail if this ever happens in tests.
|
| + DCHECK(wallpaper_url.is_valid());
|
| + if (!wallpaper_url.is_valid()) {
|
| + if (!wallpaper_url.is_empty()) {
|
| + LOG(WARNING) << "Invalid Customized Wallpaper URL '"
|
| + << wallpaper_url.spec() << "'.";
|
| + }
|
| + applying->Finished(false);
|
| + return;
|
| + }
|
| +
|
| + scoped_ptr<bool> exists(new bool(false));
|
| +
|
| + base::Closure check_file_exists =
|
| + base::Bind(&CheckWallpaperCacheExists,
|
| + GetCustomizedWallpaperDownloadedFileName(),
|
| + base::Unretained(exists.get()));
|
| + base::Closure on_checked_closure =
|
| + base::Bind(&ServicesCustomizationDocument::OnCheckedWallpaperCacheExists,
|
| + weak_ptr_factory_.GetWeakPtr(),
|
| + base::Passed(exists.Pass()),
|
| + base::Passed(applying.Pass()));
|
| + if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
|
| + FROM_HERE, check_file_exists, on_checked_closure)) {
|
| + LOG(WARNING) << "Failed to start check Wallpaper cache exists.";
|
| + }
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::OnCheckedWallpaperCacheExists(
|
| + scoped_ptr<bool> exists,
|
| + scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying) {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
|
| + DCHECK(exists);
|
| + DCHECK(applying);
|
| +
|
| + ApplyWallpaper(*exists, applying.Pass());
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::ApplyWallpaper(
|
| + bool default_wallpaper_file_exists,
|
| + scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying) {
|
| + GURL wallpaper_url;
|
| + const bool wallpaper_url_present = GetDefaultWallpaperUrl(&wallpaper_url);
|
| +
|
| + PrefService* pref_service = g_browser_process->local_state();
|
| +
|
| + std::string current_url =
|
| + pref_service->GetString(prefs::kCustomizationDefaultWallpaperURL);
|
| + if (current_url != wallpaper_url.spec()) {
|
| + if (wallpaper_url_present) {
|
| + VLOG(1) << "ServicesCustomizationDocument::ApplyWallpaper() : "
|
| + << "Wallpaper URL in customization document '"
|
| + << wallpaper_url.spec() << "' differs from current '"
|
| + << current_url << "'."
|
| + << (GURL(current_url).is_valid() && default_wallpaper_file_exists
|
| + ? " Ignored."
|
| + : " Will refetch.");
|
| + } else {
|
| + VLOG(1) << "ServicesCustomizationDocument::ApplyWallpaper() : "
|
| + << "No wallpaper URL attribute in customization document, "
|
| + << "but current value is non-empty: '" << current_url
|
| + << "'. Ignored.";
|
| + }
|
| + }
|
| + if (!wallpaper_url_present) {
|
| + applying->Finished(true);
|
| + return;
|
| + }
|
| +
|
| + DCHECK(wallpaper_url.is_valid());
|
| +
|
| + // Never update system-wide wallpaper (i.e. do not check
|
| + // current_url == wallpaper_url.spec() )
|
| + if (GURL(current_url).is_valid() && default_wallpaper_file_exists) {
|
| + VLOG(1)
|
| + << "ServicesCustomizationDocument::ApplyWallpaper() : reuse existing";
|
| + OnOEMWallpaperDownloaded(applying.Pass(), true, GURL(current_url));
|
| + } else {
|
| + VLOG(1)
|
| + << "ServicesCustomizationDocument::ApplyWallpaper() : start download";
|
| + StartOEMWallpaperDownload(wallpaper_url, applying.Pass());
|
| + }
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::OnOEMWallpaperDownloaded(
|
| + scoped_ptr<ServicesCustomizationDocument::ApplyingTask> applying,
|
| + bool success,
|
| + const GURL& wallpaper_url) {
|
| + if (success) {
|
| + DCHECK(wallpaper_url.is_valid());
|
| +
|
| + VLOG(1) << "Setting default wallpaper to '"
|
| + << GetCustomizedWallpaperDownloadedFileName().value() << "' ('"
|
| + << wallpaper_url.spec() << "')";
|
| + WallpaperManager::Get()->SetCustomizedDefaultWallpaper(
|
| + wallpaper_url,
|
| + GetCustomizedWallpaperDownloadedFileName(),
|
| + GetCustomizedWallpaperCacheDir());
|
| + }
|
| + wallpaper_downloader_.reset();
|
| + applying->Finished(success);
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::ApplyingTaskStarted() {
|
| + ++apply_tasks_started_;
|
| +}
|
| +
|
| +void ServicesCustomizationDocument::ApplyingTaskFinished(bool success) {
|
| + DCHECK_GT(apply_tasks_started_, apply_tasks_finished_);
|
| + ++apply_tasks_finished_;
|
| +
|
| + apply_tasks_success_ += success;
|
| +
|
| + if (apply_tasks_started_ != apply_tasks_finished_)
|
| + return;
|
| +
|
| + if (apply_tasks_success_ == apply_tasks_finished_)
|
| + SetApplied(true);
|
| +}
|
| +
|
| } // namespace chromeos
|
|
|