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 "chrome/grit/chromium_strings.h" 26#include "chrome/grit/generated_resources.h" 27#include "components/infobars/core/confirm_infobar_delegate.h" 28#include "components/infobars/core/infobar.h" 29#include "content/public/browser/web_contents.h" 30#include "grit/theme_resources.h" 31#include "ui/base/l10n/l10n_util.h" 32 33class SkBitmap; 34 35namespace { 36 37// KeystonePromotionInfoBarDelegate ------------------------------------------- 38 39class 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 75void 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 91KeystonePromotionInfoBarDelegate::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 105KeystonePromotionInfoBarDelegate::~KeystonePromotionInfoBarDelegate() { 106} 107 108int KeystonePromotionInfoBarDelegate::GetIconID() const { 109 return IDR_PRODUCT_LOGO_32; 110} 111 112base::string16 KeystonePromotionInfoBarDelegate::GetMessageText() const { 113 return l10n_util::GetStringFUTF16(IDS_PROMOTE_INFOBAR_TEXT, 114 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); 115} 116 117base::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 123bool KeystonePromotionInfoBarDelegate::Accept() { 124 [[KeystoneGlue defaultKeystoneGlue] promoteTicket]; 125 return true; 126} 127 128bool KeystonePromotionInfoBarDelegate::Cancel() { 129 prefs_->SetBoolean(prefs::kShowUpdatePromotionInfoBar, false); 130 return true; 131} 132 133bool 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 222void KeystoneInfoBar::PromotionInfoBar(Profile* profile) { 223 KeystonePromotionInfoBar* promotionInfoBar = 224 [[[KeystonePromotionInfoBar alloc] init] autorelease]; 225 226 [promotionInfoBar checkAndShowInfoBarForProfile:profile]; 227} 228