Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / notifications / extension_welcome_notification.cc
blobd974145eb92ab67a5d782091e3a75acc1ac08cc7
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.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 "grit/theme_resources.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/message_center/message_center.h"
27 #include "ui/message_center/notification.h"
28 #include "ui/message_center/notification_delegate.h"
29 #include "ui/message_center/notification_types.h"
31 const int ExtensionWelcomeNotification::kRequestedShowTimeDays = 14;
32 const char ExtensionWelcomeNotification::kChromeNowExtensionID[] =
33 "pafkbggdmjlpgkdkcbjmhmfcdpncadgh";
35 namespace {
37 class NotificationCallbacks
38 : public message_center::NotificationDelegate {
39 public:
40 NotificationCallbacks(
41 Profile* profile,
42 const message_center::NotifierId notifier_id,
43 const std::string& welcome_notification_id,
44 ExtensionWelcomeNotification::Delegate* delegate)
45 : profile_(profile),
46 notifier_id_(notifier_id.type, notifier_id.id),
47 welcome_notification_id_(welcome_notification_id),
48 delegate_(delegate) {
51 // Overridden from NotificationDelegate:
52 void Close(bool by_user) override {
53 if (by_user) {
54 // Setting the preference here may cause the notification erasing
55 // to reenter. Posting a task avoids this issue.
56 delegate_->PostTask(
57 FROM_HERE,
58 base::Bind(&NotificationCallbacks::MarkAsDismissed, this));
62 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();
73 private:
74 void MarkAsDismissed() {
75 profile_->GetPrefs()->SetBoolean(prefs::kWelcomeNotificationDismissedLocal,
76 true);
79 void OpenNotificationLearnMoreTab() {
80 chrome::NavigateParams params(
81 profile_,
82 GURL(chrome::kNotificationWelcomeLearnMoreURL),
83 ui::PAGE_TRANSITION_LINK);
84 params.disposition = NEW_FOREGROUND_TAB;
85 params.window_action = chrome::NavigateParams::SHOW_WINDOW;
86 chrome::Navigate(&params);
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);
99 ~NotificationCallbacks() override {}
101 Profile* const profile_;
103 const message_center::NotifierId notifier_id_;
105 std::string welcome_notification_id_;
107 // Weak ref owned by ExtensionWelcomeNotification.
108 ExtensionWelcomeNotification::Delegate* const delegate_;
110 DISALLOW_COPY_AND_ASSIGN(NotificationCallbacks);
113 class DefaultDelegate : public ExtensionWelcomeNotification::Delegate {
114 public:
115 DefaultDelegate() {}
117 message_center::MessageCenter* GetMessageCenter() override {
118 return g_browser_process->message_center();
121 base::Time GetCurrentTime() override { return base::Time::Now(); }
123 void PostTask(const tracked_objects::Location& from_here,
124 const base::Closure& task) override {
125 base::ThreadTaskRunnerHandle::Get()->PostTask(from_here, task);
128 private:
129 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
132 } // namespace
134 ExtensionWelcomeNotification::ExtensionWelcomeNotification(
135 Profile* const profile,
136 ExtensionWelcomeNotification::Delegate* const delegate)
137 : notifier_id_(message_center::NotifierId::APPLICATION,
138 kChromeNowExtensionID),
139 profile_(profile),
140 delegate_(delegate) {
141 welcome_notification_dismissed_pref_.Init(
142 prefs::kWelcomeNotificationDismissed,
143 profile_->GetPrefs(),
144 base::Bind(
145 &ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged,
146 base::Unretained(this)));
147 welcome_notification_dismissed_local_pref_.Init(
148 prefs::kWelcomeNotificationDismissedLocal,
149 profile_->GetPrefs());
152 // static
153 ExtensionWelcomeNotification* ExtensionWelcomeNotification::Create(
154 Profile* const profile) {
155 return Create(profile, new DefaultDelegate());
158 // static
159 ExtensionWelcomeNotification* ExtensionWelcomeNotification::Create(
160 Profile* const profile, Delegate* const delegate) {
161 return new ExtensionWelcomeNotification(profile, delegate);
164 ExtensionWelcomeNotification::~ExtensionWelcomeNotification() {
165 if (delayed_notification_) {
166 delayed_notification_.reset();
167 PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this);
168 } else {
169 HideWelcomeNotification();
173 void ExtensionWelcomeNotification::OnIsSyncingChanged() {
174 DCHECK(delayed_notification_);
175 PrefServiceSyncable* const pref_service_syncable =
176 PrefServiceSyncable::FromProfile(profile_);
177 if (pref_service_syncable->IsSyncing()) {
178 pref_service_syncable->RemoveObserver(this);
179 scoped_ptr<Notification> previous_notification(
180 delayed_notification_.release());
181 ShowWelcomeNotificationIfNecessary(*(previous_notification.get()));
185 void ExtensionWelcomeNotification::ShowWelcomeNotificationIfNecessary(
186 const Notification& notification) {
187 if ((notification.notifier_id() == notifier_id_) && !delayed_notification_) {
188 PrefServiceSyncable* const pref_service_syncable =
189 PrefServiceSyncable::FromProfile(profile_);
190 if (pref_service_syncable->IsSyncing()) {
191 PrefService* const pref_service = profile_->GetPrefs();
192 if (!UserHasDismissedWelcomeNotification()) {
193 const PopUpRequest pop_up_request =
194 pref_service->GetBoolean(
195 prefs::kWelcomeNotificationPreviouslyPoppedUp)
196 ? POP_UP_HIDDEN
197 : POP_UP_SHOWN;
198 if (pop_up_request == POP_UP_SHOWN) {
199 pref_service->SetBoolean(
200 prefs::kWelcomeNotificationPreviouslyPoppedUp, true);
203 if (IsWelcomeNotificationExpired()) {
204 ExpireWelcomeNotification();
205 } else {
206 ShowWelcomeNotification(
207 notification.display_source(), pop_up_request);
210 } else {
211 delayed_notification_.reset(new Notification(notification));
212 pref_service_syncable->AddObserver(this);
217 // static
218 void ExtensionWelcomeNotification::RegisterProfilePrefs(
219 user_prefs::PrefRegistrySyncable* prefs) {
220 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissed,
221 false,
222 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
223 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationDismissedLocal, false);
224 prefs->RegisterBooleanPref(prefs::kWelcomeNotificationPreviouslyPoppedUp,
225 false);
226 prefs->RegisterInt64Pref(prefs::kWelcomeNotificationExpirationTimestamp, 0);
229 message_center::MessageCenter*
230 ExtensionWelcomeNotification::GetMessageCenter() const {
231 return delegate_->GetMessageCenter();
234 void ExtensionWelcomeNotification::ShowWelcomeNotification(
235 const base::string16& display_source,
236 const PopUpRequest pop_up_request) {
237 message_center::ButtonInfo learn_more(
238 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE));
239 learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
240 IDR_NOTIFICATION_WELCOME_LEARN_MORE);
241 message_center::ButtonInfo disable(
242 l10n_util::GetStringUTF16(IDS_NOTIFIER_WELCOME_BUTTON));
243 disable.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
244 IDR_NOTIFIER_BLOCK_BUTTON);
246 message_center::RichNotificationData rich_notification_data;
247 rich_notification_data.priority = 2;
248 rich_notification_data.buttons.push_back(learn_more);
249 rich_notification_data.buttons.push_back(disable);
251 if (welcome_notification_id_.empty())
252 welcome_notification_id_ = base::GenerateGUID();
254 if (!welcome_notification_id_.empty()) {
255 scoped_ptr<message_center::Notification> message_center_notification(
256 new message_center::Notification(
257 message_center::NOTIFICATION_TYPE_BASE_FORMAT,
258 welcome_notification_id_,
259 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE),
260 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY),
261 ui::ResourceBundle::GetSharedInstance().GetImageNamed(
262 IDR_NOTIFICATION_WELCOME_ICON),
263 display_source, GURL(), notifier_id_, rich_notification_data,
264 new NotificationCallbacks(profile_, notifier_id_,
265 welcome_notification_id_,
266 delegate_.get())));
268 if (pop_up_request == POP_UP_HIDDEN)
269 message_center_notification->set_shown_as_popup(true);
271 GetMessageCenter()->AddNotification(message_center_notification.Pass());
272 StartExpirationTimer();
276 void ExtensionWelcomeNotification::HideWelcomeNotification() {
277 if (!welcome_notification_id_.empty() &&
278 GetMessageCenter()->FindVisibleNotificationById(
279 welcome_notification_id_) != NULL) {
280 GetMessageCenter()->RemoveNotification(welcome_notification_id_, false);
281 StopExpirationTimer();
285 bool ExtensionWelcomeNotification::UserHasDismissedWelcomeNotification() const {
286 // This was previously a syncable preference; now it's per-machine.
287 // Only the local pref will be written moving forward, but check for both so
288 // users won't be double-toasted.
289 bool shown_synced = profile_->GetPrefs()->GetBoolean(
290 prefs::kWelcomeNotificationDismissed);
291 bool shown_local = profile_->GetPrefs()->GetBoolean(
292 prefs::kWelcomeNotificationDismissedLocal);
293 return (shown_synced || shown_local);
296 void ExtensionWelcomeNotification::OnWelcomeNotificationDismissedChanged() {
297 if (UserHasDismissedWelcomeNotification()) {
298 HideWelcomeNotification();
302 void ExtensionWelcomeNotification::StartExpirationTimer() {
303 if (!expiration_timer_ && !IsWelcomeNotificationExpired()) {
304 base::Time expiration_timestamp = GetExpirationTimestamp();
305 if (expiration_timestamp.is_null()) {
306 SetExpirationTimestampFromNow();
307 expiration_timestamp = GetExpirationTimestamp();
308 DCHECK(!expiration_timestamp.is_null());
310 expiration_timer_.reset(
311 new base::OneShotTimer<ExtensionWelcomeNotification>());
312 expiration_timer_->Start(
313 FROM_HERE,
314 expiration_timestamp - delegate_->GetCurrentTime(),
315 this,
316 &ExtensionWelcomeNotification::ExpireWelcomeNotification);
320 void ExtensionWelcomeNotification::StopExpirationTimer() {
321 if (expiration_timer_) {
322 expiration_timer_->Stop();
323 expiration_timer_.reset();
327 void ExtensionWelcomeNotification::ExpireWelcomeNotification() {
328 DCHECK(IsWelcomeNotificationExpired());
329 profile_->GetPrefs()->SetBoolean(
330 prefs::kWelcomeNotificationDismissedLocal, true);
331 HideWelcomeNotification();
334 base::Time ExtensionWelcomeNotification::GetExpirationTimestamp() const {
335 PrefService* const pref_service = profile_->GetPrefs();
336 const int64 expiration_timestamp =
337 pref_service->GetInt64(prefs::kWelcomeNotificationExpirationTimestamp);
338 return (expiration_timestamp == 0)
339 ? base::Time()
340 : base::Time::FromInternalValue(expiration_timestamp);
343 void ExtensionWelcomeNotification::SetExpirationTimestampFromNow() {
344 PrefService* const pref_service = profile_->GetPrefs();
345 pref_service->SetInt64(
346 prefs::kWelcomeNotificationExpirationTimestamp,
347 (delegate_->GetCurrentTime() +
348 base::TimeDelta::FromDays(kRequestedShowTimeDays)).ToInternalValue());
351 bool ExtensionWelcomeNotification::IsWelcomeNotificationExpired() const {
352 const base::Time expiration_timestamp = GetExpirationTimestamp();
353 return !expiration_timestamp.is_null() &&
354 (expiration_timestamp <= delegate_->GetCurrentTime());