| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/notification_promo.h" | 5 #include "chrome/browser/web_resource/notification_promo.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #endif // defined(OS_ANDROID) | 28 #endif // defined(OS_ANDROID) |
| 29 | 29 |
| 30 using content::UserMetricsAction; | 30 using content::UserMetricsAction; |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 const int kDefaultGroupSize = 100; | 34 const int kDefaultGroupSize = 100; |
| 35 | 35 |
| 36 const char promo_server_url[] = "https://clients3.google.com/crsignal/client"; | 36 const char promo_server_url[] = "https://clients3.google.com/crsignal/client"; |
| 37 | 37 |
| 38 // The name of the preference that stores the promotion object. |
| 38 const char kPrefPromoObject[] = "promo"; | 39 const char kPrefPromoObject[] = "promo"; |
| 40 |
| 41 // Keys in the kPrefPromoObject dictionary; used only here. |
| 39 const char kPrefPromoText[] = "text"; | 42 const char kPrefPromoText[] = "text"; |
| 40 #if defined(OS_ANDROID) | 43 const char kPrefPromoPayload[] = "payload"; |
| 41 const char kPrefPromoTextLong[] = "text_long"; | |
| 42 const char kPrefPromoActionType[] = "action_type"; | |
| 43 const char kPrefPromoActionArgs[] = "action_args"; | |
| 44 #endif | |
| 45 const char kPrefPromoStart[] = "start"; | 44 const char kPrefPromoStart[] = "start"; |
| 46 const char kPrefPromoEnd[] = "end"; | 45 const char kPrefPromoEnd[] = "end"; |
| 47 const char kPrefPromoNumGroups[] = "num_groups"; | 46 const char kPrefPromoNumGroups[] = "num_groups"; |
| 48 const char kPrefPromoSegment[] = "segment"; | 47 const char kPrefPromoSegment[] = "segment"; |
| 49 const char kPrefPromoIncrement[] = "increment"; | 48 const char kPrefPromoIncrement[] = "increment"; |
| 50 const char kPrefPromoIncrementFrequency[] = "increment_frequency"; | 49 const char kPrefPromoIncrementFrequency[] = "increment_frequency"; |
| 51 const char kPrefPromoIncrementMax[] = "increment_max"; | 50 const char kPrefPromoIncrementMax[] = "increment_max"; |
| 52 const char kPrefPromoMaxViews[] = "max_views"; | 51 const char kPrefPromoMaxViews[] = "max_views"; |
| 53 const char kPrefPromoGroup[] = "group"; | 52 const char kPrefPromoGroup[] = "group"; |
| 54 const char kPrefPromoViews[] = "views"; | 53 const char kPrefPromoViews[] = "views"; |
| 55 const char kPrefPromoClosed[] = "closed"; | 54 const char kPrefPromoClosed[] = "closed"; |
| 56 const char kPrefPromoGPlusRequired[] = "gplus_required"; | 55 const char kPrefPromoGPlusRequired[] = "gplus_required"; |
| 57 | 56 |
| 58 #if defined(OS_ANDROID) | |
| 59 const int kCurrentMobilePayloadFormatVersion = 3; | |
| 60 #endif // defined(OS_ANDROID) | |
| 61 | |
| 62 // Returns a string suitable for the Promo Server URL 'osname' value. | 57 // Returns a string suitable for the Promo Server URL 'osname' value. |
| 63 std::string PlatformString() { | 58 std::string PlatformString() { |
| 64 #if defined(OS_WIN) | 59 #if defined(OS_WIN) |
| 65 return "win"; | 60 return "win"; |
| 66 #elif defined(OS_IOS) | 61 #elif defined(OS_IOS) |
| 67 // TODO(noyau): add iOS-specific implementation | 62 // TODO(noyau): add iOS-specific implementation |
| 68 const bool isTablet = false; | 63 const bool isTablet = false; |
| 69 return std::string("ios-") + (isTablet ? "tablet" : "phone"); | 64 return std::string("ios-") + (isTablet ? "tablet" : "phone"); |
| 70 #elif defined(OS_MACOSX) | 65 #elif defined(OS_MACOSX) |
| 71 return "mac"; | 66 return "mac"; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 // Convert PromoType to appropriate string. | 115 // Convert PromoType to appropriate string. |
| 121 const char* PromoTypeToString(NotificationPromo::PromoType promo_type) { | 116 const char* PromoTypeToString(NotificationPromo::PromoType promo_type) { |
| 122 for (size_t i = 0; i < arraysize(kPromoMap); ++i) { | 117 for (size_t i = 0; i < arraysize(kPromoMap); ++i) { |
| 123 if (kPromoMap[i].promo_type == promo_type) | 118 if (kPromoMap[i].promo_type == promo_type) |
| 124 return kPromoMap[i].promo_type_str; | 119 return kPromoMap[i].promo_type_str; |
| 125 } | 120 } |
| 126 NOTREACHED(); | 121 NOTREACHED(); |
| 127 return ""; | 122 return ""; |
| 128 } | 123 } |
| 129 | 124 |
| 130 // TODO(achuith): remove this in m23. | 125 // TODO(achuith): http://crbug.com/143773 remove this by m24 |
| 131 void ClearDeprecatedPrefs(PrefService* prefs) { | 126 void ClearDeprecatedPrefs(PrefService* prefs) { |
| 132 prefs->RegisterStringPref(prefs::kNtpPromoLine, | 127 #if defined(OS_ANDROID) || defined(OS_IOS) |
| 128 const char kNtpPromoLineLong[] = "ntp.promo_line_long"; |
| 129 const char kNtpPromoActionType[] = "ntp.promo_action_type"; |
| 130 const char kNtpPromoActionArgs[] = "ntp.promo_action_args"; |
| 131 prefs->RegisterStringPref(kNtpPromoLineLong, |
| 133 std::string(), | 132 std::string(), |
| 134 PrefService::UNSYNCABLE_PREF); | 133 PrefService::UNSYNCABLE_PREF); |
| 135 prefs->ClearPref(prefs::kNtpPromoLine); | 134 prefs->RegisterStringPref(kNtpPromoActionType, |
| 136 #if defined(OS_ANDROID) | |
| 137 prefs->RegisterStringPref(prefs::kNtpPromoLineLong, | |
| 138 std::string(), | 135 std::string(), |
| 139 PrefService::UNSYNCABLE_PREF); | 136 PrefService::UNSYNCABLE_PREF); |
| 140 prefs->RegisterStringPref(prefs::kNtpPromoActionType, | 137 prefs->RegisterListPref(kNtpPromoActionArgs, |
| 138 new base::ListValue, |
| 139 PrefService::UNSYNCABLE_PREF); |
| 140 prefs->ClearPref(kNtpPromoLineLong); |
| 141 prefs->ClearPref(kNtpPromoActionType); |
| 142 prefs->ClearPref(kNtpPromoActionArgs); |
| 143 #endif // defined(OS_ANDROID) || defined(OS_IOS) |
| 144 |
| 145 const char kNtpPromoLine[] = "ntp.promo_line"; |
| 146 const char kNtpPromoStart[] = "ntp.promo_start"; |
| 147 const char kNtpPromoEnd[] = "ntp.promo_end"; |
| 148 const char kNtpPromoNumGroups[] = "ntp.promo_num_groups"; |
| 149 const char kNtpPromoInitialSegment[] = "ntp.promo_initial_segment"; |
| 150 const char kNtpPromoIncrement[] = "ntp.promo_increment"; |
| 151 const char kNtpPromoGroupTimeSlice[] = "ntp.promo_group_timeslice"; |
| 152 const char kNtpPromoGroupMax[] = "ntp.promo_group_max"; |
| 153 const char kNtpPromoClosed[] = "ntp.promo_closed"; |
| 154 const char kNtpPromoGroup[] = "ntp.promo_group"; |
| 155 const char kNtpPromoViews[] = "ntp.promo_views"; |
| 156 const char kNtpPromoViewsMax[] = "ntp.promo_views_max"; |
| 157 const char kNtpPromoGplusRequired[] = "ntp.gplus_required"; |
| 158 |
| 159 prefs->RegisterStringPref(kNtpPromoLine, |
| 141 std::string(), | 160 std::string(), |
| 142 PrefService::UNSYNCABLE_PREF); | 161 PrefService::UNSYNCABLE_PREF); |
| 143 prefs->RegisterListPref(prefs::kNtpPromoActionArgs, | 162 prefs->RegisterDoublePref(kNtpPromoStart, |
| 144 new base::ListValue, | |
| 145 PrefService::UNSYNCABLE_PREF); | |
| 146 prefs->ClearPref(prefs::kNtpPromoLineLong); | |
| 147 prefs->ClearPref(prefs::kNtpPromoActionType); | |
| 148 prefs->ClearPref(prefs::kNtpPromoActionArgs); | |
| 149 #endif // defined(OS_ANDROID) | |
| 150 | |
| 151 prefs->RegisterDoublePref(prefs::kNtpPromoStart, | |
| 152 0, | 163 0, |
| 153 PrefService::UNSYNCABLE_PREF); | 164 PrefService::UNSYNCABLE_PREF); |
| 154 prefs->RegisterDoublePref(prefs::kNtpPromoEnd, | 165 prefs->RegisterDoublePref(kNtpPromoEnd, |
| 155 0, | 166 0, |
| 156 PrefService::UNSYNCABLE_PREF); | 167 PrefService::UNSYNCABLE_PREF); |
| 157 | 168 prefs->RegisterIntegerPref(kNtpPromoNumGroups, |
| 158 prefs->RegisterIntegerPref(prefs::kNtpPromoNumGroups, | |
| 159 0, | 169 0, |
| 160 PrefService::UNSYNCABLE_PREF); | 170 PrefService::UNSYNCABLE_PREF); |
| 161 prefs->RegisterIntegerPref(prefs::kNtpPromoInitialSegment, | 171 prefs->RegisterIntegerPref(kNtpPromoInitialSegment, |
| 162 0, | 172 0, |
| 163 PrefService::UNSYNCABLE_PREF); | 173 PrefService::UNSYNCABLE_PREF); |
| 164 prefs->RegisterIntegerPref(prefs::kNtpPromoIncrement, | 174 prefs->RegisterIntegerPref(kNtpPromoIncrement, |
| 165 1, | 175 1, |
| 166 PrefService::UNSYNCABLE_PREF); | 176 PrefService::UNSYNCABLE_PREF); |
| 167 prefs->RegisterIntegerPref(prefs::kNtpPromoGroupTimeSlice, | 177 prefs->RegisterIntegerPref(kNtpPromoGroupTimeSlice, |
| 168 0, | 178 0, |
| 169 PrefService::UNSYNCABLE_PREF); | 179 PrefService::UNSYNCABLE_PREF); |
| 170 prefs->RegisterIntegerPref(prefs::kNtpPromoGroupMax, | 180 prefs->RegisterIntegerPref(kNtpPromoGroupMax, |
| 171 0, | 181 0, |
| 172 PrefService::UNSYNCABLE_PREF); | 182 PrefService::UNSYNCABLE_PREF); |
| 173 | 183 prefs->RegisterIntegerPref(kNtpPromoViewsMax, |
| 174 prefs->RegisterIntegerPref(prefs::kNtpPromoViewsMax, | |
| 175 0, | 184 0, |
| 176 PrefService::UNSYNCABLE_PREF); | 185 PrefService::UNSYNCABLE_PREF); |
| 177 | 186 prefs->RegisterIntegerPref(kNtpPromoGroup, |
| 178 prefs->RegisterIntegerPref(prefs::kNtpPromoGroup, | |
| 179 0, | 187 0, |
| 180 PrefService::UNSYNCABLE_PREF); | 188 PrefService::UNSYNCABLE_PREF); |
| 181 prefs->RegisterIntegerPref(prefs::kNtpPromoViews, | 189 prefs->RegisterIntegerPref(kNtpPromoViews, |
| 182 0, | 190 0, |
| 183 PrefService::UNSYNCABLE_PREF); | 191 PrefService::UNSYNCABLE_PREF); |
| 184 prefs->RegisterBooleanPref(prefs::kNtpPromoClosed, | 192 prefs->RegisterBooleanPref(kNtpPromoClosed, |
| 193 false, |
| 194 PrefService::UNSYNCABLE_PREF); |
| 195 prefs->RegisterBooleanPref(kNtpPromoGplusRequired, |
| 185 false, | 196 false, |
| 186 PrefService::UNSYNCABLE_PREF); | 197 PrefService::UNSYNCABLE_PREF); |
| 187 | 198 |
| 188 prefs->RegisterBooleanPref(prefs::kNtpPromoGplusRequired, | 199 prefs->ClearPref(kNtpPromoLine); |
| 189 false, | 200 prefs->ClearPref(kNtpPromoStart); |
| 190 PrefService::UNSYNCABLE_PREF); | 201 prefs->ClearPref(kNtpPromoEnd); |
| 202 prefs->ClearPref(kNtpPromoNumGroups); |
| 203 prefs->ClearPref(kNtpPromoInitialSegment); |
| 204 prefs->ClearPref(kNtpPromoIncrement); |
| 205 prefs->ClearPref(kNtpPromoGroupTimeSlice); |
| 206 prefs->ClearPref(kNtpPromoGroupMax); |
| 207 prefs->ClearPref(kNtpPromoViewsMax); |
| 208 prefs->ClearPref(kNtpPromoGroup); |
| 209 prefs->ClearPref(kNtpPromoViews); |
| 210 prefs->ClearPref(kNtpPromoClosed); |
| 211 prefs->ClearPref(kNtpPromoGplusRequired); |
| 212 } |
| 191 | 213 |
| 192 prefs->ClearPref(prefs::kNtpPromoStart); | 214 // Deep-copies a node, replacing any "value" that is a key |
| 193 prefs->ClearPref(prefs::kNtpPromoEnd); | 215 // into "strings" dictionary with its value from "strings". |
| 194 prefs->ClearPref(prefs::kNtpPromoNumGroups); | 216 // E.g. for |
| 195 prefs->ClearPref(prefs::kNtpPromoInitialSegment); | 217 // {promo_action_args:['MSG_SHORT']} + strings:{MSG_SHORT:'yes'} |
| 196 prefs->ClearPref(prefs::kNtpPromoIncrement); | 218 // it will return |
| 197 prefs->ClearPref(prefs::kNtpPromoGroupTimeSlice); | 219 // {promo_action_args:['yes']} |
| 198 prefs->ClearPref(prefs::kNtpPromoGroupMax); | 220 // |node| - a value to be deep copied and resolved. |
| 199 prefs->ClearPref(prefs::kNtpPromoViewsMax); | 221 // |strings| - a dictionary of strings to be used for resolution. |
| 200 prefs->ClearPref(prefs::kNtpPromoGroup); | 222 // Returns a _new_ object that is a deep copy with replacements. |
| 201 prefs->ClearPref(prefs::kNtpPromoViews); | 223 // TODO(aruslan): http://crbug.com/144320 Consider moving it to values.cc/h. |
| 202 prefs->ClearPref(prefs::kNtpPromoClosed); | 224 base::Value* DeepCopyAndResolveStrings( |
| 203 prefs->ClearPref(prefs::kNtpPromoGplusRequired); | 225 const base::Value* node, |
| 226 const base::DictionaryValue* strings) { |
| 227 switch (node->GetType()) { |
| 228 case base::Value::TYPE_LIST: { |
| 229 const base::ListValue* list = static_cast<const base::ListValue*>(node); |
| 230 base::ListValue* copy = new base::ListValue; |
| 231 for (base::ListValue::const_iterator it = list->begin(); |
| 232 it != list->end(); ++it) { |
| 233 base::Value* child_copy = DeepCopyAndResolveStrings(*it, strings); |
| 234 copy->Append(child_copy); |
| 235 } |
| 236 return copy; |
| 237 } |
| 238 |
| 239 case Value::TYPE_DICTIONARY: { |
| 240 const base::DictionaryValue* dict = |
| 241 static_cast<const base::DictionaryValue*>(node); |
| 242 base::DictionaryValue* copy = new base::DictionaryValue; |
| 243 for (base::DictionaryValue::key_iterator it = dict->begin_keys(); |
| 244 it != dict->end_keys(); ++it) { |
| 245 const base::Value* child = NULL; |
| 246 bool rv = dict->GetWithoutPathExpansion(*it, &child); |
| 247 DCHECK(rv); |
| 248 base::Value* child_copy = DeepCopyAndResolveStrings(child, strings); |
| 249 copy->SetWithoutPathExpansion(*it, child_copy); |
| 250 } |
| 251 return copy; |
| 252 } |
| 253 |
| 254 case Value::TYPE_STRING: { |
| 255 const base::StringValue* str = |
| 256 static_cast<const base::StringValue*>(node); |
| 257 std::string value; |
| 258 bool rv = str->GetAsString(&value); |
| 259 DCHECK(rv); |
| 260 std::string actual_value; |
| 261 if (!strings || !strings->GetString(value, &actual_value)) |
| 262 actual_value = value; |
| 263 return new base::StringValue(actual_value); |
| 264 } |
| 265 |
| 266 default: |
| 267 // For everything else, just make a copy. |
| 268 return node->DeepCopy(); |
| 269 } |
| 204 } | 270 } |
| 205 | 271 |
| 206 } // namespace | 272 } // namespace |
| 207 | 273 |
| 208 NotificationPromo::NotificationPromo(Profile* profile) | 274 NotificationPromo::NotificationPromo(Profile* profile) |
| 209 : profile_(profile), | 275 : profile_(profile), |
| 210 prefs_(profile_->GetPrefs()), | 276 prefs_(profile_->GetPrefs()), |
| 211 promo_type_(NO_PROMO), | 277 promo_type_(NO_PROMO), |
| 212 #if defined(OS_ANDROID) | 278 promo_payload_(new base::DictionaryValue()), |
| 213 promo_action_args_(new base::ListValue), | |
| 214 #endif | |
| 215 start_(0.0), | 279 start_(0.0), |
| 216 end_(0.0), | 280 end_(0.0), |
| 217 num_groups_(kDefaultGroupSize), | 281 num_groups_(kDefaultGroupSize), |
| 218 initial_segment_(0), | 282 initial_segment_(0), |
| 219 increment_(1), | 283 increment_(1), |
| 220 time_slice_(0), | 284 time_slice_(0), |
| 221 max_group_(0), | 285 max_group_(0), |
| 222 max_views_(0), | 286 max_views_(0), |
| 223 group_(0), | 287 group_(0), |
| 224 views_(0), | 288 views_(0), |
| (...skipping 13 matching lines...) Expand all Loading... |
| 238 if (!json.GetList(PromoTypeToString(promo_type_), &promo_list)) { | 302 if (!json.GetList(PromoTypeToString(promo_type_), &promo_list)) { |
| 239 LOG(ERROR) << "Malformed JSON: not " << PromoTypeToString(promo_type_); | 303 LOG(ERROR) << "Malformed JSON: not " << PromoTypeToString(promo_type_); |
| 240 return; | 304 return; |
| 241 } | 305 } |
| 242 | 306 |
| 243 // No support for multiple promos yet. Only consider the first one. | 307 // No support for multiple promos yet. Only consider the first one. |
| 244 const DictionaryValue* promo = NULL; | 308 const DictionaryValue* promo = NULL; |
| 245 if (!promo_list->GetDictionary(0, &promo)) | 309 if (!promo_list->GetDictionary(0, &promo)) |
| 246 return; | 310 return; |
| 247 | 311 |
| 248 // Strings. Assume the first one is the promo text. | |
| 249 const DictionaryValue* strings = NULL; | |
| 250 if (promo->GetDictionary("strings", &strings)) { | |
| 251 #if !defined(OS_ANDROID) | |
| 252 DictionaryValue::Iterator iter(*strings); | |
| 253 iter.value().GetAsString(&promo_text_); | |
| 254 DVLOG(1) << "promo_text_=" << promo_text_; | |
| 255 #endif // defined(OS_ANDROID) | |
| 256 } | |
| 257 | |
| 258 // Date. | 312 // Date. |
| 259 const ListValue* date_list = NULL; | 313 const ListValue* date_list = NULL; |
| 260 if (promo->GetList("date", &date_list)) { | 314 if (promo->GetList("date", &date_list)) { |
| 261 const DictionaryValue* date; | 315 const DictionaryValue* date; |
| 262 if (date_list->GetDictionary(0, &date)) { | 316 if (date_list->GetDictionary(0, &date)) { |
| 263 std::string time_str; | 317 std::string time_str; |
| 264 base::Time time; | 318 base::Time time; |
| 265 if (date->GetString("start", &time_str) && | 319 if (date->GetString("start", &time_str) && |
| 266 base::Time::FromString(time_str.c_str(), &time)) { | 320 base::Time::FromString(time_str.c_str(), &time)) { |
| 267 start_ = time.ToDoubleT(); | 321 start_ = time.ToDoubleT(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 286 grouping->GetInteger("increment_frequency", &time_slice_); | 340 grouping->GetInteger("increment_frequency", &time_slice_); |
| 287 grouping->GetInteger("increment_max", &max_group_); | 341 grouping->GetInteger("increment_max", &max_group_); |
| 288 | 342 |
| 289 DVLOG(1) << "num_groups_ = " << num_groups_ | 343 DVLOG(1) << "num_groups_ = " << num_groups_ |
| 290 << ", initial_segment_ = " << initial_segment_ | 344 << ", initial_segment_ = " << initial_segment_ |
| 291 << ", increment_ = " << increment_ | 345 << ", increment_ = " << increment_ |
| 292 << ", time_slice_ = " << time_slice_ | 346 << ", time_slice_ = " << time_slice_ |
| 293 << ", max_group_ = " << max_group_; | 347 << ", max_group_ = " << max_group_; |
| 294 } | 348 } |
| 295 | 349 |
| 350 // Strings. |
| 351 const DictionaryValue* strings = NULL; |
| 352 promo->GetDictionary("strings", &strings); |
| 353 |
| 296 // Payload. | 354 // Payload. |
| 297 const DictionaryValue* payload = NULL; | 355 const DictionaryValue* payload = NULL; |
| 298 if (promo->GetDictionary("payload", &payload)) { | 356 if (promo->GetDictionary("payload", &payload)) { |
| 299 payload->GetBoolean("gplus_required", &gplus_required_); | 357 payload->GetBoolean("gplus_required", &gplus_required_); |
| 358 DVLOG(1) << "gplus_required_ = " << gplus_required_; |
| 300 | 359 |
| 301 DVLOG(1) << "gplus_required_ = " << gplus_required_; | 360 base::Value* ppcopy = DeepCopyAndResolveStrings(payload, strings); |
| 361 DCHECK(ppcopy && ppcopy->IsType(base::Value::TYPE_DICTIONARY)); |
| 362 promo_payload_.reset(static_cast<base::DictionaryValue*>(ppcopy)); |
| 302 } | 363 } |
| 303 | 364 |
| 365 if (!promo_payload_->GetString("promo_message_short", &promo_text_) && |
| 366 strings) { |
| 367 // For compatibility with the legacy desktop version, |
| 368 // if no |payload.promo_message_short| is specified, |
| 369 // the first string in |strings| is used. |
| 370 DictionaryValue::Iterator iter(*strings); |
| 371 iter.value().GetAsString(&promo_text_); |
| 372 } |
| 373 DVLOG(1) << "promo_text_=" << promo_text_; |
| 374 |
| 304 promo->GetInteger("max_views", &max_views_); | 375 promo->GetInteger("max_views", &max_views_); |
| 305 DVLOG(1) << "max_views_ " << max_views_; | 376 DVLOG(1) << "max_views_ " << max_views_; |
| 306 | 377 |
| 307 #if defined(OS_ANDROID) | |
| 308 int payload_version = 0; | |
| 309 if (!payload) { | |
| 310 LOG(ERROR) << "Malformed JSON: no payload"; | |
| 311 return; | |
| 312 } | |
| 313 if (!strings) { | |
| 314 LOG(ERROR) << "Malformed JSON: no strings"; | |
| 315 return; | |
| 316 } | |
| 317 if (!payload->GetInteger("payload_format_version", &payload_version) || | |
| 318 payload_version != kCurrentMobilePayloadFormatVersion) { | |
| 319 LOG(ERROR) << "Unsupported promo payload_format_version " << payload_version | |
| 320 << "; expected " << kCurrentMobilePayloadFormatVersion; | |
| 321 return; | |
| 322 } | |
| 323 std::string promo_key_short; | |
| 324 std::string promo_key_long; | |
| 325 if (!payload->GetString("promo_message_short", &promo_key_short) || | |
| 326 !payload->GetString("promo_message_long", &promo_key_long) || | |
| 327 !strings->GetString(promo_key_short, &promo_text_) || | |
| 328 !strings->GetString(promo_key_long, &promo_text_long_)) { | |
| 329 LOG(ERROR) << "Malformed JSON: no promo_message_short or _long"; | |
| 330 return; | |
| 331 } | |
| 332 payload->GetString("promo_action_type", &promo_action_type_); | |
| 333 // We need to be idempotent as the tests call us more than once. | |
| 334 promo_action_args_.reset(new base::ListValue); | |
| 335 const ListValue* args; | |
| 336 if (payload->GetList("promo_action_args", &args)) { | |
| 337 // JSON format for args: "promo_action_args" : [ "<arg1>", "<arg2>"... ] | |
| 338 // Every value comes from "strings" dictionary, either directly or not. | |
| 339 // Every arg is either directly a key into "strings" dictionary, | |
| 340 // or a key into "payload" dictionary with the value that is a key into | |
| 341 // "strings" dictionary. | |
| 342 for (std::size_t i = 0; i < args->GetSize(); ++i) { | |
| 343 std::string name, key, value; | |
| 344 if (!args->GetString(i, &name) || | |
| 345 !(strings->GetString(name, &value) || | |
| 346 (payload->GetString(name, &key) && | |
| 347 strings->GetString(key, &value)))) { | |
| 348 LOG(ERROR) << "Malformed JSON: failed to parse promo_action_args"; | |
| 349 return; | |
| 350 } | |
| 351 promo_action_args_->Append(base::Value::CreateStringValue(value)); | |
| 352 } | |
| 353 } | |
| 354 #endif // defined(OS_ANDROID) | |
| 355 | |
| 356 CheckForNewNotification(); | 378 CheckForNewNotification(); |
| 357 } | 379 } |
| 358 | 380 |
| 359 void NotificationPromo::CheckForNewNotification() { | 381 void NotificationPromo::CheckForNewNotification() { |
| 360 NotificationPromo old_promo(profile_); | 382 NotificationPromo old_promo(profile_); |
| 361 old_promo.InitFromPrefs(promo_type_); | 383 old_promo.InitFromPrefs(promo_type_); |
| 362 const double old_start = old_promo.start_; | 384 const double old_start = old_promo.start_; |
| 363 const double old_end = old_promo.end_; | 385 const double old_end = old_promo.end_; |
| 364 const std::string old_promo_text = old_promo.promo_text_; | 386 const std::string old_promo_text = old_promo.promo_text_; |
| 365 | 387 |
| 366 new_notification_ = | 388 new_notification_ = |
| 367 old_start != start_ || old_end != end_ || old_promo_text != promo_text_; | 389 old_start != start_ || old_end != end_ || old_promo_text != promo_text_; |
| 368 if (new_notification_) | 390 if (new_notification_) |
| 369 OnNewNotification(); | 391 OnNewNotification(); |
| 370 } | 392 } |
| 371 | 393 |
| 372 void NotificationPromo::OnNewNotification() { | 394 void NotificationPromo::OnNewNotification() { |
| 373 DVLOG(1) << "OnNewNotification"; | 395 DVLOG(1) << "OnNewNotification"; |
| 374 // Create a new promo group. | 396 // Create a new promo group. |
| 375 group_ = base::RandInt(0, num_groups_ - 1); | 397 group_ = base::RandInt(0, num_groups_ - 1); |
| 376 WritePrefs(); | 398 WritePrefs(); |
| 377 } | 399 } |
| 378 | 400 |
| 379 // static | 401 // static |
| 380 void NotificationPromo::RegisterUserPrefs(PrefService* prefs) { | 402 void NotificationPromo::RegisterUserPrefs(PrefService* prefs) { |
| 381 ClearDeprecatedPrefs(prefs); | 403 ClearDeprecatedPrefs(prefs); |
| 382 prefs->RegisterDictionaryPref("promo", | 404 prefs->RegisterDictionaryPref(kPrefPromoObject, |
| 383 new base::DictionaryValue, | 405 new base::DictionaryValue, |
| 384 PrefService::UNSYNCABLE_PREF); | 406 PrefService::UNSYNCABLE_PREF); |
| 385 } | 407 } |
| 386 | 408 |
| 387 void NotificationPromo::WritePrefs() { | 409 void NotificationPromo::WritePrefs() { |
| 388 DVLOG(1) << "WritePrefs"; | 410 DVLOG(1) << "WritePrefs"; |
| 389 base::DictionaryValue* ntp_promo = new base::DictionaryValue; | 411 base::DictionaryValue* ntp_promo = new base::DictionaryValue; |
| 390 ntp_promo->SetString(kPrefPromoText, promo_text_); | 412 ntp_promo->SetString(kPrefPromoText, promo_text_); |
| 391 #if defined(OS_ANDROID) | 413 ntp_promo->Set(kPrefPromoPayload, promo_payload_->DeepCopy()); |
| 392 ntp_promo->SetString(kPrefPromoTextLong, promo_text_long_); | |
| 393 ntp_promo->SetString(kPrefPromoActionType, promo_action_type_); | |
| 394 DCHECK(promo_action_args_.get()); | |
| 395 ntp_promo->Set(kPrefPromoActionArgs, promo_action_args_->DeepCopy()); | |
| 396 #endif // defined(OS_ANDROID) | |
| 397 ntp_promo->SetDouble(kPrefPromoStart, start_); | 414 ntp_promo->SetDouble(kPrefPromoStart, start_); |
| 398 ntp_promo->SetDouble(kPrefPromoEnd, end_); | 415 ntp_promo->SetDouble(kPrefPromoEnd, end_); |
| 399 | 416 |
| 400 ntp_promo->SetInteger(kPrefPromoNumGroups, num_groups_); | 417 ntp_promo->SetInteger(kPrefPromoNumGroups, num_groups_); |
| 401 ntp_promo->SetInteger(kPrefPromoSegment, initial_segment_); | 418 ntp_promo->SetInteger(kPrefPromoSegment, initial_segment_); |
| 402 ntp_promo->SetInteger(kPrefPromoIncrement, increment_); | 419 ntp_promo->SetInteger(kPrefPromoIncrement, increment_); |
| 403 ntp_promo->SetInteger(kPrefPromoIncrementFrequency, time_slice_); | 420 ntp_promo->SetInteger(kPrefPromoIncrementFrequency, time_slice_); |
| 404 ntp_promo->SetInteger(kPrefPromoIncrementMax, max_group_); | 421 ntp_promo->SetInteger(kPrefPromoIncrementMax, max_group_); |
| 405 | 422 |
| 406 ntp_promo->SetInteger(kPrefPromoMaxViews, max_views_); | 423 ntp_promo->SetInteger(kPrefPromoMaxViews, max_views_); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 419 prefs_->Set(kPrefPromoObject, promo_dict); | 436 prefs_->Set(kPrefPromoObject, promo_dict); |
| 420 } | 437 } |
| 421 | 438 |
| 422 void NotificationPromo::InitFromPrefs(PromoType promo_type) { | 439 void NotificationPromo::InitFromPrefs(PromoType promo_type) { |
| 423 promo_type_ = promo_type; | 440 promo_type_ = promo_type; |
| 424 const base::DictionaryValue* promo_dict = | 441 const base::DictionaryValue* promo_dict = |
| 425 prefs_->GetDictionary(kPrefPromoObject); | 442 prefs_->GetDictionary(kPrefPromoObject); |
| 426 if (!promo_dict) | 443 if (!promo_dict) |
| 427 return; | 444 return; |
| 428 | 445 |
| 429 const base::ListValue* promo_list(NULL); | 446 const base::ListValue* promo_list = NULL; |
| 430 promo_dict->GetList(PromoTypeToString(promo_type_), &promo_list); | 447 promo_dict->GetList(PromoTypeToString(promo_type_), &promo_list); |
| 431 if (!promo_list) | 448 if (!promo_list) |
| 432 return; | 449 return; |
| 433 | 450 |
| 434 const base::DictionaryValue* ntp_promo(NULL); | 451 const base::DictionaryValue* ntp_promo = NULL; |
| 435 promo_list->GetDictionary(0, &ntp_promo); | 452 promo_list->GetDictionary(0, &ntp_promo); |
| 436 if (!ntp_promo) | 453 if (!ntp_promo) |
| 437 return; | 454 return; |
| 438 | 455 |
| 439 ntp_promo->GetString(kPrefPromoText, &promo_text_); | 456 ntp_promo->GetString(kPrefPromoText, &promo_text_); |
| 440 #if defined(OS_ANDROID) | 457 const base::DictionaryValue* promo_payload = NULL; |
| 441 ntp_promo->GetString(kPrefPromoTextLong, &promo_text_long_); | 458 if (ntp_promo->GetDictionary(kPrefPromoPayload, &promo_payload)) |
| 442 ntp_promo->GetString(kPrefPromoActionType, &promo_action_type_); | 459 promo_payload_.reset(promo_payload->DeepCopy()); |
| 443 const base::ListValue* lv(NULL); | |
| 444 ntp_promo->GetList(kPrefPromoActionArgs, &lv); | |
| 445 DCHECK(lv != NULL); | |
| 446 promo_action_args_.reset(lv->DeepCopy()); | |
| 447 #endif // defined(OS_ANDROID) | |
| 448 | 460 |
| 449 ntp_promo->GetDouble(kPrefPromoStart, &start_); | 461 ntp_promo->GetDouble(kPrefPromoStart, &start_); |
| 450 ntp_promo->GetDouble(kPrefPromoEnd, &end_); | 462 ntp_promo->GetDouble(kPrefPromoEnd, &end_); |
| 451 | 463 |
| 452 ntp_promo->GetInteger(kPrefPromoNumGroups, &num_groups_); | 464 ntp_promo->GetInteger(kPrefPromoNumGroups, &num_groups_); |
| 453 ntp_promo->GetInteger(kPrefPromoSegment, &initial_segment_); | 465 ntp_promo->GetInteger(kPrefPromoSegment, &initial_segment_); |
| 454 ntp_promo->GetInteger(kPrefPromoIncrement, &increment_); | 466 ntp_promo->GetInteger(kPrefPromoIncrement, &increment_); |
| 455 ntp_promo->GetInteger(kPrefPromoIncrementFrequency, &time_slice_); | 467 ntp_promo->GetInteger(kPrefPromoIncrementFrequency, &time_slice_); |
| 456 ntp_promo->GetInteger(kPrefPromoIncrementMax, &max_group_); | 468 ntp_promo->GetInteger(kPrefPromoIncrementMax, &max_group_); |
| 457 | 469 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 if (group_ < initial_segment_) | 537 if (group_ < initial_segment_) |
| 526 return start_; | 538 return start_; |
| 527 return start_ + | 539 return start_ + |
| 528 std::ceil(static_cast<float>(group_ - initial_segment_ + 1) / increment_) | 540 std::ceil(static_cast<float>(group_ - initial_segment_ + 1) / increment_) |
| 529 * time_slice_; | 541 * time_slice_; |
| 530 } | 542 } |
| 531 | 543 |
| 532 double NotificationPromo::EndTime() const { | 544 double NotificationPromo::EndTime() const { |
| 533 return end_; | 545 return end_; |
| 534 } | 546 } |
| OLD | NEW |