Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / notifications / extension_welcome_notification.cc
blob383107fe18b1cced99e481215b26fefc14ffa312
1 // Copyright 2014 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.
5 #include "chrome/browser/notifications/extension_welcome_notification.h"
7 #include "base/guid.h"
8 #include "base/lazy_instance.h"
9 #include "base/location.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/notifications/notification.h"
16 #include "chrome/browser/prefs/pref_service_syncable_util.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser_navigator.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "components/syncable_prefs/pref_service_syncable.h"
24 #include "grit/theme_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/message_center/message_center.h"
28 #include "ui/message_center/notification.h"
29 #include "ui/message_center/notification_delegate.h"
30 #include "ui/message_center/notification_types.h"
32 const int ExtensionWelcomeNotification::kRequestedShowTimeDays = 14;
33 const char ExtensionWelcomeNotification::kChromeNowExtensionID[] =
34 "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
36 namespace {
38 class NotificationCallbacks
39 : public message_center::NotificationDelegate {
40 public:
41 NotificationCallbacks(
42 Profile* profile,
43 const message_center::NotifierId notifier_id,
44 const std::string& welcome_notification_id,
45 ExtensionWelcomeNotification::Delegate* delegate)
46 : profile_(profile),
47 notifier_id_(notifier_id.type, notifier_id.id),
48 welcome_notification_id_(welcome_notification_id),
49 delegate_(delegate) {
52 // Overridden from NotificationDelegate:
53 void Close(bool by_user) override {
54 if (by_user) {
55 // Setting the preference here may cause the notification erasing
56 // to reenter. Posting a task avoids this issue.
57 delegate_->PostTask(
58 FROM_HERE,
59 base::Bind(&NotificationCallbacks::MarkAsDismissed, this));
63 void ButtonClick(int index) override {
64 if (index == 0) {
65 OpenNotificationLearnMoreTab();
66 } else if (index == 1) {
67 DisableNotificationProvider();
68 Close(true);
69 } else {
70 NOTREACHED();
74 private:
75 void MarkAsDismissed() {
76 profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissedLocal,
77 true);
80 void OpenNotificationLearnMoreTab() {
81 chrome::NavigateParams params(
82 profile_,
83 GURL(chrome::kNotificationWelcomeLearnMoreURL),
84 ui::PAGE_TRANSITION_LINK);
85 params.disposition = NEW_FOREGROUND_TAB;
86 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
87 chrome::Navigate(&params);
90 void DisableNotificationProvider() {
91 message_center::Notifier notifier(notifier_id_, base::string16(), true);
92 message_center::MessageCenter* message_center =
93 delegate_->GetMessageCenter();
94 message_center->DisableNotificationsByNotifier(notifier_id_);
95 message_center->RemoveNotification(welcome_notification_id_, false);
96 message_center->GetNotifierSettingsProvider()->SetNotifierEnabled(
97 notifier, false);
100 ~NotificationCallbacks() override {}
102 Profile* const profile_;
104 const message_center::NotifierId notifier_id_;
106 std::string welcome_notification_id_;
108 // Weak ref owned by ExtensionWelcomeNotification.
109 ExtensionWelcomeNotification::Delegate* const delegate_;
111 DISALLOW_COPY_AND_ASSIGN(NotificationCallbacks);
114 class DefaultDelegate : public ExtensionWelcomeNotification::Delegate {
115 public:
116 DefaultDelegate() {}
118 message_center::MessageCenter* GetMessageCenter() override {
119 return g_browser_process->message_center();
122 base::Time GetCurrentTime() override { return base::Time::Now(); }
124 void PostTask(const tracked_objects::Location& from_here,
125 const base::Closure& task) override {
126 base::ThreadTaskRunnerHandle::Get()->PostTask(from_here, task);
129 private:
130 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
133 } // namespace
135 ExtensionWelcomeNotification::ExtensionWelcomeNotification(
136 Profile* const profile,
137 ExtensionWelcomeNotification::Delegate* const delegate)
138 : notifier_id_(message_center::NotifierId::APPLICATION,
139 kChromeNowExtensionID),
140 profile_(profile),
141 delegate_(delegate) {
142 welcome_notification_dismissed_pref_.Init(
143 prefs::kWelcomeNotificationDismissed,
144 profile_->GetPrefs(),
145 base::Bind(
146 &ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged,
147 base::Unretained(this)));
148 welcome_notification_dismissed_local_pref_.Init(
149 prefs::kWelcomeNotificationDismissedLocal,
150 profile_->GetPrefs());
153 // static
154 ExtensionWelcomeNotification* ExtensionWelcomeNotification::Create(
155 Profile* const profile) {
156 return Create(profile, new DefaultDelegate());
159 // static
160 ExtensionWelcomeNotification* ExtensionWelcomeNotification::Create(
161 Profile* const profile, Delegate* const delegate) {
162 return new ExtensionWelcomeNotification(profile, delegate);
165 ExtensionWelcomeNotification::~ExtensionWelcomeNotification() {
166 if (delayed_notification_) {
167 delayed_notification_.reset();
168 PrefServiceSyncableFromProfile(profile_)->RemoveObserver(this);
169 } else {
170 HideWelcomeNotification();
174 void ExtensionWelcomeNotification::OnIsSyncingChanged() {
175 DCHECK(delayed_notification_);
176 syncable_prefs::PrefServiceSyncable* const pref_service_syncable =
177 PrefServiceSyncableFromProfile(profile_);
178 if (pref_service_syncable->IsSyncing()) {
179 pref_service_syncable->RemoveObserver(this);
180 scoped_ptr<Notification> previous_notification(
181 delayed_notification_.release());
182 ShowWelcomeNotificationIfNecessary(*(previous_notification.get()));
186 void ExtensionWelcomeNotification::ShowWelcomeNotificationIfNecessary(
187 const Notification& notification) {
188 if ((notification.notifier_id() == notifier_id_) && !delayed_notification_) {
189 syncable_prefs::PrefServiceSyncable* const pref_service_syncable =
190 PrefServiceSyncableFromProfile(profile_);
191 if (pref_service_syncable->IsSyncing()) {
192 PrefService* const pref_service = profile_->GetPrefs();
193 if (!UserHasDismissedWelcomeNotification()) {
194 const PopUpRequest pop_up_request =
195 pref_service->GetBoolean(
196 prefs::kWelcomeNotificationPreviouslyPoppedUp)
197 ? POP_UP_HIDDEN
198 : POP_UP_SHOWN;
199 if (pop_up_request == POP_UP_SHOWN) {
200 pref_service->SetBoolean(
201 prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
204 if (IsWelcomeNotificationExpired()) {
205 ExpireWelcomeNotification();
206 } else {
207 ShowWelcomeNotification(
208 notification.display_source(), pop_up_request);
211 } else {
212 delayed_notification_.reset(new Notification(notification));
213 pref_service_syncable->AddObserver(this);
218 // static
219 void ExtensionWelcomeNotification::RegisterProfilePrefs(
220 user_prefs::PrefRegistrySyncable* prefs) {
221 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissed,
222 false,
223 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
224 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissedLocal, false);
225 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp,
226 false);
227 prefs->RegisterInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp, 0);
230 message_center::MessageCenter*
231 ExtensionWelcomeNotification::GetMessageCenter() const {
232 return delegate_->GetMessageCenter();
235 void ExtensionWelcomeNotification::ShowWelcomeNotification(
236 const base::string16& display_source,
237 const PopUpRequest pop_up_request) {
238 message_center::ButtonInfo learn_more(
239 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
240 learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
241 IDR_NOTIFICATION_WELCOME_LEARN_MORE);
242 message_center::ButtonInfo disable(
243 l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
244 disable.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
245 IDR_NOTIFIER_BLOCK_BUTTON);
247 message_center::RichNotificationData rich_notification_data;
248 rich_notification_data.priority = 2;
249 rich_notification_data.buttons.push_back(learn_more);
250 rich_notification_data.buttons.push_back(disable);
252 if (welcome_notification_id_.empty())
253 welcome_notification_id_ = base::GenerateGUID();
255 if (!welcome_notification_id_.empty()) {
256 scoped_ptr<message_center::Notification> message_center_notification(
257 new message_center::Notification(
258 message_center::NOTIFICATION_TYPE_BASE_FORMAT,
259 welcome_notification_id_,
260 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
261 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
262 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
263 IDR_NOTIFICATION_WELCOME_ICON),
264 display_source, GURL(), notifier_id_, rich_notification_data,
265 new NotificationCallbacks(profile_, notifier_id_,
266 welcome_notification_id_,
267 delegate_.get())));
269 if (pop_up_request == POP_UP_HIDDEN)
270 message_center_notification->set_shown_as_popup(true);
272 GetMessageCenter()->AddNotification(message_center_notification.Pass());
273 StartExpirationTimer();
277 void ExtensionWelcomeNotification::HideWelcomeNotification() {
278 if (!welcome_notification_id_.empty() &&
279 GetMessageCenter()->FindVisibleNotificationById(
280 welcome_notification_id_) != NULL) {
281 GetMessageCenter()->RemoveNotification(welcome_notification_id_, false);
282 StopExpirationTimer();
286 bool ExtensionWelcomeNotification::UserHasDismissedWelcomeNotification() const {
287 // This was previously a syncable preference; now it's per-machine.
288 // Only the local pref will be written moving forward, but check for both so
289 // users won't be double-toasted.
290 bool shown_synced = profile_->GetPrefs()->GetBoolean(
291 prefs::kWelcomeNotificationDismissed);
292 bool shown_local = profile_->GetPrefs()->GetBoolean(
293 prefs::kWelcomeNotificationDismissedLocal);
294 return (shown_synced || shown_local);
297 void ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged() {
298 if (UserHasDismissedWelcomeNotification()) {
299 HideWelcomeNotification();
303 void ExtensionWelcomeNotification::StartExpirationTimer() {
304 if (!expiration_timer_ && !IsWelcomeNotificationExpired()) {
305 base::Time expiration_timestamp = GetExpirationTimestamp();
306 if (expiration_timestamp.is_null()) {
307 SetExpirationTimestampFromNow();
308 expiration_timestamp = GetExpirationTimestamp();
309 DCHECK(!expiration_timestamp.is_null());
311 expiration_timer_.reset(
312 new base::OneShotTimer<ExtensionWelcomeNotification>());
313 expiration_timer_->Start(
314 FROM_HERE,
315 expiration_timestamp - delegate_->GetCurrentTime(),
316 this,
317 &ExtensionWelcomeNotification::ExpireWelcomeNotification);
321 void ExtensionWelcomeNotification::StopExpirationTimer() {
322 if (expiration_timer_) {
323 expiration_timer_->Stop();
324 expiration_timer_.reset();
328 void ExtensionWelcomeNotification::ExpireWelcomeNotification() {
329 DCHECK(IsWelcomeNotificationExpired());
330 profile_->GetPrefs()->SetBoolean(
331 prefs::kWelcomeNotificationDismissedLocal, true);
332 HideWelcomeNotification();
335 base::Time ExtensionWelcomeNotification::GetExpirationTimestamp() const {
336 PrefService* const pref_service = profile_->GetPrefs();
337 const int64 expiration_timestamp =
338 pref_service->GetInt64(prefs::kWelcomeNotificationExpirationTimestamp);
339 return (expiration_timestamp == 0)
340 ? base::Time()
341 : base::Time::FromInternalValue(expiration_timestamp);
344 void ExtensionWelcomeNotification::SetExpirationTimestampFromNow() {
345 PrefService* const pref_service = profile_->GetPrefs();
346 pref_service->SetInt64(
347 prefs::kWelcomeNotificationExpirationTimestamp,
348 (delegate_->GetCurrentTime() +
349 base::TimeDelta::FromDays(kRequestedShowTimeDays)).ToInternalValue());
352 bool ExtensionWelcomeNotification::IsWelcomeNotificationExpired() const {
353 const base::Time expiration_timestamp = GetExpirationTimestamp();
354 return !expiration_timestamp.is_null() &&
355 (expiration_timestamp <= delegate_->GetCurrentTime());