• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/web_resource/promo_resource_service.h"
6 
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/web_resource/notification_promo.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/pref_names.h"
19 #include "components/pref_registry/pref_registry_syncable.h"
20 #include "content/public/browser/notification_service.h"
21 #include "url/gurl.h"
22 
23 namespace {
24 
25 // Delay on first fetch so we don't interfere with startup.
26 const int kStartResourceFetchDelay = 5000;
27 
28 // Delay between calls to fetch the promo json: 6 hours in production, and 3 min
29 // in debug.
30 const int kCacheUpdateDelay = 6 * 60 * 60 * 1000;
31 const int kTestCacheUpdateDelay = 3 * 60 * 1000;
32 
33 // The promotion type used for Unpack() and ScheduleNotificationOnInit().
34 const NotificationPromo::PromoType kValidPromoTypes[] = {
35 #if defined(OS_ANDROID) || defined(OS_IOS)
36     NotificationPromo::MOBILE_NTP_SYNC_PROMO,
37 #if defined(OS_IOS)
38     NotificationPromo::MOBILE_NTP_WHATS_NEW_PROMO,
39 #endif  // defined(OS_IOS)
40 #else
41     NotificationPromo::NTP_NOTIFICATION_PROMO,
42     NotificationPromo::NTP_BUBBLE_PROMO,
43 #endif
44 };
45 
GetPromoResourceURL()46 GURL GetPromoResourceURL() {
47   const std::string promo_server_url = CommandLine::ForCurrentProcess()->
48       GetSwitchValueASCII(switches::kPromoServerURL);
49   return promo_server_url.empty() ?
50       NotificationPromo::PromoServerURL() : GURL(promo_server_url);
51 }
52 
IsTest()53 bool IsTest() {
54   return CommandLine::ForCurrentProcess()->HasSwitch(switches::kPromoServerURL);
55 }
56 
GetCacheUpdateDelay()57 int GetCacheUpdateDelay() {
58   return IsTest() ? kTestCacheUpdateDelay : kCacheUpdateDelay;
59 }
60 
61 }  // namespace
62 
63 // static
RegisterPrefs(PrefRegistrySimple * registry)64 void PromoResourceService::RegisterPrefs(PrefRegistrySimple* registry) {
65   registry->RegisterStringPref(prefs::kNtpPromoResourceCacheUpdate, "0");
66   NotificationPromo::RegisterPrefs(registry);
67 }
68 
69 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)70 void PromoResourceService::RegisterProfilePrefs(
71     user_prefs::PrefRegistrySyncable* registry) {
72   // TODO(dbeam): This is registered only for migration; remove in M28
73   // when all prefs have been cleared.  http://crbug.com/168887
74   registry->RegisterStringPref(
75       prefs::kNtpPromoResourceCacheUpdate,
76       "0",
77       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
78   NotificationPromo::RegisterProfilePrefs(registry);
79 }
80 
81 // static
MigrateUserPrefs(PrefService * user_prefs)82 void PromoResourceService::MigrateUserPrefs(PrefService* user_prefs) {
83   user_prefs->ClearPref(prefs::kNtpPromoResourceCacheUpdate);
84   NotificationPromo::MigrateUserPrefs(user_prefs);
85 }
86 
PromoResourceService()87 PromoResourceService::PromoResourceService()
88     : WebResourceService(g_browser_process->local_state(),
89                          GetPromoResourceURL(),
90                          true,  // append locale to URL
91                          prefs::kNtpPromoResourceCacheUpdate,
92                          kStartResourceFetchDelay,
93                          GetCacheUpdateDelay()),
94                          weak_ptr_factory_(this) {
95   ScheduleNotificationOnInit();
96 }
97 
~PromoResourceService()98 PromoResourceService::~PromoResourceService() {
99 }
100 
ScheduleNotification(const NotificationPromo & notification_promo)101 void PromoResourceService::ScheduleNotification(
102     const NotificationPromo& notification_promo) {
103   const double promo_start = notification_promo.StartTimeForGroup();
104   const double promo_end = notification_promo.EndTime();
105 
106   if (promo_start > 0 && promo_end > 0) {
107     const int64 ms_until_start =
108         static_cast<int64>((base::Time::FromDoubleT(
109             promo_start) - base::Time::Now()).InMilliseconds());
110     const int64 ms_until_end =
111         static_cast<int64>((base::Time::FromDoubleT(
112             promo_end) - base::Time::Now()).InMilliseconds());
113     if (ms_until_start > 0) {
114       // Schedule the next notification to happen at the start of promotion.
115       PostNotification(ms_until_start);
116     } else if (ms_until_end > 0) {
117       if (ms_until_start <= 0) {
118         // The promo is active.  Notify immediately.
119         PostNotification(0);
120       }
121       // Schedule the next notification to happen at the end of promotion.
122       PostNotification(ms_until_end);
123     } else {
124       // The promo (if any) has finished.  Notify immediately.
125       PostNotification(0);
126     }
127   } else {
128       // The promo (if any) was apparently cancelled.  Notify immediately.
129       PostNotification(0);
130   }
131 }
132 
ScheduleNotificationOnInit()133 void PromoResourceService::ScheduleNotificationOnInit() {
134   // If the promo start is in the future, set a notification task to
135   // invalidate the NTP cache at the time of the promo start.
136   for (size_t i = 0; i < arraysize(kValidPromoTypes); ++i) {
137     NotificationPromo notification_promo;
138     notification_promo.InitFromPrefs(kValidPromoTypes[i]);
139     ScheduleNotification(notification_promo);
140   }
141 }
142 
PostNotification(int64 delay_ms)143 void PromoResourceService::PostNotification(int64 delay_ms) {
144   // Note that this could cause re-issuing a notification every time
145   // we receive an update from a server if something goes wrong.
146   // Given that this couldn't happen more frequently than every
147   // kCacheUpdateDelay milliseconds, we should be fine.
148   // TODO(achuith): This crashes if we post delay_ms = 0 to the message loop.
149   // during startup.
150   if (delay_ms > 0) {
151     base::MessageLoop::current()->PostDelayedTask(
152         FROM_HERE,
153         base::Bind(&PromoResourceService::PromoResourceStateChange,
154                    weak_ptr_factory_.GetWeakPtr()),
155         base::TimeDelta::FromMilliseconds(delay_ms));
156   } else if (delay_ms == 0) {
157     PromoResourceStateChange();
158   }
159 }
160 
PromoResourceStateChange()161 void PromoResourceService::PromoResourceStateChange() {
162   content::NotificationService* service =
163       content::NotificationService::current();
164   service->Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED,
165                   content::Source<WebResourceService>(this),
166                   content::NotificationService::NoDetails());
167 }
168 
Unpack(const base::DictionaryValue & parsed_json)169 void PromoResourceService::Unpack(const base::DictionaryValue& parsed_json) {
170   for (size_t i = 0; i < arraysize(kValidPromoTypes); ++i) {
171     NotificationPromo notification_promo;
172     notification_promo.InitFromJson(parsed_json, kValidPromoTypes[i]);
173     if (notification_promo.new_notification())
174       ScheduleNotification(notification_promo);
175   }
176 }
177