1 // Copyright 2013 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/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/notifications/notification.h" 13 #include "chrome/browser/prefs/pref_service_syncable.h" 14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/ui/browser_navigator.h" 16 #include "chrome/common/pref_names.h" 17 #include "chrome/common/url_constants.h" 18 #include "components/user_prefs/pref_registry_syncable.h" 19 #include "grit/generated_resources.h" 20 #include "grit/theme_resources.h" 21 #include "ui/base/l10n/l10n_util.h" 22 #include "ui/base/resource/resource_bundle.h" 23 #include "ui/message_center/message_center.h" 24 #include "ui/message_center/notification.h" 25 #include "ui/message_center/notification_delegate.h" 26 #include "ui/message_center/notification_types.h" 27 28 const char kChromeNowExtensionID[] = "pafkbggdmjlpgkdkcbjmhmfcdpncadgh"; 29 30 class WelcomeNotificationDelegate 31 : public message_center::NotificationDelegate { 32 public: 33 WelcomeNotificationDelegate(const std::string& id, Profile* profile) 34 : profile_(profile) {} 35 36 // Overridden from NotificationDelegate: 37 virtual void Display() OVERRIDE {} 38 virtual void Error() OVERRIDE {} 39 40 virtual void Close(bool by_user) OVERRIDE { 41 if (by_user) { 42 // Setting the preference here may cause the notification erasing 43 // to reenter. Posting a task avoids this issue. 44 base::MessageLoop::current()->PostTask( 45 FROM_HERE, 46 base::Bind(&WelcomeNotificationDelegate::MarkAsDismissed, this)); 47 } 48 } 49 50 virtual void Click() OVERRIDE {} 51 virtual void ButtonClick(int index) OVERRIDE { 52 DCHECK(index == 0); 53 OpenNotificationLearnMoreTab(); 54 } 55 56 private: 57 void MarkAsDismissed() { 58 profile_->GetPrefs()-> 59 SetBoolean(prefs::kWelcomeNotificationDismissed, true); 60 } 61 62 void OpenNotificationLearnMoreTab() { 63 chrome::NavigateParams params( 64 profile_, 65 GURL(chrome::kNotificationWelcomeLearnMoreURL), 66 content::PAGE_TRANSITION_LINK); 67 params.disposition = NEW_FOREGROUND_TAB; 68 params.window_action = chrome::NavigateParams::SHOW_WINDOW; 69 chrome::Navigate(¶ms); 70 } 71 72 virtual ~WelcomeNotificationDelegate() {} 73 74 Profile* const profile_; 75 76 DISALLOW_COPY_AND_ASSIGN(WelcomeNotificationDelegate); 77 }; 78 79 WelcomeNotification::WelcomeNotification( 80 Profile* profile, 81 message_center::MessageCenter* message_center) 82 : profile_(profile), 83 message_center_(message_center) { 84 welcome_notification_dismissed_pref_.Init( 85 prefs::kWelcomeNotificationDismissed, 86 profile_->GetPrefs(), 87 base::Bind( 88 &WelcomeNotification::OnWelcomeNotificationDismissedChanged, 89 base::Unretained(this))); 90 } 91 92 WelcomeNotification::~WelcomeNotification() { 93 if (delayed_notification_) { 94 delayed_notification_.reset(); 95 PrefServiceSyncable::FromProfile(profile_)->RemoveObserver(this); 96 } 97 } 98 99 void WelcomeNotification::OnIsSyncingChanged() { 100 DCHECK(delayed_notification_); 101 PrefServiceSyncable* pref_service_syncable = 102 PrefServiceSyncable::FromProfile(profile_); 103 if (pref_service_syncable->IsSyncing()) { 104 pref_service_syncable->RemoveObserver(this); 105 scoped_ptr<Notification> previous_notification( 106 delayed_notification_.release()); 107 ShowWelcomeNotificationIfNecessary(*(previous_notification.get())); 108 } 109 } 110 111 void WelcomeNotification::ShowWelcomeNotificationIfNecessary( 112 const Notification& notification) { 113 message_center::NotifierId notifier_id = notification.notifier_id(); 114 if ((notifier_id.id == kChromeNowExtensionID) && !delayed_notification_) { 115 PrefServiceSyncable* pref_service_syncable = 116 PrefServiceSyncable::FromProfile(profile_); 117 if (pref_service_syncable->IsSyncing()) { 118 PrefService* pref_service = profile_->GetPrefs(); 119 if (!pref_service->GetBoolean(prefs::kWelcomeNotificationDismissed)) { 120 PopUpRequest pop_up_request = 121 pref_service->GetBoolean( 122 prefs::kWelcomeNotificationPreviouslyPoppedUp) 123 ? POP_UP_HIDDEN 124 : POP_UP_SHOWN; 125 if (pop_up_request == POP_UP_SHOWN) { 126 pref_service->SetBoolean( 127 prefs::kWelcomeNotificationPreviouslyPoppedUp, true); 128 } 129 130 ShowWelcomeNotification(notifier_id, 131 notification.display_source(), 132 pop_up_request); 133 } 134 } else { 135 delayed_notification_.reset(new Notification(notification)); 136 pref_service_syncable->AddObserver(this); 137 } 138 } 139 } 140 141 // Static 142 void WelcomeNotification::RegisterProfilePrefs( 143 user_prefs::PrefRegistrySyncable* prefs) { 144 prefs->RegisterBooleanPref( 145 prefs::kWelcomeNotificationDismissed, 146 false, 147 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 148 prefs->RegisterBooleanPref( 149 prefs::kWelcomeNotificationPreviouslyPoppedUp, 150 false, 151 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 152 } 153 154 void WelcomeNotification::ShowWelcomeNotification( 155 const message_center::NotifierId notifier_id, 156 const base::string16& display_source, 157 PopUpRequest pop_up_request) { 158 message_center::ButtonInfo learn_more( 159 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BUTTON_LEARN_MORE)); 160 learn_more.icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed( 161 IDR_NOTIFICATION_WELCOME_LEARN_MORE); 162 163 message_center::RichNotificationData rich_notification_data; 164 rich_notification_data.priority = 2; 165 rich_notification_data.buttons.push_back(learn_more); 166 167 if (welcome_notification_id_.empty()) 168 welcome_notification_id_ = base::GenerateGUID(); 169 170 if (!welcome_notification_id_.empty()) { 171 scoped_ptr<message_center::Notification> message_center_notification( 172 new message_center::Notification( 173 message_center::NOTIFICATION_TYPE_BASE_FORMAT, 174 welcome_notification_id_, 175 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_TITLE), 176 l10n_util::GetStringUTF16(IDS_NOTIFICATION_WELCOME_BODY), 177 ui::ResourceBundle::GetSharedInstance().GetImageNamed( 178 IDR_NOTIFICATION_WELCOME_ICON), 179 display_source, 180 notifier_id, 181 rich_notification_data, 182 new WelcomeNotificationDelegate( 183 welcome_notification_id_, profile_))); 184 185 if (pop_up_request == POP_UP_HIDDEN) 186 message_center_notification->set_shown_as_popup(true); 187 188 message_center_->AddNotification(message_center_notification.Pass()); 189 } 190 } 191 192 void WelcomeNotification::HideWelcomeNotification() { 193 if (!welcome_notification_id_.empty() && 194 message_center_->HasNotification(welcome_notification_id_)) { 195 message_center_->RemoveNotification(welcome_notification_id_, false); 196 } 197 } 198 199 void WelcomeNotification::OnWelcomeNotificationDismissedChanged() { 200 const bool welcome_notification_dismissed = 201 profile_->GetPrefs()->GetBoolean(prefs::kWelcomeNotificationDismissed); 202 if (welcome_notification_dismissed) 203 HideWelcomeNotification(); 204 } 205