15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_resource/promo_resource_service.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 99ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h" 157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_resource/notification_promo.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "components/user_prefs/pref_registry_syncable.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "url/gurl.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delay on first fetch so we don't interfere with startup. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStartResourceFetchDelay = 5000; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delay between calls to fetch the promo json: 6 hours in production, and 3 min 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in debug. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kCacheUpdateDelay = 6 * 60 * 60 * 1000; 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTestCacheUpdateDelay = 3 * 60 * 1000; 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The promotion type used for Unpack() and ScheduleNotificationOnInit(). 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const NotificationPromo::PromoType kValidPromoTypes[] = { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_ANDROID) || defined(OS_IOS) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationPromo::MOBILE_NTP_SYNC_PROMO, 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationPromo::NTP_NOTIFICATION_PROMO, 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationPromo::NTP_BUBBLE_PROMO, 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL GetPromoResourceURL() { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string promo_server_url = CommandLine::ForCurrentProcess()-> 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSwitchValueASCII(switches::kPromoServerURL); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return promo_server_url.empty() ? 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NotificationPromo::PromoServerURL() : GURL(promo_server_url); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsTest() { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CommandLine::ForCurrentProcess()->HasSwitch(switches::kPromoServerURL); 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetCacheUpdateDelay() { 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return IsTest() ? kTestCacheUpdateDelay : kCacheUpdateDelay; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PromoResourceService::RegisterPrefs(PrefRegistrySimple* registry) { 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registry->RegisterStringPref(prefs::kNtpPromoResourceCacheUpdate, "0"); 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationPromo::RegisterPrefs(registry); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PromoResourceService::RegisterProfilePrefs( 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_prefs::PrefRegistrySyncable* registry) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // TODO(dbeam): This is registered only for migration; remove in M28 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // when all prefs have been cleared. http://crbug.com/168887 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) registry->RegisterStringPref( 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) prefs::kNtpPromoResourceCacheUpdate, 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) "0", 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch NotificationPromo::RegisterProfilePrefs(registry); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PromoResourceService::MigrateUserPrefs(PrefService* user_prefs) { 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) user_prefs->ClearPref(prefs::kNtpPromoResourceCacheUpdate); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationPromo::MigrateUserPrefs(user_prefs); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PromoResourceService::PromoResourceService() 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : WebResourceService(g_browser_process->local_state(), 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPromoResourceURL(), 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) true, // append locale to URL 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) prefs::kNtpPromoResourceCacheUpdate, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kStartResourceFetchDelay, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetCacheUpdateDelay()), 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNotificationOnInit(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PromoResourceService::~PromoResourceService() { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PromoResourceService::ScheduleNotification( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const NotificationPromo& notification_promo) { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double promo_start = notification_promo.StartTimeForGroup(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const double promo_end = notification_promo.EndTime(); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (promo_start > 0 && promo_end > 0) { 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int64 ms_until_start = 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int64>((base::Time::FromDoubleT( 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) promo_start) - base::Time::Now()).InMilliseconds()); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int64 ms_until_end = 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<int64>((base::Time::FromDoubleT( 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) promo_end) - base::Time::Now()).InMilliseconds()); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ms_until_start > 0) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Schedule the next notification to happen at the start of promotion. 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostNotification(ms_until_start); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (ms_until_end > 0) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ms_until_start <= 0) { 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The promo is active. Notify immediately. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostNotification(0); 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Schedule the next notification to happen at the end of promotion. 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostNotification(ms_until_end); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The promo (if any) has finished. Notify immediately. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostNotification(0); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The promo (if any) was apparently cancelled. Notify immediately. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PostNotification(0); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PromoResourceService::ScheduleNotificationOnInit() { 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the promo start is in the future, set a notification task to 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invalidate the NTP cache at the time of the promo start. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kValidPromoTypes); ++i) { 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationPromo notification_promo; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_promo.InitFromPrefs(kValidPromoTypes[i]); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNotification(notification_promo); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PromoResourceService::PostNotification(int64 delay_ms) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that this could cause re-issuing a notification every time 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we receive an update from a server if something goes wrong. 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Given that this couldn't happen more frequently than every 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // kCacheUpdateDelay milliseconds, we should be fine. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(achuith): This crashes if we post delay_ms = 0 to the message loop. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // during startup. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (delay_ms > 0) { 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) base::MessageLoop::current()->PostDelayedTask( 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&PromoResourceService::PromoResourceStateChange, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr()), 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeDelta::FromMilliseconds(delay_ms)); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (delay_ms == 0) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PromoResourceStateChange(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PromoResourceService::PromoResourceStateChange() { 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService* service = 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::current(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) service->Notify(chrome::NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Source<WebResourceService>(this), 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::NoDetails()); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PromoResourceService::Unpack(const DictionaryValue& parsed_json) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (size_t i = 0; i < arraysize(kValidPromoTypes); ++i) { 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NotificationPromo notification_promo; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) notification_promo.InitFromJson(parsed_json, kValidPromoTypes[i]); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (notification_promo.new_notification()) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNotification(notification_promo); 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 174