diff options
author | zmo@google.com <zmo@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-18 17:54:48 +0000 |
---|---|---|
committer | zmo@google.com <zmo@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-18 17:54:48 +0000 |
commit | 92c699d5a6b73316cb9fd7f44ef9753038b02846 (patch) | |
tree | d252157e33f107736619be082422fd753a3956e1 /chrome | |
parent | c63248d4041385f117c09a47cee79415396193c5 (diff) | |
download | chromium_src-92c699d5a6b73316cb9fd7f44ef9753038b02846.zip chromium_src-92c699d5a6b73316cb9fd7f44ef9753038b02846.tar.gz chromium_src-92c699d5a6b73316cb9fd7f44ef9753038b02846.tar.bz2 |
Refactor WebResourceService class, making it more generic. Move all the promo-related code into a new PromoResourceService class that inherits WebResourceService.
This refactoring will allow us to re-use WebResourceService class for GPU Blacklist updates purpose.
This CL tries to minimize the code change and adds no new logic.
BUG=68802
TEST=unittest,promo functions working fine as before.
Review URL: http://codereview.chromium.org/6542003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@75403 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
19 files changed, 651 insertions, 545 deletions
diff --git a/chrome/browser/dom_ui/new_tab_ui.cc b/chrome/browser/dom_ui/new_tab_ui.cc index 1cc4f55..9439871 100644 --- a/chrome/browser/dom_ui/new_tab_ui.cc +++ b/chrome/browser/dom_ui/new_tab_ui.cc @@ -273,7 +273,7 @@ void NewTabPageClosePromoHandler::HandleClosePromo( const ListValue* args) { web_ui_->GetProfile()->GetPrefs()->SetBoolean(prefs::kNTPPromoClosed, true); NotificationService* service = NotificationService::current(); - service->Notify(NotificationType::WEB_RESOURCE_STATE_CHANGED, + service->Notify(NotificationType::PROMO_RESOURCE_STATE_CHANGED, Source<NewTabPageClosePromoHandler>(this), NotificationService::NoDetails()); } diff --git a/chrome/browser/dom_ui/ntp_resource_cache.cc b/chrome/browser/dom_ui/ntp_resource_cache.cc index 3df1391..29fcbe4 100644 --- a/chrome/browser/dom_ui/ntp_resource_cache.cc +++ b/chrome/browser/dom_ui/ntp_resource_cache.cc @@ -22,7 +22,7 @@ #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/themes/browser_theme_provider.h" -#include "chrome/browser/web_resource/web_resource_service.h" +#include "chrome/browser/web_resource/promo_resource_service.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" @@ -149,7 +149,7 @@ bool InDateRange(double begin, double end) { NTPResourceCache::NTPResourceCache(Profile* profile) : profile_(profile) { registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, NotificationService::AllSources()); - registrar_.Add(this, NotificationType::WEB_RESOURCE_STATE_CHANGED, + registrar_.Add(this, NotificationType::PROMO_RESOURCE_STATE_CHANGED, NotificationService::AllSources()); // Watch for pref changes that cause us to need to invalidate the HTML cache. @@ -190,7 +190,7 @@ void NTPResourceCache::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { // Invalidate the cache. if (NotificationType::BROWSER_THEME_CHANGED == type || - NotificationType::WEB_RESOURCE_STATE_CHANGED == type) { + NotificationType::PROMO_RESOURCE_STATE_CHANGED == type) { new_tab_incognito_html_ = NULL; new_tab_html_ = NULL; new_tab_incognito_css_ = NULL; @@ -380,7 +380,7 @@ void NTPResourceCache::CreateNewTabHTML() { if (profile_->GetPrefs()->FindPreference(prefs::kNTPPromoStart) && profile_->GetPrefs()->FindPreference(prefs::kNTPPromoEnd) && profile_->GetPrefs()->FindPreference(prefs::kNTPPromoLine) && - WebResourceServiceUtil::CanShowPromo(profile_)) { + PromoResourceServiceUtil::CanShowPromo(profile_)) { localized_strings.SetString("serverpromo", InDateRange(profile_->GetPrefs()->GetDouble(prefs::kNTPPromoStart), profile_->GetPrefs()->GetDouble(prefs::kNTPPromoEnd)) ? diff --git a/chrome/browser/dom_ui/tips_handler.cc b/chrome/browser/dom_ui/tips_handler.cc index 7f7b565..a636682 100644 --- a/chrome/browser/dom_ui/tips_handler.cc +++ b/chrome/browser/dom_ui/tips_handler.cc @@ -10,8 +10,9 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/web_resource/web_resource_service.h" +#include "chrome/browser/web_resource/promo_resource_service.h" #include "chrome/common/pref_names.h" #include "chrome/common/web_resource/web_resource_unpacker.h" #include "chrome/common/url_constants.h" @@ -22,7 +23,7 @@ WebUIMessageHandler* TipsHandler::Attach(WebUI* web_ui) { web_ui_ = web_ui; tips_cache_ = web_ui_->GetProfile()->GetPrefs()-> - GetMutableDictionary(prefs::kNTPWebResourceCache); + GetMutableDictionary(prefs::kNTPPromoResourceCache); return WebUIMessageHandler::Attach(web_ui); } @@ -58,9 +59,9 @@ void TipsHandler::HandleGetTips(const ListValue* args) { if (tips_cache_ != NULL && !tips_cache_->empty()) { if (tips_cache_->GetInteger( - WebResourceService::kCurrentTipPrefName, ¤t_tip_index) && + PromoResourceService::kCurrentTipPrefName, ¤t_tip_index) && tips_cache_->GetList( - WebResourceService::kTipCachePrefName, &wr_list) && + PromoResourceService::kTipCachePrefName, &wr_list) && wr_list && wr_list->GetSize() > 0) { if (wr_list->GetSize() <= static_cast<size_t>(current_tip_index)) { // Check to see whether the home page is set to NTP; if not, add tip @@ -91,7 +92,7 @@ void TipsHandler::SendTip(const std::string& tip, const std::string& tip_type, DictionaryValue* tip_dict = new DictionaryValue(); tip_dict->SetString(tip_type, tip); list_value.Append(tip_dict); - tips_cache_->SetInteger(WebResourceService::kCurrentTipPrefName, + tips_cache_->SetInteger(PromoResourceService::kCurrentTipPrefName, tip_index); // Send list of web resource items back out to the DOM. web_ui_->CallJavascriptFunction(L"tips", list_value); @@ -99,9 +100,9 @@ void TipsHandler::SendTip(const std::string& tip, const std::string& tip_type, // static void TipsHandler::RegisterUserPrefs(PrefService* prefs) { - prefs->RegisterDictionaryPref(prefs::kNTPWebResourceCache); - prefs->RegisterStringPref(prefs::kNTPWebResourceServer, - WebResourceService::kDefaultWebResourceServer); + prefs->RegisterDictionaryPref(prefs::kNTPPromoResourceCache); + prefs->RegisterStringPref(prefs::kNTPPromoResourceServer, + PromoResourceService::kDefaultPromoResourceServer); } bool TipsHandler::IsValidURL(const std::wstring& url_string) { diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc index 0d96782..9ed51ec 100644 --- a/chrome/browser/profiles/profile.cc +++ b/chrome/browser/profiles/profile.cc @@ -561,7 +561,7 @@ class OffTheRecordProfileImpl : public Profile, NOTREACHED(); } - virtual void InitWebResources() { + virtual void InitPromoResources() { NOTREACHED(); } diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 61db6b8..b981575 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h @@ -106,7 +106,7 @@ class VisitedLinkEventListener; class VisitedLinkMaster; class WebDataService; class WebKitContext; -class WebResourceService; +class PromoResourceService; typedef intptr_t ProfileId; @@ -478,8 +478,8 @@ class Profile { virtual void InitExtensions() = 0; - // Start up service that gathers data from a web resource feed. - virtual void InitWebResources() = 0; + // Start up service that gathers data from a promo resource feed. + virtual void InitPromoResources() = 0; // Returns the new tab page resource cache. virtual NTPResourceCache* GetNTPResourceCache() = 0; diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 1505d22..d8e1fd6 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -82,7 +82,7 @@ #include "chrome/browser/user_style_sheet_watcher.h" #include "chrome/browser/visitedlink/visitedlink_event_listener.h" #include "chrome/browser/visitedlink/visitedlink_master.h" -#include "chrome/browser/web_resource/web_resource_service.h" +#include "chrome/browser/web_resource/promo_resource_service.h" #include "chrome/browser/webdata/web_data_service.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -481,12 +481,12 @@ void ProfileImpl::InstallDefaultApps() { } } -void ProfileImpl::InitWebResources() { - if (web_resource_service_) +void ProfileImpl::InitPromoResources() { + if (promo_resource_service_) return; - web_resource_service_ = new WebResourceService(this); - web_resource_service_->StartAfterDelay(); + promo_resource_service_ = new PromoResourceService(this); + promo_resource_service_->StartAfterDelay(); } NTPResourceCache* ProfileImpl::GetNTPResourceCache() { diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index 0934dbb..92086ed 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h @@ -115,7 +115,7 @@ class ProfileImpl : public Profile, virtual StatusTray* GetStatusTray(); virtual void MarkAsCleanShutdown(); virtual void InitExtensions(); - virtual void InitWebResources(); + virtual void InitPromoResources(); virtual NTPResourceCache* GetNTPResourceCache(); virtual FilePath last_selected_directory(); virtual void set_last_selected_directory(const FilePath& path); @@ -209,7 +209,7 @@ class ProfileImpl : public Profile, scoped_ptr<TemplateURLFetcher> template_url_fetcher_; scoped_ptr<TemplateURLModel> template_url_model_; scoped_ptr<BookmarkModel> bookmark_bar_model_; - scoped_refptr<WebResourceService> web_resource_service_; + scoped_refptr<PromoResourceService> promo_resource_service_; scoped_ptr<NTPResourceCache> ntp_resource_cache_; scoped_ptr<TokenService> token_service_; diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index 83772f1..41406a3 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -179,7 +179,7 @@ bool ProfileManager::AddProfile(Profile* profile, bool init_extensions) { profile->InitExtensions(); const CommandLine& command_line = *CommandLine::ForCurrentProcess(); if (!command_line.HasSwitch(switches::kDisableWebResources)) - profile->InitWebResources(); + profile->InitPromoResources(); return true; } diff --git a/chrome/browser/web_resource/promo_resource_service.cc b/chrome/browser/web_resource/promo_resource_service.cc new file mode 100644 index 0000000..f694563 --- /dev/null +++ b/chrome/browser/web_resource/promo_resource_service.cc @@ -0,0 +1,358 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_resource/promo_resource_service.h" + +#include "base/string_number_conversions.h" +#include "base/threading/thread_restrictions.h" +#include "base/time.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/platform_util.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sync/sync_ui_util.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" +#include "chrome/common/pref_names.h" + +namespace { + +// Delay on first fetch so we don't interfere with startup. +static const int kStartResourceFetchDelay = 5000; + +// Delay between calls to update the cache (48 hours). +static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000; + +// Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order +// to be able to roll out promos slowly, or display different promos to +// different groups. +static const int kNTPPromoGroupSize = 16; + +// Maximum number of hours for each time slice (4 weeks). +static const int kMaxTimeSliceHours = 24 * 7 * 4; + +// Used to determine which build type should be shown a given promo. +enum BuildType { + DEV_BUILD = 1, + BETA_BUILD = 1 << 1, + STABLE_BUILD = 1 << 2, +}; + +} // namespace + +const char* PromoResourceService::kCurrentTipPrefName = "current_tip"; +const char* PromoResourceService::kTipCachePrefName = "tips"; + +// Server for dynamically loaded NTP HTML elements. TODO(mirandac): append +// locale for future usage, when we're serving localizable strings. +const char* PromoResourceService::kDefaultPromoResourceServer = + "https://www.google.com/support/chrome/bin/topic/1142433/inproduct?hl="; + +PromoResourceService::PromoResourceService(Profile* profile) + : WebResourceService(profile, + PromoResourceService::kDefaultPromoResourceServer, + true, // append locale to URL + NotificationType::PROMO_RESOURCE_STATE_CHANGED, + prefs::kNTPPromoResourceCacheUpdate, + kStartResourceFetchDelay, + kCacheUpdateDelay), + web_resource_cache_(NULL) { + Init(); +} + +PromoResourceService::~PromoResourceService() { } + +void PromoResourceService::Init() { + prefs_->RegisterStringPref(prefs::kNTPPromoResourceCacheUpdate, "0"); + prefs_->RegisterDoublePref(prefs::kNTPCustomLogoStart, 0); + prefs_->RegisterDoublePref(prefs::kNTPCustomLogoEnd, 0); + prefs_->RegisterDoublePref(prefs::kNTPPromoStart, 0); + prefs_->RegisterDoublePref(prefs::kNTPPromoEnd, 0); + prefs_->RegisterStringPref(prefs::kNTPPromoLine, std::string()); + prefs_->RegisterBooleanPref(prefs::kNTPPromoClosed, false); + prefs_->RegisterIntegerPref(prefs::kNTPPromoGroup, -1); + prefs_->RegisterIntegerPref(prefs::kNTPPromoBuild, + DEV_BUILD | BETA_BUILD | STABLE_BUILD); + prefs_->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, 0); + + // If the promo start is in the future, set a notification task to invalidate + // the NTP cache at the time of the promo start. + double promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); + double promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); + ScheduleNotification(promo_start, promo_end); +} + +void PromoResourceService::Unpack(const DictionaryValue& parsed_json) { + UnpackLogoSignal(parsed_json); + UnpackPromoSignal(parsed_json); +} + +void PromoResourceService::ScheduleNotification(double promo_start, + double promo_end) { + if (promo_start > 0 && promo_end > 0) { + int64 ms_until_start = + static_cast<int64>((base::Time::FromDoubleT( + promo_start) - base::Time::Now()).InMilliseconds()); + int64 ms_until_end = + static_cast<int64>((base::Time::FromDoubleT( + promo_end) - base::Time::Now()).InMilliseconds()); + if (ms_until_start > 0) + PostNotification(ms_until_start); + if (ms_until_end > 0) { + PostNotification(ms_until_end); + if (ms_until_start <= 0) { + // Notify immediately if time is between start and end. + PostNotification(0); + } + } + } +} + +void PromoResourceService::UnpackTips(const DictionaryValue& parsed_json) { + // Get dictionary of cached preferences. + web_resource_cache_ = + prefs_->GetMutableDictionary(prefs::kNTPPromoResourceCache); + + // The list of individual tips. + ListValue* tip_holder = new ListValue(); + web_resource_cache_->Set(PromoResourceService::kTipCachePrefName, tip_holder); + + DictionaryValue* topic_dict; + ListValue* answer_list; + std::string topic_id; + std::string answer_id; + std::string inproduct; + int tip_counter = 0; + + if (parsed_json.GetDictionary("topic", &topic_dict)) { + if (topic_dict->GetString("topic_id", &topic_id)) + web_resource_cache_->SetString("topic_id", topic_id); + if (topic_dict->GetList("answers", &answer_list)) { + for (ListValue::const_iterator tip_iter = answer_list->begin(); + tip_iter != answer_list->end(); ++tip_iter) { + if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) + continue; + DictionaryValue* a_dic = + static_cast<DictionaryValue*>(*tip_iter); + if (a_dic->GetString("inproduct", &inproduct)) { + tip_holder->Append(Value::CreateStringValue(inproduct)); + } + tip_counter++; + } + // If tips exist, set current index to 0. + if (!inproduct.empty()) { + web_resource_cache_->SetInteger( + PromoResourceService::kCurrentTipPrefName, 0); + } + } + } +} + +void PromoResourceService::UnpackPromoSignal( + const DictionaryValue& parsed_json) { + DictionaryValue* topic_dict; + ListValue* answer_list; + double old_promo_start = 0; + double old_promo_end = 0; + double promo_start = 0; + double promo_end = 0; + + // Check for preexisting start and end values. + if (prefs_->HasPrefPath(prefs::kNTPPromoStart) && + prefs_->HasPrefPath(prefs::kNTPPromoEnd)) { + old_promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); + old_promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); + } + + // Check for newly received start and end values. + if (parsed_json.GetDictionary("topic", &topic_dict)) { + if (topic_dict->GetList("answers", &answer_list)) { + std::string promo_start_string = ""; + std::string promo_end_string = ""; + std::string promo_string = ""; + std::string promo_build = ""; + int promo_build_type = 0; + int time_slice_hrs = 0; + for (ListValue::const_iterator tip_iter = answer_list->begin(); + tip_iter != answer_list->end(); ++tip_iter) { + if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) + continue; + DictionaryValue* a_dic = + static_cast<DictionaryValue*>(*tip_iter); + std::string promo_signal; + if (a_dic->GetString("name", &promo_signal)) { + if (promo_signal == "promo_start") { + a_dic->GetString("question", &promo_build); + size_t split = promo_build.find(":"); + if (split != std::string::npos && + base::StringToInt(promo_build.substr(0, split), + &promo_build_type) && + base::StringToInt(promo_build.substr(split+1), + &time_slice_hrs) && + promo_build_type >= 0 && + promo_build_type <= (DEV_BUILD | BETA_BUILD | STABLE_BUILD) && + time_slice_hrs >= 0 && + time_slice_hrs <= kMaxTimeSliceHours) { + prefs_->SetInteger(prefs::kNTPPromoBuild, promo_build_type); + prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, + time_slice_hrs); + } else { + // If no time data or bad time data are set, show promo on all + // builds with no time slicing. + prefs_->SetInteger(prefs::kNTPPromoBuild, + DEV_BUILD | BETA_BUILD | STABLE_BUILD); + prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, 0); + } + a_dic->GetString("inproduct", &promo_start_string); + a_dic->GetString("tooltip", &promo_string); + prefs_->SetString(prefs::kNTPPromoLine, promo_string); + srand(static_cast<uint32>(time(NULL))); + prefs_->SetInteger(prefs::kNTPPromoGroup, + rand() % kNTPPromoGroupSize); + } else if (promo_signal == "promo_end") { + a_dic->GetString("inproduct", &promo_end_string); + } + } + } + if (!promo_start_string.empty() && + promo_start_string.length() > 0 && + !promo_end_string.empty() && + promo_end_string.length() > 0) { + base::Time start_time; + base::Time end_time; + if (base::Time::FromString( + ASCIIToWide(promo_start_string).c_str(), &start_time) && + base::Time::FromString( + ASCIIToWide(promo_end_string).c_str(), &end_time)) { + // Add group time slice, adjusted from hours to seconds. + promo_start = start_time.ToDoubleT() + + (prefs_->FindPreference(prefs::kNTPPromoGroup) ? + prefs_->GetInteger(prefs::kNTPPromoGroup) * + time_slice_hrs * 60 * 60 : 0); + promo_end = end_time.ToDoubleT(); + } + } + } + } + + // If start or end times have changed, trigger a new web resource + // notification, so that the logo on the NTP is updated. This check is + // outside the reading of the web resource data, because the absence of + // dates counts as a triggering change if there were dates before. + // Also reset the promo closed preference, to signal a new promo. + if (!(old_promo_start == promo_start) || + !(old_promo_end == promo_end)) { + prefs_->SetDouble(prefs::kNTPPromoStart, promo_start); + prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end); + prefs_->SetBoolean(prefs::kNTPPromoClosed, false); + ScheduleNotification(promo_start, promo_end); + } +} + +void PromoResourceService::UnpackLogoSignal( + const DictionaryValue& parsed_json) { + DictionaryValue* topic_dict; + ListValue* answer_list; + double old_logo_start = 0; + double old_logo_end = 0; + double logo_start = 0; + double logo_end = 0; + + // Check for preexisting start and end values. + if (prefs_->HasPrefPath(prefs::kNTPCustomLogoStart) && + prefs_->HasPrefPath(prefs::kNTPCustomLogoEnd)) { + old_logo_start = prefs_->GetDouble(prefs::kNTPCustomLogoStart); + old_logo_end = prefs_->GetDouble(prefs::kNTPCustomLogoEnd); + } + + // Check for newly received start and end values. + if (parsed_json.GetDictionary("topic", &topic_dict)) { + if (topic_dict->GetList("answers", &answer_list)) { + std::string logo_start_string = ""; + std::string logo_end_string = ""; + for (ListValue::const_iterator tip_iter = answer_list->begin(); + tip_iter != answer_list->end(); ++tip_iter) { + if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) + continue; + DictionaryValue* a_dic = + static_cast<DictionaryValue*>(*tip_iter); + std::string logo_signal; + if (a_dic->GetString("name", &logo_signal)) { + if (logo_signal == "custom_logo_start") { + a_dic->GetString("inproduct", &logo_start_string); + } else if (logo_signal == "custom_logo_end") { + a_dic->GetString("inproduct", &logo_end_string); + } + } + } + if (!logo_start_string.empty() && + logo_start_string.length() > 0 && + !logo_end_string.empty() && + logo_end_string.length() > 0) { + base::Time start_time; + base::Time end_time; + if (base::Time::FromString( + ASCIIToWide(logo_start_string).c_str(), &start_time) && + base::Time::FromString( + ASCIIToWide(logo_end_string).c_str(), &end_time)) { + logo_start = start_time.ToDoubleT(); + logo_end = end_time.ToDoubleT(); + } + } + } + } + + // If logo start or end times have changed, trigger a new web resource + // notification, so that the logo on the NTP is updated. This check is + // outside the reading of the web resource data, because the absence of + // dates counts as a triggering change if there were dates before. + if (!(old_logo_start == logo_start) || + !(old_logo_end == logo_end)) { + prefs_->SetDouble(prefs::kNTPCustomLogoStart, logo_start); + prefs_->SetDouble(prefs::kNTPCustomLogoEnd, logo_end); + NotificationService* service = NotificationService::current(); + service->Notify(NotificationType::PROMO_RESOURCE_STATE_CHANGED, + Source<WebResourceService>(this), + NotificationService::NoDetails()); + } +} + +namespace PromoResourceServiceUtil { + +bool CanShowPromo(Profile* profile) { + bool promo_closed = false; + PrefService* prefs = profile->GetPrefs(); + if (prefs->HasPrefPath(prefs::kNTPPromoClosed)) + promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed); + + // Only show if not synced. + bool is_synced = + (profile->HasProfileSyncService() && + sync_ui_util::GetStatus( + profile->GetProfileSyncService()) == sync_ui_util::SYNCED); + + // GetVersionStringModifier hits the registry. See http://crbug.com/70898. + base::ThreadRestrictions::ScopedAllowIO allow_io; + const std::string channel = platform_util::GetVersionStringModifier(); + bool is_promo_build = false; + if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) { + int builds_allowed = prefs->GetInteger(prefs::kNTPPromoBuild); + if (channel == "dev") { + is_promo_build = (DEV_BUILD & builds_allowed) != 0; + } else if (channel == "beta") { + is_promo_build = (BETA_BUILD & builds_allowed) != 0; + } else if (channel == "stable") { + is_promo_build = (STABLE_BUILD & builds_allowed) != 0; + } else { + is_promo_build = true; + } + } + + return !promo_closed && !is_synced && is_promo_build; +} + +} // namespace PromoResourceServiceUtil + diff --git a/chrome/browser/web_resource/promo_resource_service.h b/chrome/browser/web_resource/promo_resource_service.h new file mode 100644 index 0000000..5f833d6 --- /dev/null +++ b/chrome/browser/web_resource/promo_resource_service.h @@ -0,0 +1,149 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_RESOURCE_PROMO_RESOURCE_SERVICE_H_ +#define CHROME_BROWSER_WEB_RESOURCE_PROMO_RESOURCE_SERVICE_H_ +#pragma once + +#include "chrome/browser/web_resource/web_resource_service.h" + +namespace PromoResourceServiceUtil { + +// Certain promotions should only be shown to certain classes of users. This +// function will change to reflect each kind of promotion. +bool CanShowPromo(Profile* profile); + +} // namespace PromoResourceServiceUtil + +// A PromoResourceService fetches data from a web resource server to be used to +// dynamically change the appearance of the New Tab Page. For example, it has +// been used to fetch "tips" to be displayed on the NTP, or to display +// promotional messages to certain groups of Chrome users. +// +// TODO(mirandac): Arrange for a server to be set up specifically for promo +// messages, which have until now been piggybacked onto the old tips server +// structure. (see http://crbug.com/70634 for details.) +class PromoResourceService + : public WebResourceService { + public: + explicit PromoResourceService(Profile* profile); + + // Unpack the web resource as a set of tips. Expects json in the form of: + // { + // "lang": "en", + // "topic": { + // "topid_id": "24013", + // "topics": [ + // ], + // "answers": [ + // { + // "answer_id": "18625", + // "inproduct": "Text here will be shown as a tip", + // }, + // ... + // ] + // } + // } + // + // Public for unit testing. + void UnpackTips(const DictionaryValue& parsed_json); + + // Unpack the web resource as a custom promo signal. Expects a start and end + // signal, with the promo to be shown in the tooltip of the start signal + // field. Delivery will be in json in the form of: + // { + // "topic": { + // "answers": [ + // { + // "answer_id": "1067976", + // "name": "promo_start", + // "question": "1:24", + // "tooltip": + // "Click \u003ca href=http://www.google.com\u003ehere\u003c/a\u003e!", + // "inproduct": "10/8/09 12:00", + // "inproduct_target": null + // }, + // { + // "answer_id": "1067976", + // "name": "promo_end", + // "question": "", + // "tooltip": "", + // "inproduct": "10/8/11 12:00", + // "inproduct_target": null + // }, + // ... + // ] + // } + // } + // + // Because the promo signal data is piggybacked onto the tip server, the + // values don't exactly correspond with the field names: + // + // For "promo_start" or "promo_end", the date to start or stop showing the + // promotional line is given by the "inproduct" line. + // For "promo_start", the promotional line itself is given in the "tooltip" + // field. The "question" field gives the type of builds that should be shown + // this promo (see the BuildType enum in web_resource_service.cc) and the + // number of hours that each promo group should see it, separated by ":". + // For example, "7:24" would indicate that all builds should see the promo, + // and each group should see it for 24 hours. + // + // Public for unit testing. + void UnpackPromoSignal(const DictionaryValue& parsed_json); + + // Unpack the promo resource as a custom logo signal. Expects a start and end + // signal. Delivery will be in json in the form of: + // { + // "topic": { + // "answers": [ + // { + // "answer_id": "107366", + // "name": "custom_logo_start", + // "question": "", + // "tooltip": "", + // "inproduct": "10/8/09 12:00", + // "inproduct_target": null + // }, + // { + // "answer_id": "107366", + // "name": "custom_logo_end", + // "question": "", + // "tooltip": "", + // "inproduct": "10/8/09 12:00", + // "inproduct_target": null + // }, + // ... + // ] + // } + // } + // + // Public for unit testing. + void UnpackLogoSignal(const DictionaryValue& parsed_json); + + static const char* kCurrentTipPrefName; + static const char* kTipCachePrefName; + + // Default server of dynamically loaded NTP HTML elements (promotions, tips): + static const char* kDefaultPromoResourceServer; + + private: + virtual ~PromoResourceService(); + + virtual void Unpack(const DictionaryValue& parsed_json); + + void Init(); + + // Schedule a notification that a web resource is either going to become + // available or be no longer valid. + void ScheduleNotification(double ms_start_time, double ms_end_time); + + // Gets mutable dictionary attached to user's preferences, so that we + // can write resource data back to user's pref file. + DictionaryValue* web_resource_cache_; + + DISALLOW_COPY_AND_ASSIGN(PromoResourceService); +}; + +#endif // CHROME_BROWSER_WEB_RESOURCE_PROMO_RESOURCE_SERVICE_H_ + diff --git a/chrome/browser/web_resource/web_resource_service_unittest.cc b/chrome/browser/web_resource/promo_resource_service_unittest.cc index cb51d9f..e84e43b 100644 --- a/chrome/browser/web_resource/web_resource_service_unittest.cc +++ b/chrome/browser/web_resource/promo_resource_service_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,16 +7,16 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/prefs/pref_service.h" -#include "chrome/browser/web_resource/web_resource_service.h" +#include "chrome/browser/web_resource/promo_resource_service.h" #include "chrome/common/pref_names.h" #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" -typedef testing::Test WebResourceServiceTest; +typedef testing::Test PromoResourceServiceTest; namespace { -// From web_resource_service.cc +// From promo_resource_service.cc enum BuildType { DEV_BUILD = 1, BETA_BUILD = 1 << 1, @@ -27,11 +27,11 @@ enum BuildType { // Verifies that custom dates read from a web resource server are written to // the preferences file. -TEST_F(WebResourceServiceTest, UnpackLogoSignal) { - // Set up a testing profile and create a web resource service. +TEST_F(PromoResourceServiceTest, UnpackLogoSignal) { + // Set up a testing profile and create a promo resource service. TestingProfile profile; - scoped_refptr<WebResourceService> web_resource_service( - new WebResourceService(&profile)); + scoped_refptr<PromoResourceService> web_resource_service( + new PromoResourceService(&profile)); // Set up start and end dates in a Dictionary as if parsed from the service. std::string json = "{ " @@ -109,11 +109,11 @@ TEST_F(WebResourceServiceTest, UnpackLogoSignal) { EXPECT_EQ(logo_end, 0); // date value reset to 0; } -TEST_F(WebResourceServiceTest, UnpackPromoSignal) { - // Set up a testing profile and create a web resource service. +TEST_F(PromoResourceServiceTest, UnpackPromoSignal) { + // Set up a testing profile and create a promo resource service. TestingProfile profile; - scoped_refptr<WebResourceService> web_resource_service( - new WebResourceService(&profile)); + scoped_refptr<PromoResourceService> web_resource_service( + new PromoResourceService(&profile)); // Set up start and end dates and promo line in a Dictionary as if parsed // from the service. diff --git a/chrome/browser/web_resource/web_resource_service.cc b/chrome/browser/web_resource/web_resource_service.cc index dad4343..daddae7 100644 --- a/chrome/browser/web_resource/web_resource_service.cc +++ b/chrome/browser/web_resource/web_resource_service.cc @@ -4,8 +4,6 @@ #include "chrome/browser/web_resource/web_resource_service.h" -#include <string> - #include "base/command_line.h" #include "base/file_path.h" #include "base/string_util.h" @@ -16,48 +14,18 @@ #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/platform_util.h" +#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/sync_ui_util.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/net/url_fetcher.h" #include "chrome/common/notification_service.h" -#include "chrome/common/notification_type.h" -#include "chrome/common/pref_names.h" +#include "chrome/common/web_resource/web_resource_unpacker.h" #include "googleurl/src/gurl.h" #include "net/base/load_flags.h" #include "net/url_request/url_request_status.h" -namespace { - -// Delay on first fetch so we don't interfere with startup. -static const int kStartResourceFetchDelay = 5000; - -// Delay between calls to update the cache (48 hours). -static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000; - -// Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order -// to be able to roll out promos slowly, or display different promos to -// different groups. -static const int kNTPPromoGroupSize = 16; - -// Maximum number of hours for each time slice (4 weeks). -static const int kMaxTimeSliceHours = 24 * 7 * 4; - -// Used to determine which build type should be shown a given promo. -enum BuildType { - DEV_BUILD = 1, - BETA_BUILD = 1 << 1, - STABLE_BUILD = 1 << 2, -}; - -} // namespace - -const char* WebResourceService::kCurrentTipPrefName = "current_tip"; -const char* WebResourceService::kTipCachePrefName = "tips"; - class WebResourceService::WebResourceFetcher : public URLFetcher::Delegate { public: @@ -70,8 +38,8 @@ class WebResourceService::WebResourceFetcher // with startup time. void StartAfterDelay(int64 delay_ms) { MessageLoop::current()->PostDelayedTask(FROM_HERE, - fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch), - delay_ms); + fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch), + delay_ms); } // Initializes the fetching of data from the resource server. Data @@ -82,16 +50,19 @@ class WebResourceService::WebResourceFetcher // First, put our next cache load on the MessageLoop. MessageLoop::current()->PostDelayedTask(FROM_HERE, fetcher_factory_.NewRunnableMethod(&WebResourceFetcher::StartFetch), - web_resource_service_->cache_update_delay()); + web_resource_service_->cache_update_delay_); // If we are still fetching data, exit. if (web_resource_service_->in_fetch_) return; else web_resource_service_->in_fetch_ = true; - std::string locale = g_browser_process->GetApplicationLocale(); - std::string web_resource_server = kDefaultWebResourceServer; - web_resource_server.append(locale); + std::string web_resource_server = + web_resource_service_->web_resource_server_; + if (web_resource_service_->apply_locale_to_url_) { + std::string locale = g_browser_process->GetApplicationLocale(); + web_resource_server.append(locale); + } url_fetcher_.reset(new URLFetcher(GURL( web_resource_server), @@ -99,9 +70,9 @@ class WebResourceService::WebResourceFetcher // Do not let url fetcher affect existing state in profile (by setting // cookies, for example. url_fetcher_->set_load_flags(net::LOAD_DISABLE_CACHE | - net::LOAD_DO_NOT_SAVE_COOKIES); + net::LOAD_DO_NOT_SAVE_COOKIES); URLRequestContextGetter* url_request_context_getter = - web_resource_service_->profile()->GetRequestContext(); + web_resource_service_->profile_->GetRequestContext(); url_fetcher_->set_request_context(url_request_context_getter); url_fetcher_->Start(); } @@ -225,43 +196,43 @@ class WebResourceService::UnpackerClient bool got_response_; }; -// Server for dynamically loaded NTP HTML elements. TODO(mirandac): append -// locale for future usage, when we're serving localizable strings. -const char* WebResourceService::kDefaultWebResourceServer = - "https://www.google.com/support/chrome/bin/topic/1142433/inproduct?hl="; - -WebResourceService::WebResourceService(Profile* profile) - : prefs_(profile->GetPrefs()), - profile_(profile), +WebResourceService::WebResourceService( + Profile* profile, + const char* web_resource_server, + bool apply_locale_to_url, + NotificationType::Type notification_type, + const char* last_update_time_pref_name, + int start_fetch_delay, + int cache_update_delay) + : profile_(profile), ALLOW_THIS_IN_INITIALIZER_LIST(service_factory_(this)), in_fetch_(false), + web_resource_server_(web_resource_server), + apply_locale_to_url_(apply_locale_to_url), + notification_type_(notification_type), + last_update_time_pref_name_(last_update_time_pref_name), + start_fetch_delay_(start_fetch_delay), + cache_update_delay_(cache_update_delay), web_resource_update_scheduled_(false) { - Init(); + DCHECK(profile); + prefs_ = profile_->GetPrefs(); + resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host(); + web_resource_fetcher_.reset(new WebResourceFetcher(this)); } WebResourceService::~WebResourceService() { } -void WebResourceService::Init() { - cache_update_delay_ = kCacheUpdateDelay; - resource_dispatcher_host_ = g_browser_process->resource_dispatcher_host(); - web_resource_fetcher_.reset(new WebResourceFetcher(this)); - prefs_->RegisterStringPref(prefs::kNTPWebResourceCacheUpdate, "0"); - prefs_->RegisterDoublePref(prefs::kNTPCustomLogoStart, 0); - prefs_->RegisterDoublePref(prefs::kNTPCustomLogoEnd, 0); - prefs_->RegisterDoublePref(prefs::kNTPPromoStart, 0); - prefs_->RegisterDoublePref(prefs::kNTPPromoEnd, 0); - prefs_->RegisterStringPref(prefs::kNTPPromoLine, std::string()); - prefs_->RegisterBooleanPref(prefs::kNTPPromoClosed, false); - prefs_->RegisterIntegerPref(prefs::kNTPPromoGroup, -1); - prefs_->RegisterIntegerPref(prefs::kNTPPromoBuild, - DEV_BUILD | BETA_BUILD | STABLE_BUILD); - prefs_->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, 0); - - // If the promo start is in the future, set a notification task to invalidate - // the NTP cache at the time of the promo start. - double promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); - double promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); - ScheduleNotification(promo_start, promo_end); +void WebResourceService::PostNotification(int64 delay_ms) { + if (web_resource_update_scheduled_) + return; + if (delay_ms > 0) { + web_resource_update_scheduled_ = true; + MessageLoop::current()->PostDelayedTask(FROM_HERE, + service_factory_.NewRunnableMethod( + &WebResourceService::WebResourceStateChange), delay_ms); + } else if (delay_ms == 0) { + WebResourceStateChange(); + } } void WebResourceService::EndFetch() { @@ -270,56 +241,25 @@ void WebResourceService::EndFetch() { void WebResourceService::OnWebResourceUnpacked( const DictionaryValue& parsed_json) { - UnpackLogoSignal(parsed_json); - UnpackPromoSignal(parsed_json); + Unpack(parsed_json); EndFetch(); } void WebResourceService::WebResourceStateChange() { web_resource_update_scheduled_ = false; NotificationService* service = NotificationService::current(); - service->Notify(NotificationType::WEB_RESOURCE_STATE_CHANGED, + service->Notify(notification_type_, Source<WebResourceService>(this), NotificationService::NoDetails()); } -void WebResourceService::ScheduleNotification(double promo_start, - double promo_end) { - if (promo_start > 0 && promo_end > 0 && !web_resource_update_scheduled_) { - int64 ms_until_start = - static_cast<int64>((base::Time::FromDoubleT( - promo_start) - base::Time::Now()).InMilliseconds()); - int64 ms_until_end = - static_cast<int64>((base::Time::FromDoubleT( - promo_end) - base::Time::Now()).InMilliseconds()); - if (ms_until_start > 0) { - web_resource_update_scheduled_ = true; - MessageLoop::current()->PostDelayedTask(FROM_HERE, - service_factory_.NewRunnableMethod( - &WebResourceService::WebResourceStateChange), - ms_until_start); - } - if (ms_until_end > 0) { - web_resource_update_scheduled_ = true; - MessageLoop::current()->PostDelayedTask(FROM_HERE, - service_factory_.NewRunnableMethod( - &WebResourceService::WebResourceStateChange), - ms_until_end); - if (ms_until_start <= 0) { - // Notify immediately if time is between start and end. - WebResourceStateChange(); - } - } - } -} - void WebResourceService::StartAfterDelay() { - int64 delay = kStartResourceFetchDelay; + int64 delay = start_fetch_delay_; // Check whether we have ever put a value in the web resource cache; // if so, pull it out and see if it's time to update again. - if (prefs_->HasPrefPath(prefs::kNTPWebResourceCacheUpdate)) { + if (prefs_->HasPrefPath(last_update_time_pref_name_)) { std::string last_update_pref = - prefs_->GetString(prefs::kNTPWebResourceCacheUpdate); + prefs_->GetString(last_update_time_pref_name_); if (!last_update_pref.empty()) { double last_update_value; base::StringToDouble(last_update_pref, &last_update_value); @@ -327,8 +267,8 @@ void WebResourceService::StartAfterDelay() { static_cast<int64>((base::Time::Now() - base::Time::FromDoubleT( last_update_value)).InMilliseconds()); delay = ms_until_update > cache_update_delay_ ? - cache_update_delay_ : (ms_until_update < kStartResourceFetchDelay ? - kStartResourceFetchDelay : ms_until_update); + cache_update_delay_ : (ms_until_update < start_fetch_delay_ ? + start_fetch_delay_ : ms_until_update); } } // Start fetch and wait for UpdateResourceCache. @@ -340,250 +280,6 @@ void WebResourceService::UpdateResourceCache(const std::string& json_data) { client->Start(); // Set cache update time in preferences. - prefs_->SetString(prefs::kNTPWebResourceCacheUpdate, + prefs_->SetString(last_update_time_pref_name_, base::DoubleToString(base::Time::Now().ToDoubleT())); } - -void WebResourceService::UnpackTips(const DictionaryValue& parsed_json) { - // Get dictionary of cached preferences. - web_resource_cache_ = - prefs_->GetMutableDictionary(prefs::kNTPWebResourceCache); - - // The list of individual tips. - ListValue* tip_holder = new ListValue(); - web_resource_cache_->Set(WebResourceService::kTipCachePrefName, tip_holder); - - DictionaryValue* topic_dict; - ListValue* answer_list; - std::string topic_id; - std::string answer_id; - std::string inproduct; - int tip_counter = 0; - - if (parsed_json.GetDictionary("topic", &topic_dict)) { - if (topic_dict->GetString("topic_id", &topic_id)) - web_resource_cache_->SetString("topic_id", topic_id); - if (topic_dict->GetList("answers", &answer_list)) { - for (ListValue::const_iterator tip_iter = answer_list->begin(); - tip_iter != answer_list->end(); ++tip_iter) { - if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) - continue; - DictionaryValue* a_dic = - static_cast<DictionaryValue*>(*tip_iter); - if (a_dic->GetString("inproduct", &inproduct)) { - tip_holder->Append(Value::CreateStringValue(inproduct)); - } - tip_counter++; - } - // If tips exist, set current index to 0. - if (!inproduct.empty()) { - web_resource_cache_->SetInteger( - WebResourceService::kCurrentTipPrefName, 0); - } - } - } -} - -void WebResourceService::UnpackPromoSignal(const DictionaryValue& parsed_json) { - DictionaryValue* topic_dict; - ListValue* answer_list; - double old_promo_start = 0; - double old_promo_end = 0; - double promo_start = 0; - double promo_end = 0; - - // Check for preexisting start and end values. - if (prefs_->HasPrefPath(prefs::kNTPPromoStart) && - prefs_->HasPrefPath(prefs::kNTPPromoEnd)) { - old_promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); - old_promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); - } - - // Check for newly received start and end values. - if (parsed_json.GetDictionary("topic", &topic_dict)) { - if (topic_dict->GetList("answers", &answer_list)) { - std::string promo_start_string = ""; - std::string promo_end_string = ""; - std::string promo_string = ""; - std::string promo_build = ""; - int promo_build_type = 0; - int time_slice_hrs = 0; - for (ListValue::const_iterator tip_iter = answer_list->begin(); - tip_iter != answer_list->end(); ++tip_iter) { - if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) - continue; - DictionaryValue* a_dic = - static_cast<DictionaryValue*>(*tip_iter); - std::string promo_signal; - if (a_dic->GetString("name", &promo_signal)) { - if (promo_signal == "promo_start") { - a_dic->GetString("question", &promo_build); - size_t split = promo_build.find(":"); - if (split != std::string::npos && - base::StringToInt(promo_build.substr(0, split), - &promo_build_type) && - base::StringToInt(promo_build.substr(split+1), - &time_slice_hrs) && - promo_build_type >= 0 && - promo_build_type <= (DEV_BUILD | BETA_BUILD | STABLE_BUILD) && - time_slice_hrs >= 0 && - time_slice_hrs <= kMaxTimeSliceHours) { - prefs_->SetInteger(prefs::kNTPPromoBuild, promo_build_type); - prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, - time_slice_hrs); - } else { - // If no time data or bad time data are set, show promo on all - // builds with no time slicing. - prefs_->SetInteger(prefs::kNTPPromoBuild, - DEV_BUILD | BETA_BUILD | STABLE_BUILD); - prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, 0); - } - a_dic->GetString("inproduct", &promo_start_string); - a_dic->GetString("tooltip", &promo_string); - prefs_->SetString(prefs::kNTPPromoLine, promo_string); - srand(static_cast<uint32>(time(NULL))); - prefs_->SetInteger(prefs::kNTPPromoGroup, - rand() % kNTPPromoGroupSize); - } else if (promo_signal == "promo_end") { - a_dic->GetString("inproduct", &promo_end_string); - } - } - } - if (!promo_start_string.empty() && - promo_start_string.length() > 0 && - !promo_end_string.empty() && - promo_end_string.length() > 0) { - base::Time start_time; - base::Time end_time; - if (base::Time::FromString( - ASCIIToWide(promo_start_string).c_str(), &start_time) && - base::Time::FromString( - ASCIIToWide(promo_end_string).c_str(), &end_time)) { - // Add group time slice, adjusted from hours to seconds. - promo_start = start_time.ToDoubleT() + - (prefs_->FindPreference(prefs::kNTPPromoGroup) ? - prefs_->GetInteger(prefs::kNTPPromoGroup) * - time_slice_hrs * 60 * 60 : 0); - promo_end = end_time.ToDoubleT(); - } - } - } - } - - // If start or end times have changed, trigger a new web resource - // notification, so that the logo on the NTP is updated. This check is - // outside the reading of the web resource data, because the absence of - // dates counts as a triggering change if there were dates before. - // Also reset the promo closed preference, to signal a new promo. - if (!(old_promo_start == promo_start) || - !(old_promo_end == promo_end)) { - prefs_->SetDouble(prefs::kNTPPromoStart, promo_start); - prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end); - prefs_->SetBoolean(prefs::kNTPPromoClosed, false); - ScheduleNotification(promo_start, promo_end); - } -} - -void WebResourceService::UnpackLogoSignal(const DictionaryValue& parsed_json) { - DictionaryValue* topic_dict; - ListValue* answer_list; - double old_logo_start = 0; - double old_logo_end = 0; - double logo_start = 0; - double logo_end = 0; - - // Check for preexisting start and end values. - if (prefs_->HasPrefPath(prefs::kNTPCustomLogoStart) && - prefs_->HasPrefPath(prefs::kNTPCustomLogoEnd)) { - old_logo_start = prefs_->GetDouble(prefs::kNTPCustomLogoStart); - old_logo_end = prefs_->GetDouble(prefs::kNTPCustomLogoEnd); - } - - // Check for newly received start and end values. - if (parsed_json.GetDictionary("topic", &topic_dict)) { - if (topic_dict->GetList("answers", &answer_list)) { - std::string logo_start_string = ""; - std::string logo_end_string = ""; - for (ListValue::const_iterator tip_iter = answer_list->begin(); - tip_iter != answer_list->end(); ++tip_iter) { - if (!(*tip_iter)->IsType(Value::TYPE_DICTIONARY)) - continue; - DictionaryValue* a_dic = - static_cast<DictionaryValue*>(*tip_iter); - std::string logo_signal; - if (a_dic->GetString("name", &logo_signal)) { - if (logo_signal == "custom_logo_start") { - a_dic->GetString("inproduct", &logo_start_string); - } else if (logo_signal == "custom_logo_end") { - a_dic->GetString("inproduct", &logo_end_string); - } - } - } - if (!logo_start_string.empty() && - logo_start_string.length() > 0 && - !logo_end_string.empty() && - logo_end_string.length() > 0) { - base::Time start_time; - base::Time end_time; - if (base::Time::FromString( - ASCIIToWide(logo_start_string).c_str(), &start_time) && - base::Time::FromString( - ASCIIToWide(logo_end_string).c_str(), &end_time)) { - logo_start = start_time.ToDoubleT(); - logo_end = end_time.ToDoubleT(); - } - } - } - } - - // If logo start or end times have changed, trigger a new web resource - // notification, so that the logo on the NTP is updated. This check is - // outside the reading of the web resource data, because the absence of - // dates counts as a triggering change if there were dates before. - if (!(old_logo_start == logo_start) || - !(old_logo_end == logo_end)) { - prefs_->SetDouble(prefs::kNTPCustomLogoStart, logo_start); - prefs_->SetDouble(prefs::kNTPCustomLogoEnd, logo_end); - NotificationService* service = NotificationService::current(); - service->Notify(NotificationType::WEB_RESOURCE_STATE_CHANGED, - Source<WebResourceService>(this), - NotificationService::NoDetails()); - } -} - -namespace WebResourceServiceUtil { - -bool CanShowPromo(Profile* profile) { - bool promo_closed = false; - PrefService* prefs = profile->GetPrefs(); - if (prefs->HasPrefPath(prefs::kNTPPromoClosed)) - promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed); - - // Only show if not synced. - bool is_synced = - (profile->HasProfileSyncService() && - sync_ui_util::GetStatus( - profile->GetProfileSyncService()) == sync_ui_util::SYNCED); - - // GetVersionStringModifier hits the registry. See http://crbug.com/70898. - base::ThreadRestrictions::ScopedAllowIO allow_io; - const std::string channel = platform_util::GetVersionStringModifier(); - bool is_promo_build = false; - if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) { - int builds_allowed = prefs->GetInteger(prefs::kNTPPromoBuild); - if (channel == "dev") { - is_promo_build = (DEV_BUILD & builds_allowed) != 0; - } else if (channel == "beta") { - is_promo_build = (BETA_BUILD & builds_allowed) != 0; - } else if (channel == "stable") { - is_promo_build = (STABLE_BUILD & builds_allowed) != 0; - } else { - is_promo_build = true; - } - } - - return !promo_closed && !is_synced && is_promo_build; -} - -} // namespace WebResourceService - diff --git a/chrome/browser/web_resource/web_resource_service.h b/chrome/browser/web_resource/web_resource_service.h index 815eaf7..1b4b680 100644 --- a/chrome/browser/web_resource/web_resource_service.h +++ b/chrome/browser/web_resource/web_resource_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,33 +8,24 @@ #include <string> -#include "base/file_path.h" -#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/utility_process_host.h" -#include "chrome/common/web_resource/web_resource_unpacker.h" +#include "chrome/common/notification_type.h" +class PrefService; class Profile; -namespace WebResourceServiceUtil { - -// Certain promotions should only be shown to certain classes of users. This -// function will change to reflect each kind of promotion. -bool CanShowPromo(Profile* profile); - -} // namespace WebResourceService - -// A WebResourceService fetches data from a web resource server to be used to -// dynamically change the appearance of the New Tab Page. For example, it has -// been used to fetch "tips" to be displayed on the NTP, or to display -// promotional messages to certain groups of Chrome users. -// -// TODO(mirandac): Arrange for a server to be set up specifically for promo -// messages, which have until now been piggybacked onto the old tips server -// structure. (see http://crbug.com/70634 for details.) +// A WebResourceService fetches data from a web resource server and store +// locally as user preference. class WebResourceService : public UtilityProcessHost::Client { public: - explicit WebResourceService(Profile* profile); + WebResourceService(Profile* profile, + const char* web_resource_server, + bool apply_locale_to_url_, + NotificationType::Type notification_type, + const char* last_update_time_pref_name, + int start_fetch_delay, + int cache_update_delay); // Sleep until cache needs to be updated, but always for at least 5 seconds // so we don't interfere with startup. Then begin updating resources. @@ -44,107 +35,19 @@ class WebResourceService // the process that will parse the JSON, and then update the cache. void UpdateResourceCache(const std::string& json_data); - // Unpack the web resource as a set of tips. Expects json in the form of: - // { - // "lang": "en", - // "topic": { - // "topid_id": "24013", - // "topics": [ - // ], - // "answers": [ - // { - // "answer_id": "18625", - // "inproduct": "Text here will be shown as a tip", - // }, - // ... - // ] - // } - // } - // - // Public for unit testing. - void UnpackTips(const DictionaryValue& parsed_json); - - // Unpack the web resource as a custom promo signal. Expects a start and end - // signal, with the promo to be shown in the tooltip of the start signal - // field. Delivery will be in json in the form of: - // { - // "topic": { - // "answers": [ - // { - // "answer_id": "1067976", - // "name": "promo_start", - // "question": "1:24", - // "tooltip": - // "Click \u003ca href=http://www.google.com\u003ehere\u003c/a\u003e!", - // "inproduct": "10/8/09 12:00", - // "inproduct_target": null - // }, - // { - // "answer_id": "1067976", - // "name": "promo_end", - // "question": "", - // "tooltip": "", - // "inproduct": "10/8/11 12:00", - // "inproduct_target": null - // }, - // ... - // ] - // } - // } - // - // Because the promo signal data is piggybacked onto the tip server, the - // values don't exactly correspond with the field names: - // - // For "promo_start" or "promo_end", the date to start or stop showing the - // promotional line is given by the "inproduct" line. - // For "promo_start", the promotional line itself is given in the "tooltip" - // field. The "question" field gives the type of builds that should be shown - // this promo (see the BuildType enum in web_resource_service.cc) and the - // number of hours that each promo group should see it, separated by ":". - // For example, "7:24" would indicate that all builds should see the promo, - // and each group should see it for 24 hours. - // - // Public for unit testing. - void UnpackPromoSignal(const DictionaryValue& parsed_json); - - // Unpack the web resource as a custom logo signal. Expects a start and end - // signal. Delivery will be in json in the form of: - // { - // "topic": { - // "answers": [ - // { - // "answer_id": "107366", - // "name": "custom_logo_start", - // "question": "", - // "tooltip": "", - // "inproduct": "10/8/09 12:00", - // "inproduct_target": null - // }, - // { - // "answer_id": "107366", - // "name": "custom_logo_end", - // "question": "", - // "tooltip": "", - // "inproduct": "10/8/09 12:00", - // "inproduct_target": null - // }, - // ... - // ] - // } - // } - // - // Public for unit testing. - void UnpackLogoSignal(const DictionaryValue& parsed_json); - - int cache_update_delay() const { return cache_update_delay_; } - - Profile* profile() const { return profile_; } - - static const char* kCurrentTipPrefName; - static const char* kTipCachePrefName; - - // Default server of dynamically loaded NTP HTML elements (promotions, tips): - static const char* kDefaultWebResourceServer; + protected: + virtual ~WebResourceService(); + + virtual void Unpack(const DictionaryValue& parsed_json) = 0; + + // If delay_ms is positive, schedule notification with the delay. + // If delay_ms is 0, notify immediately by calling WebResourceStateChange(). + // If delay_ms is negative, do nothing. + void PostNotification(int64 delay_ms); + + // We need to be able to load parsed resource data into preferences file, + // and get proper install directory. + PrefService* prefs_; private: class WebResourceFetcher; @@ -152,10 +55,6 @@ class WebResourceService class UnpackerClient; - ~WebResourceService(); - - void Init(); - // Set in_fetch_ to false, clean up temp directories (in the future). void EndFetch(); @@ -165,16 +64,6 @@ class WebResourceService // Notify listeners that the state of a web resource has changed. void WebResourceStateChange(); - // Schedule a notification that a web resource is either going to become - // available or be no longer valid. - void ScheduleNotification(double ms_start_time, double ms_end_time); - - // We need to be able to load parsed resource data into preferences file, - // and get proper install directory. - PrefService* prefs_; - - // Display and fetch of promo lines depends on data associated with a user's - // profile. Profile* profile_; scoped_ptr<WebResourceFetcher> web_resource_fetcher_; @@ -186,15 +75,26 @@ class WebResourceService // Page immediately when a new web resource should be shown or removed. ScopedRunnableMethodFactory<WebResourceService> service_factory_; - // Gets mutable dictionary attached to user's preferences, so that we - // can write resource data back to user's pref file. - DictionaryValue* web_resource_cache_; - // True if we are currently mid-fetch. If we are asked to start a fetch // when we are still fetching resource data, schedule another one in // kCacheUpdateDelay time, and silently exit. bool in_fetch_; + // URL that hosts the web resource. + const char* web_resource_server_; + + // Indicates whether we should append locale to the web resource server URL. + bool apply_locale_to_url_; + + // Notification type when an update is done. + NotificationType::Type notification_type_; + + // Pref name to store the last update's time. + const char* last_update_time_pref_name_; + + // Delay on first fetch so we don't interfere with startup. + int start_fetch_delay_; + // Delay between calls to update the web resource cache. This delay may be // different for different builds of Chrome. int cache_update_delay_; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 6745c31..b8d33fc 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3518,6 +3518,8 @@ 'browser/visitedlink/visitedlink_master.h', 'browser/web_applications/web_app.cc', 'browser/web_applications/web_app.h', + 'browser/web_resource/promo_resource_service.cc', + 'browser/web_resource/promo_resource_service.h', 'browser/web_resource/web_resource_service.cc', 'browser/web_resource/web_resource_service.h', 'browser/webdata/autofill_change.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 1d7e6c5..12c2654 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1744,7 +1744,7 @@ 'browser/webdata/web_data_service_unittest.cc', 'browser/webdata/web_database_unittest.cc', 'browser/webui/web_ui_unittest.cc', - 'browser/web_resource/web_resource_service_unittest.cc', + 'browser/web_resource/promo_resource_service_unittest.cc', 'common/bzip2_unittest.cc', 'common/child_process_logging_mac_unittest.mm', 'common/chrome_paths_unittest.cc', diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 04a600ad..ca41f91 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -780,7 +780,7 @@ class NotificationType { // The state of a web resource has been changed. A resource may have been // added, removed, or altered. Source is WebResourceService, and the // details are NoDetails. - WEB_RESOURCE_STATE_CHANGED, + PROMO_RESOURCE_STATE_CHANGED, // Autocomplete ------------------------------------------------------------ diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index f3ddcc3..78430dd 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1033,15 +1033,15 @@ const char kNTPMostVisitedURLsBlacklist[] = "ntp.most_visited_blacklist"; // Page. const char kNTPMostVisitedPinnedURLs[] = "ntp.pinned_urls"; -// Data downloaded from resource pages (JSON, RSS) to be used to dynamically -// deliver data for the new tab page. -const char kNTPWebResourceCache[] = "ntp.web_resource_cache"; +// Data downloaded from promo resource pages (JSON, RSS) to be used to +// dynamically deliver data for the new tab page. +const char kNTPPromoResourceCache[] = "ntp.promo_resource_cache"; -// Last time of update of web_resource_cache. -const char kNTPWebResourceCacheUpdate[] = "ntp.web_resource_cache_update"; +// Last time of update of promo_resource_cache. +const char kNTPPromoResourceCacheUpdate[] = "ntp.promo_resource_cache_update"; -// Serves resources for the NTP. -const char kNTPWebResourceServer[] = "ntp.web_resource_server"; +// Serves promo resources for the NTP. +const char kNTPPromoResourceServer[] = "ntp.web_resource_server"; // Serves tips for the NTP. const char kNTPTipsResourceServer[] = "ntp.tips_resource_server"; diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 8fe066d..9dff4dd 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -362,9 +362,9 @@ extern const char kNTPTipsResourceServer[]; extern const char kNTPMostVisitedURLsBlacklist[]; extern const char kNTPMostVisitedPinnedURLs[]; -extern const char kNTPWebResourceCache[]; -extern const char kNTPWebResourceCacheUpdate[]; -extern const char kNTPWebResourceServer[]; +extern const char kNTPPromoResourceCache[]; +extern const char kNTPPromoResourceCacheUpdate[]; +extern const char kNTPPromoResourceServer[]; extern const char kNTPDateResourceServer[]; extern const char kNTPShownSections[]; extern const char kNTPPrefVersion[]; diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index ec2f82a..9d41ae1 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -237,7 +237,7 @@ class TestingProfile : public Profile { virtual WebKitContext* GetOffTheRecordWebKitContext(); virtual void MarkAsCleanShutdown() {} virtual void InitExtensions() {} - virtual void InitWebResources() {} + virtual void InitPromoResources() {} virtual NTPResourceCache* GetNTPResourceCache(); virtual DesktopNotificationService* GetDesktopNotificationService(); |