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