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