Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: chrome/browser/notifications/extension_welcome_notification.cc

Issue 580093003: Factor Google Now welcome notifications out of DesktopNotificationService. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/notifications/extension_welcome_notification.h"
6
7 #include "base/guid.h"
8 #include "base/lazy_instance.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/notifications/notification.h"
14 #include "chrome/browser/prefs/pref_service_syncable.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser_navigator.h"
17 #include "chrome/common/pref_names.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "components/pref_registry/pref_registry_syncable.h"
21 #include "grit/theme_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/base/resource/resource_bundle.h"
24 #include "ui/message_center/message_center.h"
25 #include "ui/message_center/notification.h"
26 #include "ui/message_center/notification_delegate.h"
27 #include "ui/message_center/notification_types.h"
28
29 const int ExtensionWelcomeNotification::kRequestedShowTimeDays = 14;
30
31 namespace {
32
33 class NotificationCallbacks
34 : public message_center::NotificationDelegate {
35 public:
36 NotificationCallbacks(
37 Profile* profile,
38 const message_center::NotifierId notifier_id,
39 const std::string& welcome_notification_id,
40 ExtensionWelcomeNotification::Delegate* delegate)
41 : profile_(profile),
42 notifier_id_(notifier_id.type, notifier_id.id),
43 welcome_notification_id_(welcome_notification_id),
44 delegate_(delegate) {
45 }
46
47 // Overridden from NotificationDelegate:
48 virtual void Display() OVERRIDE {}
49 virtual void Error() OVERRIDE {}
50
51 virtual void Close(bool by_user) OVERRIDE {
52 if (by_user) {
53 // Setting the preference here may cause the notification erasing
54 // to reenter. Posting a task avoids this issue.
55 delegate_->PostTask(
56 FROM_HERE,
57 base::Bind(&NotificationCallbacks::MarkAsDismissed, this));
58 }
59 }
60
61 virtual void Click() OVERRIDE {}
62 virtual void ButtonClick(int index) OVERRIDE {
63 if (index == 0) {
64 OpenNotificationLearnMoreTab();
65 } else if (index == 1) {
66 DisableNotificationProvider();
67 Close(true);
68 } else {
69 NOTREACHED();
70 }
71 }
72
73 private:
74 void MarkAsDismissed() {
75 profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissedLocal,
76 true);
77 }
78
79 void OpenNotificationLearnMoreTab() {
80 chrome::NavigateParams params(
81 profile_,
82 GURL(chrome::kNotificationWelcomeLearnMoreURL),
83 content::PAGE_TRANSITION_LINK);
84 params.disposition = NEW_FOREGROUND_TAB;
85 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
86 chrome::Navigate(&params);
87 }
88
89 void DisableNotificationProvider() {
90 message_center::Notifier notifier(notifier_id_, base::string16(), true);
91 message_center::MessageCenter* message_center =
92 delegate_->GetMessageCenter();
93 message_center->DisableNotificationsByNotifier(notifier_id_);
94 message_center->RemoveNotification(welcome_notification_id_, false);
95 message_center->GetNotifierSettingsProvider()->SetNotifierEnabled(
96 notifier, false);
97 }
98
99 virtual ~NotificationCallbacks() {}
100
101 Profile* const profile_;
102
103 const message_center::NotifierId notifier_id_;
104
105 std::string welcome_notification_id_;
106
107 // Weak ref owned by ExtensionWelcomeNotification.
108 ExtensionWelcomeNotification::Delegate* const delegate_;
109
110 DISALLOW_COPY_AND_ASSIGN(NotificationCallbacks);
111 };
112
113 class DefaultDelegate : public ExtensionWelcomeNotification::Delegate {
114 public:
115 DefaultDelegate() {}
116
117 virtual message_center::MessageCenter* GetMessageCenter() OVERRIDE {
118 return g_browser_process->message_center();
119 }
120
121 virtual base::Time GetCurrentTime() OVERRIDE {
122 return base::Time::Now();
123 }
124
125 virtual void PostTask(
126 const tracked_objects::Location& from_here,
127 const base::Closure& task) OVERRIDE {
128 base::MessageLoop::current()->PostTask(from_here, task);
129 }
130
131 private:
132 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
133 };
134
135 } // namespace
136
137 ExtensionWelcomeNotification::ExtensionWelcomeNotification(
138 const std::string& extension_id,
139 Profile* const profile,
140 ExtensionWelcomeNotification::Delegate* const delegate)
141 : notifier_id_(message_center::NotifierId::APPLICATION, extension_id),
142 profile_(profile),
143 delegate_(delegate) {
144 welcome_notification_dismissed_pref_.Init(
145 prefs::kWelcomeNotificationDismissed,
146 profile_->GetPrefs(),
147 base::Bind(
148 &ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged,
149 base::Unretained(this)));
150 welcome_notification_dismissed_local_pref_.Init(
151 prefs::kWelcomeNotificationDismissedLocal,
152 profile_->GetPrefs());
153 }
154
155 // static
156 scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
157 const std::string& extension_id,
158 Profile* const profile) {
159 return Create(extension_id, profile, new DefaultDelegate()).Pass();
160 }
161
162 // static
163 scoped_ptr<ExtensionWelcomeNotification> ExtensionWelcomeNotification::Create(
164 const std::string& extension_id,
165 Profile* const profile,
166 Delegate* const delegate) {
167 return scoped_ptr<ExtensionWelcomeNotification>(
168 new ExtensionWelcomeNotification(extension_id, profile, delegate)).Pass();
169 }
170
171 ExtensionWelcomeNotification::~ExtensionWelcomeNotification() {
172 if (delayed_notification_) {
173 delayed_notification_.reset();
174 PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
175 } else {
176 HideWelcomeNotification();
177 }
178 }
179
180 void ExtensionWelcomeNotification::OnIsSyncingChanged() {
181 DCHECK(delayed_notification_);
182 PrefServiceSyncable* const pref_service_syncable =
183 PrefServiceSyncable::FromProfile(profile_);
184 if (pref_service_syncable->IsSyncing()) {
185 pref_service_syncable->RemoveObserver(this);
186 scoped_ptr<Notification> previous_notification(
187 delayed_notification_.release());
188 ShowWelcomeNotificationIfNecessary(*(previous_notification.get()));
189 }
190 }
191
192 void ExtensionWelcomeNotification::ShowWelcomeNotificationIfNecessary(
193 const Notification& notification) {
194 if ((notification.notifier_id() == notifier_id_) && !delayed_notification_) {
195 PrefServiceSyncable* const pref_service_syncable =
196 PrefServiceSyncable::FromProfile(profile_);
197 if (pref_service_syncable->IsSyncing()) {
198 PrefService* const pref_service = profile_->GetPrefs();
199 if (!UserHasDismissedWelcomeNotification()) {
200 const PopUpRequest pop_up_request =
201 pref_service->GetBoolean(
202 prefs::kWelcomeNotificationPreviouslyPoppedUp)
203 ? POP_UP_HIDDEN
204 : POP_UP_SHOWN;
205 if (pop_up_request == POP_UP_SHOWN) {
206 pref_service->SetBoolean(
207 prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
208 }
209
210 if (IsWelcomeNotificationExpired()) {
211 ExpireWelcomeNotification();
212 } else {
213 ShowWelcomeNotification(
214 notification.display_source(), pop_up_request);
215 }
216 }
217 } else {
218 delayed_notification_.reset(new Notification(notification));
219 pref_service_syncable->AddObserver(this);
220 }
221 }
222 }
223
224 // static
225 void ExtensionWelcomeNotification::RegisterProfilePrefs(
226 user_prefs::PrefRegistrySyncable* prefs) {
227 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissed,
228 false,
229 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
230 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissedLocal,
231 false,
232 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
233 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp,
234 false,
235 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
236 prefs->RegisterInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp,
237 0,
238 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
239 }
240
241 message_center::MessageCenter*
242 ExtensionWelcomeNotification::GetMessageCenter() const {
243 return delegate_->GetMessageCenter();
244 }
245
246 void ExtensionWelcomeNotification::ShowWelcomeNotification(
247 const base::string16& display_source,
248 const PopUpRequest pop_up_request) {
249 message_center::ButtonInfo learn_more(
250 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
251 learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
252 IDR_NOTIFICATION_WELCOME_LEARN_MORE);
253 message_center::ButtonInfo disable(
254 l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
255 disable.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
256 IDR_NOTIFIER_BLOCK_BUTTON);
257
258 message_center::RichNotificationData rich_notification_data;
259 rich_notification_data.priority = 2;
260 rich_notification_data.buttons.push_back(learn_more);
261 rich_notification_data.buttons.push_back(disable);
262
263 if (welcome_notification_id_.empty())
264 welcome_notification_id_ = base::GenerateGUID();
265
266 if (!welcome_notification_id_.empty()) {
267 scoped_ptr<message_center::Notification> message_center_notification(
268 new message_center::Notification(
269 message_center::NOTIFICATION_TYPE_BASE_FORMAT,
270 welcome_notification_id_,
271 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
272 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
273 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
274 IDR_NOTIFICATION_WELCOME_ICON),
275 display_source,
276 notifier_id_,
277 rich_notification_data,
278 new NotificationCallbacks(
279 profile_, notifier_id_, welcome_notification_id_,
280 delegate_.get())));
281
282 if (pop_up_request == POP_UP_HIDDEN)
283 message_center_notification->set_shown_as_popup(true);
284
285 GetMessageCenter()->AddNotification(message_center_notification.Pass());
286 StartExpirationTimer();
287 }
288 }
289
290 void ExtensionWelcomeNotification::HideWelcomeNotification() {
291 if (!welcome_notification_id_.empty() &&
292 GetMessageCenter()->FindVisibleNotificationById(
293 welcome_notification_id_) != NULL) {
294 GetMessageCenter()->RemoveNotification(welcome_notification_id_, false);
295 StopExpirationTimer();
296 }
297 }
298
299 bool ExtensionWelcomeNotification::UserHasDismissedWelcomeNotification() const {
300 // This was previously a syncable preference; now it's per-machine.
301 // Only the local pref will be written moving forward, but check for both so
302 // users won't be double-toasted.
303 bool shown_synced = profile_->GetPrefs()->GetBoolean(
304 prefs::kWelcomeNotificationDismissed);
305 bool shown_local = profile_->GetPrefs()->GetBoolean(
306 prefs::kWelcomeNotificationDismissedLocal);
307 return (shown_synced || shown_local);
308 }
309
310 void ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged() {
311 if (UserHasDismissedWelcomeNotification()) {
312 HideWelcomeNotification();
313 }
314 }
315
316 void ExtensionWelcomeNotification::StartExpirationTimer() {
317 if (!expiration_timer_ && !IsWelcomeNotificationExpired()) {
318 base::Time expiration_timestamp = GetExpirationTimestamp();
319 if (expiration_timestamp.is_null()) {
320 SetExpirationTimestampFromNow();
321 expiration_timestamp = GetExpirationTimestamp();
322 DCHECK(!expiration_timestamp.is_null());
323 }
324 expiration_timer_.reset(
325 new base::OneShotTimer<ExtensionWelcomeNotification>());
326 expiration_timer_->Start(
327 FROM_HERE,
328 expiration_timestamp - delegate_->GetCurrentTime(),
329 this,
330 &ExtensionWelcomeNotification::ExpireWelcomeNotification);
331 }
332 }
333
334 void ExtensionWelcomeNotification::StopExpirationTimer() {
335 if (expiration_timer_) {
336 expiration_timer_->Stop();
337 expiration_timer_.reset();
338 }
339 }
340
341 void ExtensionWelcomeNotification::ExpireWelcomeNotification() {
342 DCHECK(IsWelcomeNotificationExpired());
343 profile_->GetPrefs()->SetBoolean(
344 prefs::kWelcomeNotificationDismissedLocal, true);
345 HideWelcomeNotification();
346 }
347
348 base::Time ExtensionWelcomeNotification::GetExpirationTimestamp() const {
349 PrefService* const pref_service = profile_->GetPrefs();
350 const int64 expiration_timestamp =
351 pref_service->GetInt64(prefs::kWelcomeNotificationExpirationTimestamp);
352 return (expiration_timestamp == 0)
353 ? base::Time()
354 : base::Time::FromInternalValue(expiration_timestamp);
355 }
356
357 void ExtensionWelcomeNotification::SetExpirationTimestampFromNow() {
358 PrefService* const pref_service = profile_->GetPrefs();
359 pref_service->SetInt64(
360 prefs::kWelcomeNotificationExpirationTimestamp,
361 (delegate_->GetCurrentTime() +
362 base::TimeDelta::FromDays(kRequestedShowTimeDays)).ToInternalValue());
363 }
364
365 bool ExtensionWelcomeNotification::IsWelcomeNotificationExpired() const {
366 const base::Time expiration_timestamp = GetExpirationTimestamp();
367 return !expiration_timestamp.is_null() &&
368 (expiration_timestamp <= delegate_->GetCurrentTime());
369 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698