Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/web_resource/promo_resource_service.h" | 5 #include "chrome/browser/web_resource/promo_resource_service.h" |
| 6 | 6 |
| 7 #include "base/string_number_conversions.h" | 7 #include "base/string_number_conversions.h" |
| 8 #include "base/threading/thread_restrictions.h" | 8 #include "base/threading/thread_restrictions.h" |
| 9 #include "base/time.h" | 9 #include "base/time.h" |
| 10 #include "base/values.h" | 10 #include "base/values.h" |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 24 | 24 |
| 25 // Delay on first fetch so we don't interfere with startup. | 25 // Delay on first fetch so we don't interfere with startup. |
| 26 static const int kStartResourceFetchDelay = 5000; | 26 static const int kStartResourceFetchDelay = 5000; |
| 27 | 27 |
| 28 // Delay between calls to update the cache (48 hours). | 28 // Delay between calls to update the cache (48 hours). |
| 29 static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000; | 29 static const int kCacheUpdateDelay = 48 * 60 * 60 * 1000; |
| 30 | 30 |
| 31 // Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order | 31 // Users are randomly assigned to one of kNTPPromoGroupSize buckets, in order |
| 32 // to be able to roll out promos slowly, or display different promos to | 32 // to be able to roll out promos slowly, or display different promos to |
| 33 // different groups. | 33 // different groups. |
| 34 static const int kNTPPromoGroupSize = 16; | 34 static const int kNTPPromoGroupSize = 100; |
| 35 | 35 |
| 36 // Maximum number of hours for each time slice (4 weeks). | 36 // Maximum number of hours for each time slice (4 weeks). |
| 37 static const int kMaxTimeSliceHours = 24 * 7 * 4; | 37 static const int kMaxTimeSliceHours = 24 * 7 * 4; |
| 38 | 38 |
| 39 // The version of the service (used to expire the cache when upgrading Chrome | 39 // The version of the service (used to expire the cache when upgrading Chrome |
| 40 // to versions with different types of promos). | 40 // to versions with different types of promos). |
| 41 static const int kPromoServiceVersion = 2; | 41 static const int kPromoServiceVersion = 2; |
| 42 | 42 |
| 43 // Properties used by the server. | 43 // Properties used by the server. |
| 44 static const char kAnswerIdProperty[] = "answer_id"; | 44 static const char kAnswerIdProperty[] = "answer_id"; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 74 prefs->RegisterDoublePref(prefs::kNTPPromoEnd, | 74 prefs->RegisterDoublePref(prefs::kNTPPromoEnd, |
| 75 0, | 75 0, |
| 76 PrefService::UNSYNCABLE_PREF); | 76 PrefService::UNSYNCABLE_PREF); |
| 77 prefs->RegisterStringPref(prefs::kNTPPromoLine, | 77 prefs->RegisterStringPref(prefs::kNTPPromoLine, |
| 78 std::string(), | 78 std::string(), |
| 79 PrefService::UNSYNCABLE_PREF); | 79 PrefService::UNSYNCABLE_PREF); |
| 80 prefs->RegisterBooleanPref(prefs::kNTPPromoClosed, | 80 prefs->RegisterBooleanPref(prefs::kNTPPromoClosed, |
| 81 false, | 81 false, |
| 82 PrefService::UNSYNCABLE_PREF); | 82 PrefService::UNSYNCABLE_PREF); |
| 83 prefs->RegisterIntegerPref(prefs::kNTPPromoGroup, | 83 prefs->RegisterIntegerPref(prefs::kNTPPromoGroup, |
| 84 -1, | 84 0, |
| 85 PrefService::UNSYNCABLE_PREF); | |
| 86 prefs->RegisterIntegerPref(prefs::kNTPPromoGroupMax, | |
| 87 0, | |
| 85 PrefService::UNSYNCABLE_PREF); | 88 PrefService::UNSYNCABLE_PREF); |
| 86 prefs->RegisterIntegerPref( | 89 prefs->RegisterIntegerPref( |
| 87 prefs::kNTPPromoBuild, | 90 prefs::kNTPPromoBuild, |
| 88 CANARY_BUILD | DEV_BUILD | BETA_BUILD | STABLE_BUILD, | 91 CANARY_BUILD | DEV_BUILD | BETA_BUILD | STABLE_BUILD, |
| 89 PrefService::UNSYNCABLE_PREF); | 92 PrefService::UNSYNCABLE_PREF); |
| 90 prefs->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, | 93 prefs->RegisterIntegerPref(prefs::kNTPPromoGroupTimeSlice, |
| 91 0, | 94 0, |
| 92 PrefService::UNSYNCABLE_PREF); | 95 PrefService::UNSYNCABLE_PREF); |
| 93 } | 96 } |
| 94 | 97 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 } | 202 } |
| 200 | 203 |
| 201 void PromoResourceService::UnpackPromoSignal( | 204 void PromoResourceService::UnpackPromoSignal( |
| 202 const DictionaryValue& parsed_json) { | 205 const DictionaryValue& parsed_json) { |
| 203 DictionaryValue* topic_dict; | 206 DictionaryValue* topic_dict; |
| 204 ListValue* answer_list; | 207 ListValue* answer_list; |
| 205 double old_promo_start = 0; | 208 double old_promo_start = 0; |
| 206 double old_promo_end = 0; | 209 double old_promo_end = 0; |
| 207 double promo_start = 0; | 210 double promo_start = 0; |
| 208 double promo_end = 0; | 211 double promo_end = 0; |
| 212 int time_slice_hrs = 0; | |
| 209 | 213 |
| 210 // Check for preexisting start and end values. | 214 // Check for preexisting start and end values. |
| 211 if (prefs_->HasPrefPath(prefs::kNTPPromoStart) && | 215 if (prefs_->HasPrefPath(prefs::kNTPPromoStart) && |
| 212 prefs_->HasPrefPath(prefs::kNTPPromoEnd)) { | 216 prefs_->HasPrefPath(prefs::kNTPPromoEnd)) { |
| 213 old_promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); | 217 old_promo_start = prefs_->GetDouble(prefs::kNTPPromoStart); |
| 214 old_promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); | 218 old_promo_end = prefs_->GetDouble(prefs::kNTPPromoEnd); |
| 215 } | 219 } |
| 216 | 220 |
| 217 // Check for newly received start and end values. | 221 // Check for newly received start and end values. |
| 218 if (parsed_json.GetDictionary("topic", &topic_dict)) { | 222 if (parsed_json.GetDictionary("topic", &topic_dict)) { |
| 219 if (topic_dict->GetList("answers", &answer_list)) { | 223 if (topic_dict->GetList("answers", &answer_list)) { |
| 220 std::string promo_start_string = ""; | 224 std::string promo_start_string = ""; |
| 221 std::string promo_end_string = ""; | 225 std::string promo_end_string = ""; |
| 222 std::string promo_string = ""; | 226 std::string promo_string = ""; |
| 223 std::string promo_build = ""; | 227 std::string promo_build = ""; |
| 224 int promo_build_type = 0; | 228 int promo_build_type = 0; |
| 225 int time_slice_hrs = 0; | 229 int max_group = 0; |
| 226 for (ListValue::const_iterator answer_iter = answer_list->begin(); | 230 for (ListValue::const_iterator answer_iter = answer_list->begin(); |
| 227 answer_iter != answer_list->end(); ++answer_iter) { | 231 answer_iter != answer_list->end(); ++answer_iter) { |
| 228 if (!(*answer_iter)->IsType(Value::TYPE_DICTIONARY)) | 232 if (!(*answer_iter)->IsType(Value::TYPE_DICTIONARY)) |
| 229 continue; | 233 continue; |
| 230 DictionaryValue* a_dic = | 234 DictionaryValue* a_dic = |
| 231 static_cast<DictionaryValue*>(*answer_iter); | 235 static_cast<DictionaryValue*>(*answer_iter); |
| 232 std::string promo_signal; | 236 std::string promo_signal; |
| 233 if (a_dic->GetString("name", &promo_signal)) { | 237 if (a_dic->GetString("name", &promo_signal)) { |
| 234 if (promo_signal == "promo_start") { | 238 if (promo_signal == "promo_start") { |
| 235 a_dic->GetString("question", &promo_build); | 239 a_dic->GetString("question", &promo_build); |
| 236 size_t split = promo_build.find(":"); | 240 size_t split = promo_build.find(':'); |
| 241 size_t split2 = promo_build.rfind(':'); | |
| 237 if (split != std::string::npos && | 242 if (split != std::string::npos && |
| 243 split2 != std::string::npos && | |
| 244 split != split2 && | |
| 238 base::StringToInt(promo_build.substr(0, split), | 245 base::StringToInt(promo_build.substr(0, split), |
| 239 &promo_build_type) && | 246 &promo_build_type) && |
| 240 base::StringToInt(promo_build.substr(split+1), | 247 base::StringToInt(promo_build.substr(split + 1, |
| 248 split2 - split - 1), | |
| 241 &time_slice_hrs) && | 249 &time_slice_hrs) && |
| 250 base::StringToInt(promo_build.substr(split2 + 1), | |
| 251 &max_group) && | |
| 242 promo_build_type >= 0 && | 252 promo_build_type >= 0 && |
| 243 promo_build_type <= (DEV_BUILD | BETA_BUILD | STABLE_BUILD) && | 253 promo_build_type <= (DEV_BUILD | BETA_BUILD | STABLE_BUILD) && |
| 244 time_slice_hrs >= 0 && | 254 time_slice_hrs >= 0 && |
| 245 time_slice_hrs <= kMaxTimeSliceHours) { | 255 time_slice_hrs <= kMaxTimeSliceHours && |
| 256 max_group >= 0 && | |
| 257 max_group <= kNTPPromoGroupSize) { | |
| 246 prefs_->SetInteger(prefs::kNTPPromoBuild, promo_build_type); | 258 prefs_->SetInteger(prefs::kNTPPromoBuild, promo_build_type); |
| 247 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, | 259 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, |
| 248 time_slice_hrs); | 260 time_slice_hrs); |
| 261 prefs_->SetInteger(prefs::kNTPPromoGroupMax, max_group); | |
| 249 } else { | 262 } else { |
| 250 // If no time data or bad time data are set, do not show promo. | 263 // If no time data or bad time data are set, do not show promo. |
| 251 prefs_->SetInteger(prefs::kNTPPromoBuild, NO_BUILD); | 264 prefs_->SetInteger(prefs::kNTPPromoBuild, NO_BUILD); |
| 252 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, 0); | 265 prefs_->SetInteger(prefs::kNTPPromoGroupTimeSlice, 0); |
| 266 prefs_->SetInteger(prefs::kNTPPromoGroupMax, 0); | |
| 253 } | 267 } |
| 254 a_dic->GetString("inproduct", &promo_start_string); | 268 a_dic->GetString("inproduct", &promo_start_string); |
| 255 a_dic->GetString("tooltip", &promo_string); | 269 a_dic->GetString("tooltip", &promo_string); |
| 256 prefs_->SetString(prefs::kNTPPromoLine, promo_string); | 270 prefs_->SetString(prefs::kNTPPromoLine, promo_string); |
| 257 srand(static_cast<uint32>(time(NULL))); | |
| 258 prefs_->SetInteger(prefs::kNTPPromoGroup, | |
| 259 rand() % kNTPPromoGroupSize); | |
| 260 } else if (promo_signal == "promo_end") { | 271 } else if (promo_signal == "promo_end") { |
| 261 a_dic->GetString("inproduct", &promo_end_string); | 272 a_dic->GetString("inproduct", &promo_end_string); |
| 262 } | 273 } |
| 263 } | 274 } |
| 264 } | 275 } |
| 265 if (!promo_start_string.empty() && | 276 if (!promo_start_string.empty() && |
| 266 promo_start_string.length() > 0 && | 277 promo_start_string.length() > 0 && |
| 267 !promo_end_string.empty() && | 278 !promo_end_string.empty() && |
| 268 promo_end_string.length() > 0) { | 279 promo_end_string.length() > 0) { |
| 269 base::Time start_time; | 280 base::Time start_time; |
| 270 base::Time end_time; | 281 base::Time end_time; |
| 271 if (base::Time::FromString( | 282 if (base::Time::FromString( |
| 272 ASCIIToWide(promo_start_string).c_str(), &start_time) && | 283 ASCIIToWide(promo_start_string).c_str(), &start_time) && |
| 273 base::Time::FromString( | 284 base::Time::FromString( |
| 274 ASCIIToWide(promo_end_string).c_str(), &end_time)) { | 285 ASCIIToWide(promo_end_string).c_str(), &end_time)) { |
| 275 // Add group time slice, adjusted from hours to seconds. | 286 promo_start = start_time.ToDoubleT(); |
| 276 promo_start = start_time.ToDoubleT() + | |
| 277 (prefs_->FindPreference(prefs::kNTPPromoGroup) ? | |
| 278 prefs_->GetInteger(prefs::kNTPPromoGroup) * | |
| 279 time_slice_hrs * 60 * 60 : 0); | |
| 280 promo_end = end_time.ToDoubleT(); | 287 promo_end = end_time.ToDoubleT(); |
| 281 } | 288 } |
| 282 } | 289 } |
| 283 } | 290 } |
| 284 } | 291 } |
| 285 | 292 |
| 286 // If start or end times have changed, trigger a new web resource | 293 // If end time has changed, trigger a new web resource |
| 287 // notification, so that the logo on the NTP is updated. This check is | 294 // notification, so that the logo on the NTP is updated. This check is |
| 288 // outside the reading of the web resource data, because the absence of | 295 // outside the reading of the web resource data, because the absence of |
| 289 // dates counts as a triggering change if there were dates before. | 296 // dates counts as a triggering change if there were dates before. |
| 290 // Also reset the promo closed preference, to signal a new promo. | 297 // Also reset the promo closed preference, to signal a new promo. |
| 291 if (!(old_promo_start == promo_start) || | 298 if (!(old_promo_end == promo_end)) { |
| 292 !(old_promo_end == promo_end)) { | 299 srand(static_cast<uint32>(time(NULL))); |
| 300 int promo_group = rand() % kNTPPromoGroupSize; | |
| 301 prefs_->SetInteger(prefs::kNTPPromoGroup, promo_group); | |
| 302 | |
| 303 // Add group time slice, adjusted from hours to seconds. | |
| 304 promo_start += promo_group * time_slice_hrs * 60 * 60; | |
| 293 prefs_->SetDouble(prefs::kNTPPromoStart, promo_start); | 305 prefs_->SetDouble(prefs::kNTPPromoStart, promo_start); |
| 294 prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end); | 306 prefs_->SetDouble(prefs::kNTPPromoEnd, promo_end); |
| 295 prefs_->SetBoolean(prefs::kNTPPromoClosed, false); | 307 prefs_->SetBoolean(prefs::kNTPPromoClosed, false); |
| 296 ScheduleNotification(promo_start, promo_end); | 308 ScheduleNotification(promo_start, promo_end); |
| 297 } | 309 } |
| 298 } | 310 } |
| 299 | 311 |
| 300 void PromoResourceService::UnpackWebStoreSignal( | 312 void PromoResourceService::UnpackWebStoreSignal( |
| 301 const DictionaryValue& parsed_json) { | 313 const DictionaryValue& parsed_json) { |
| 302 DictionaryValue* topic_dict; | 314 DictionaryValue* topic_dict; |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 457 } | 469 } |
| 458 | 470 |
| 459 namespace PromoResourceServiceUtil { | 471 namespace PromoResourceServiceUtil { |
| 460 | 472 |
| 461 bool CanShowPromo(Profile* profile) { | 473 bool CanShowPromo(Profile* profile) { |
| 462 bool promo_closed = false; | 474 bool promo_closed = false; |
| 463 PrefService* prefs = profile->GetPrefs(); | 475 PrefService* prefs = profile->GetPrefs(); |
| 464 if (prefs->HasPrefPath(prefs::kNTPPromoClosed)) | 476 if (prefs->HasPrefPath(prefs::kNTPPromoClosed)) |
| 465 promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed); | 477 promo_closed = prefs->GetBoolean(prefs::kNTPPromoClosed); |
| 466 | 478 |
| 467 // Only show if not synced. | 479 bool is_valid_group = prefs->HasPrefPath(prefs::kNTPPromoGroup) && |
| 468 bool is_synced = | 480 prefs->HasPrefPath(prefs::kNTPPromoGroupMax) && |
| 469 (profile->HasProfileSyncService() && | 481 (prefs->GetInteger(prefs::kNTPPromoGroup) < |
| 470 sync_ui_util::GetStatus( | 482 prefs->GetInteger(prefs::kNTPPromoGroupMax)); |
| 471 profile->GetProfileSyncService()) == sync_ui_util::SYNCED); | |
| 472 | 483 |
| 473 bool is_promo_build = false; | 484 bool is_promo_build = false; |
| 474 if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) { | 485 if (prefs->HasPrefPath(prefs::kNTPPromoBuild)) { |
| 475 // GetChannel hits the registry on Windows. See http://crbug.com/70898. | 486 // GetChannel hits the registry on Windows. See http://crbug.com/70898. |
| 476 base::ThreadRestrictions::ScopedAllowIO allow_io; | 487 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 477 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); | 488 chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
| 478 is_promo_build = PromoResourceService::IsBuildTargeted( | 489 is_promo_build = PromoResourceService::IsBuildTargeted( |
| 479 channel, prefs->GetInteger(prefs::kNTPPromoBuild)); | 490 channel, prefs->GetInteger(prefs::kNTPPromoBuild)); |
| 480 } | 491 } |
| 481 | 492 |
| 482 return !promo_closed && !is_synced && is_promo_build; | 493 return !promo_closed && is_valid_group && is_promo_build; |
|
jstritar
2011/08/24 19:41:48
It might be good to test that CanShowPromo is fals
| |
| 483 } | 494 } |
| 484 | 495 |
| 485 } // namespace PromoResourceServiceUtil | 496 } // namespace PromoResourceServiceUtil |
| OLD | NEW |