| Index: chrome/browser/web_resource/web_resource_service.cc
|
| ===================================================================
|
| --- chrome/browser/web_resource/web_resource_service.cc (revision 75300)
|
| +++ chrome/browser/web_resource/web_resource_service.cc (working copy)
|
| @@ -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 @@
|
| // 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 @@
|
| // 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 @@
|
| // 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 @@
|
| 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::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 @@
|
| 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 @@
|
| 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
|
| -
|
|
|