1 // Copyright (c) 2012 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/ui/cocoa/keystone_infobar_delegate.h" 6 7 #import <AppKit/AppKit.h> 8 9 #include <string> 10 11 #include "base/bind.h" 12 #include "base/command_line.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/message_loop/message_loop.h" 15 #include "base/prefs/pref_service.h" 16 #include "chrome/browser/first_run/first_run.h" 17 #include "chrome/browser/infobars/infobar_service.h" 18 #import "chrome/browser/mac/keystone_glue.h" 19 #include "chrome/browser/profiles/profile.h" 20 #include "chrome/browser/ui/browser.h" 21 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" 22 #include "chrome/browser/ui/tabs/tab_strip_model.h" 23 #include "chrome/common/chrome_switches.h" 24 #include "chrome/common/pref_names.h" 25 #include "components/infobars/core/confirm_infobar_delegate.h" 26 #include "components/infobars/core/infobar.h" 27 #include "content/public/browser/web_contents.h" 28 #include "grit/chromium_strings.h" 29 #include "grit/generated_resources.h" 30 #include "grit/theme_resources.h" 31 #include "ui/base/l10n/l10n_util.h" 32 33 class SkBitmap; 34 35 namespace { 36 37 // KeystonePromotionInfoBarDelegate ------------------------------------------- 38 39 class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate { 40 public: 41 // If there's an active tab, creates a keystone promotion delegate and adds it 42 // to the InfoBarService associated with that tab. 43 static void Create(); 44 45 private: 46 explicit KeystonePromotionInfoBarDelegate(PrefService* prefs); 47 virtual ~KeystonePromotionInfoBarDelegate(); 48 49 // Sets this info bar to be able to expire. Called a predetermined amount 50 // of time after this object is created. 51 void SetCanExpire() { can_expire_ = true; } 52 53 // ConfirmInfoBarDelegate 54 virtual int GetIconID() const OVERRIDE; 55 virtual base::string16 GetMessageText() const OVERRIDE; 56 virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 57 virtual bool Accept() OVERRIDE; 58 virtual bool Cancel() OVERRIDE; 59 virtual bool ShouldExpireInternal( 60 const NavigationDetails& details) const OVERRIDE; 61 62 // The prefs to use. 63 PrefService* prefs_; // weak 64 65 // Whether the info bar should be dismissed on the next navigation. 66 bool can_expire_; 67 68 // Used to delay the expiration of the info bar. 69 base::WeakPtrFactory<KeystonePromotionInfoBarDelegate> weak_ptr_factory_; 70 71 DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate); 72 }; 73 74 // static 75 void KeystonePromotionInfoBarDelegate::Create() { 76 Browser* browser = chrome::GetLastActiveBrowser(); 77 if (!browser) 78 return; 79 content::WebContents* webContents = 80 browser->tab_strip_model()->GetActiveWebContents(); 81 if (!webContents) 82 return; 83 InfoBarService* infobar_service = 84 InfoBarService::FromWebContents(webContents); 85 infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar( 86 scoped_ptr<ConfirmInfoBarDelegate>(new KeystonePromotionInfoBarDelegate( 87 Profile::FromBrowserContext( 88 webContents->GetBrowserContext())->GetPrefs())))); 89 } 90 91 KeystonePromotionInfoBarDelegate::KeystonePromotionInfoBarDelegate( 92 PrefService* prefs) 93 : ConfirmInfoBarDelegate(), 94 prefs_(prefs), 95 can_expire_(false), 96 weak_ptr_factory_(this) { 97 const base::TimeDelta kCanExpireOnNavigationAfterDelay = 98 base::TimeDelta::FromSeconds(8); 99 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 100 base::Bind(&KeystonePromotionInfoBarDelegate::SetCanExpire, 101 weak_ptr_factory_.GetWeakPtr()), 102 kCanExpireOnNavigationAfterDelay); 103 } 104 105 KeystonePromotionInfoBarDelegate::~KeystonePromotionInfoBarDelegate() { 106 } 107 108 int KeystonePromotionInfoBarDelegate::GetIconID() const { 109 return IDR_PRODUCT_LOGO_32; 110 } 111 112 base::string16 KeystonePromotionInfoBarDelegate::GetMessageText() const { 113 return l10n_util::GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT, 114 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 115 } 116 117 base::string16 KeystonePromotionInfoBarDelegate::GetButtonLabel( 118 InfoBarButton button) const { 119 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 120 IDS_PROMOTE_INFOBAR_PROMOTE_BUTTON : IDS_PROMOTE_INFOBAR_DONT_ASK_BUTTON); 121 } 122 123 bool KeystonePromotionInfoBarDelegate::Accept() { 124 [[KeystoneGlue defaultKeystoneGlue] promoteTicket]; 125 return true; 126 } 127 128 bool KeystonePromotionInfoBarDelegate::Cancel() { 129 prefs_->SetBoolean(prefs::kShowUpdatePromotionInfoBar, false); 130 return true; 131 } 132 133 bool KeystonePromotionInfoBarDelegate::ShouldExpireInternal( 134 const NavigationDetails& details) const { 135 return can_expire_; 136 } 137 138 } // namespace 139 140 141 // KeystonePromotionInfoBar --------------------------------------------------- 142 143 @interface KeystonePromotionInfoBar : NSObject 144 - (void)checkAndShowInfoBarForProfile:(Profile*)profile; 145 - (void)updateStatus:(NSNotification*)notification; 146 - (void)removeObserver; 147 @end // @interface KeystonePromotionInfoBar 148 149 @implementation KeystonePromotionInfoBar 150 151 - (void)dealloc { 152 [self removeObserver]; 153 [super dealloc]; 154 } 155 156 - (void)checkAndShowInfoBarForProfile:(Profile*)profile { 157 // If this is the first run, the user clicked the "don't ask again" button 158 // at some point in the past, or if the "don't ask about the default 159 // browser" command-line switch is present, bail out. That command-line 160 // switch is recycled here because it's likely that the set of users that 161 // don't want to be nagged about the default browser also don't want to be 162 // nagged about the update check. (Automated testers, I'm thinking of 163 // you...) 164 CommandLine* commandLine = CommandLine::ForCurrentProcess(); 165 if (first_run::IsChromeFirstRun() || 166 !profile->GetPrefs()->GetBoolean(prefs::kShowUpdatePromotionInfoBar) || 167 commandLine->HasSwitch(switches::kNoDefaultBrowserCheck)) { 168 return; 169 } 170 171 // If there is no Keystone glue (maybe because this application isn't 172 // Keystone-enabled) or the application is on a read-only filesystem, 173 // doing anything related to auto-update is pointless. Bail out. 174 KeystoneGlue* keystoneGlue = [KeystoneGlue defaultKeystoneGlue]; 175 if (!keystoneGlue || [keystoneGlue isOnReadOnlyFilesystem]) { 176 return; 177 } 178 179 // Stay alive as long as needed. This is balanced by a release in 180 // -updateStatus:. 181 [self retain]; 182 183 AutoupdateStatus recentStatus = [keystoneGlue recentStatus]; 184 if (recentStatus == kAutoupdateNone || 185 recentStatus == kAutoupdateRegistering) { 186 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 187 [center addObserver:self 188 selector:@selector(updateStatus:) 189 name:kAutoupdateStatusNotification 190 object:nil]; 191 } else { 192 [self updateStatus:[keystoneGlue recentNotification]]; 193 } 194 } 195 196 - (void)updateStatus:(NSNotification*)notification { 197 NSDictionary* dictionary = [notification userInfo]; 198 AutoupdateStatus status = static_cast<AutoupdateStatus>( 199 [[dictionary objectForKey:kAutoupdateStatusStatus] intValue]); 200 201 if (status == kAutoupdateNone || status == kAutoupdateRegistering) { 202 return; 203 } 204 205 [self removeObserver]; 206 207 if (status != kAutoupdateRegisterFailed && 208 [[KeystoneGlue defaultKeystoneGlue] needsPromotion]) { 209 KeystonePromotionInfoBarDelegate::Create(); 210 } 211 212 [self release]; 213 } 214 215 - (void)removeObserver { 216 [[NSNotificationCenter defaultCenter] removeObserver:self]; 217 } 218 219 @end // @implementation KeystonePromotionInfoBar 220 221 // static 222 void KeystoneInfoBar::PromotionInfoBar(Profile* profile) { 223 KeystonePromotionInfoBar* promotionInfoBar = 224 [[[KeystonePromotionInfoBar alloc] init] autorelease]; 225 226 [promotionInfoBar checkAndShowInfoBarForProfile:profile]; 227 } 228