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